@openclaw/slack 2026.10.10 → 2026.11.5-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/.setup/{account-inspect-Bc7TVU8F.mjs → account-inspect-DgQgj0wk.mjs} +11 -8
- package/dist/.setup/{accounts-CEgdyqoW.mjs → accounts-EaPP0fFY.mjs} +10 -1
- package/dist/.setup/{action-runtime-DPoxYao5.mjs → action-runtime-CK9QZgQl.mjs} +38 -45
- package/dist/.setup/action-runtime.runtime-CpZktret.mjs +1 -0
- package/dist/.setup/{actions-PF2cP6to.mjs → actions-s3CcFO45.mjs} +89 -76
- package/dist/.setup/{approval-handler.runtime-BtRklemy.mjs → approval-handler.runtime-Ch7BecYK.mjs} +26 -30
- package/dist/.setup/{approval-message-updates-CpwbsEj6.mjs → approval-message-updates-CqcRoa28.mjs} +1 -1
- package/dist/.setup/{channel-B6bRmYmX.mjs → channel-CAvo_WNZ.mjs} +566 -338
- package/dist/.setup/{channel-type-Dh4vwh1Y.mjs → channel-type-9Lw6yLf2.mjs} +4 -8
- package/dist/.setup/{channel.setup-BBzT6uKA.mjs → channel.setup-BlgXNuCJ.mjs} +13 -13
- package/dist/.setup/{config-schema-Cz3uId-c.mjs → config-schema-Bx1tCZB0.mjs} +3 -7
- package/dist/.setup/cursor-pages-jVn3Vkfi.mjs +309 -0
- package/dist/.setup/{directory-config-BEPra1E2.mjs → directory-config-CGvKYg9F.mjs} +3 -3
- package/dist/.setup/{directory-live-BkUwPrS0.mjs → directory-live-DNdw97LA.mjs} +4 -4
- package/dist/.setup/{doctor-contract-HK8aedwU.mjs → doctor-contract-BB2KJ9Ni.mjs} +37 -45
- package/dist/.setup/{message-tool-api-DeiQJoRV.mjs → message-tool-api-B38BpEaE.mjs} +4 -3
- package/dist/.setup/{monitor-DsZUQtTM.mjs → monitor-BD86SotB.mjs} +3397 -3672
- package/dist/.setup/{outbound-adapter-C0R5jz6S.mjs → outbound-adapter-BH6iPWBj.mjs} +30 -36
- package/dist/.setup/paths-CQZI_5WY.mjs +7 -0
- package/dist/.setup/{pipeline.runtime-CIFVL0kf.mjs → pipeline.runtime-C4ELxaRU.mjs} +415 -534
- package/dist/.setup/{policy-Bp1FvE6m.mjs → policy-C6_DdlSf.mjs} +1 -2
- package/dist/.setup/{session-status-CHkEn3HM.mjs → probe-B_Ax1vS1.mjs} +985 -622
- package/dist/.setup/question-delivery-D3qAIwuv.mjs +38 -0
- package/dist/.setup/{relay-source-DFBDTA5Z.mjs → relay-source-a8jodKuO.mjs} +11 -4
- package/dist/.setup/{replies-7DRN46EL.mjs → replies-Bq7n0gfM.mjs} +34 -19
- package/dist/.setup/{reply-blocks-DOjiDr44.mjs → reply-blocks-DyYYRrP_.mjs} +200 -205
- package/dist/.setup/{resolve-channels-BNQ1KZXh.mjs → resolve-channels-CF2JME9q.mjs} +4 -7
- package/dist/.setup/{resolve-users-C4dC8Z7D.mjs → resolve-users-DDcCAjH1.mjs} +8 -16
- package/dist/.setup/{scopes-C1aeCBa6.mjs → scopes-CzHC_dwV.mjs} +2 -1
- package/dist/.setup/{secret-contract-D0UY2JWF.mjs → secret-contract-CqVqR7MP.mjs} +4 -2
- package/dist/.setup/{secret-contract-api-BhzGpUb0.mjs → secret-contract-api-DaCXZ47j.mjs} +1 -1
- package/dist/.setup/{send-C5uXkmZV.mjs → send-WJZ73VSf.mjs} +297 -333
- package/dist/.setup/{send-results-D-o6PgtS.mjs → send-results-Bm6V1ekL.mjs} +3 -4
- package/dist/.setup/setup-plugin-api-DJXIB8CF.mjs +2 -0
- package/dist/.setup/{setup-surface-CtM1pm-9.mjs → setup-surface-uIqP2B0Y.mjs} +5 -6
- package/dist/.setup/{slash-dispatch.runtime-Bnn9a5qB.mjs → slash-dispatch.runtime-Cwuwv7FL.mjs} +2 -2
- package/dist/.setup/{target-parsing-0pRZtahO.mjs → target-parsing-DwYAP3ts.mjs} +1 -2
- package/dist/.setup/{targets-BqXz7CpG.mjs → targets-eeOxA_b_.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 -1
- package/dist/channel-plugin-api.js +1 -1
- package/dist/directory-contract-api.js +1 -1
- package/dist/doctor-contract-api.js +1 -1
- package/dist/index.js +0 -6
- package/dist/message-tool-api.js +1 -1
- package/dist/runtime-api.js +10 -12
- package/dist/secret-contract-api.js +1 -1
- package/dist/setup-entry.js +2 -2
- package/dist/setup-plugin-api.js +1 -1
- 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/body-parser/README.md +13 -17
- package/node_modules/@slack/bolt/node_modules/body-parser/lib/read.js +57 -74
- package/node_modules/@slack/bolt/node_modules/body-parser/lib/types/json.js +11 -11
- package/node_modules/@slack/bolt/node_modules/body-parser/lib/types/urlencoded.js +5 -5
- package/node_modules/@slack/bolt/node_modules/body-parser/lib/utils.js +15 -0
- package/node_modules/@slack/bolt/node_modules/body-parser/package.json +12 -7
- 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-DWKWaKgC.mjs +0 -1
- package/dist/.setup/http-GpAVKwSX.mjs +0 -2
- package/dist/.setup/plugin-routes-lXsy_bNV.mjs +0 -21
- package/dist/.setup/probe-C5VWf3sz.mjs +0 -686
- package/dist/.setup/registry-1G0f1zuZ.mjs +0 -34
- package/dist/.setup/setup-plugin-api-D7DoueEh.mjs +0 -2
- package/dist/.setup/shared-CohTHxM1.mjs +0 -255
- package/dist/.source-module-urls/562d694877afe9d9dcbb3b32a8883c16974738f2aa892c48d45572cdc9a62529.json +0 -1
- package/dist/http-routes-api.js +0 -1
- 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-nwUcYXjP.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-C5VWf3sz.mjs";
|
|
6
|
-
import { a as prepareSlackReply, l as resolveSlackReplyRenderPlan, s as resolveSlackReplyBlocks } from "./reply-blocks-DOjiDr44.mjs";
|
|
2
|
+
import { d as resolveSlackMarkdownOptions, o as resolveDefaultSlackAccountId, p as resolveSlackReplyToMode } from "./accounts-EaPP0fFY.mjs";
|
|
3
|
+
import { n as formatSlackTarget } from "./target-parsing-DwYAP3ts.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-B_Ax1vS1.mjs";
|
|
7
5
|
import { n as resolveSlackReplyThreadTs } from "./thread-ts-47Au2-Yn.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-DyYYRrP_.mjs";
|
|
7
|
+
import { d as getOrCreateWeakOwnerMap, m as writeLruMapEntry, p as readLruMapEntry } from "./cursor-pages-jVn3Vkfi.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-s3CcFO45.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-WJZ73VSf.mjs";
|
|
10
|
+
import { n as resolveSlackChannelConfig } from "./policy-C6_DdlSf.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-BD86SotB.mjs";
|
|
12
|
+
import { a as emitSlackMessageSentHooks, i as sanitizeSlackMonitorReplyPayload, n as deliverReplies, t as createSlackReplyDeliveryPlan } from "./replies-Bq7n0gfM.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";
|
|
@@ -96,13 +96,6 @@ function resolveSlackNativeProgressTaskCards(entry, style) {
|
|
|
96
96
|
}
|
|
97
97
|
const SLACK_STREAM_RECIPIENT_TEAM_CACHE_MAX = 2e3;
|
|
98
98
|
const slackStreamRecipientTeamCaches = /* @__PURE__ */ new WeakMap();
|
|
99
|
-
function getSlackStreamRecipientTeamCache(client) {
|
|
100
|
-
const existing = slackStreamRecipientTeamCaches.get(client);
|
|
101
|
-
if (existing) return existing;
|
|
102
|
-
const cache = /* @__PURE__ */ new Map();
|
|
103
|
-
slackStreamRecipientTeamCaches.set(client, cache);
|
|
104
|
-
return cache;
|
|
105
|
-
}
|
|
106
99
|
function buildSlackEventDeliveryKey(params, preparedReply = prepareSlackReply(params.payload)) {
|
|
107
100
|
const reply = resolveSendableOutboundReplyParts(params.payload, { text: params.textOverride });
|
|
108
101
|
const renderPlan = preparedReply.resolvePreview(params.textOverride);
|
|
@@ -121,7 +114,7 @@ function buildSlackEventDeliveryKey(params, preparedReply = prepareSlackReply(pa
|
|
|
121
114
|
}
|
|
122
115
|
async function resolveSlackStreamRecipientTeamId(params) {
|
|
123
116
|
const cacheKey = params.fallbackTeamId && params.userId ? `${params.fallbackTeamId}:${params.userId}` : void 0;
|
|
124
|
-
const cache = cacheKey ?
|
|
117
|
+
const cache = cacheKey ? getOrCreateWeakOwnerMap(slackStreamRecipientTeamCaches, params.client) : void 0;
|
|
125
118
|
const cachedTeamId = cache && cacheKey ? readLruMapEntry(cache, cacheKey) : void 0;
|
|
126
119
|
if (cachedTeamId) return cachedTeamId;
|
|
127
120
|
if (params.userId) try {
|
|
@@ -144,8 +137,6 @@ const DEFAULT_THROTTLE_MS = 1e3;
|
|
|
144
137
|
function createSlackDraftStream(params) {
|
|
145
138
|
const maxChars = Math.min(params.maxChars ?? 8e3, SLACK_TEXT_LIMIT);
|
|
146
139
|
const throttleMs = Math.max(250, params.throttleMs ?? DEFAULT_THROTTLE_MS);
|
|
147
|
-
const send = params.send ?? sendMessageSlack;
|
|
148
|
-
const remove = params.remove ?? deleteSlackMessage;
|
|
149
140
|
let streamMessage;
|
|
150
141
|
let untrackConversationBoundary;
|
|
151
142
|
let lastSentKey = "";
|
|
@@ -159,7 +150,7 @@ function createSlackDraftStream(params) {
|
|
|
159
150
|
streamMessage = void 0;
|
|
160
151
|
lastSentKey = "";
|
|
161
152
|
};
|
|
162
|
-
const editPreview = (message, update) => (
|
|
153
|
+
const editPreview = (message, update) => (update.textIsSlackMrkdwn ? editSlackRenderedMessage : editSlackMessage)(message.channelId, message.messageId, update.text, {
|
|
163
154
|
cfg: params.cfg,
|
|
164
155
|
token: params.token,
|
|
165
156
|
accountId: params.accountId,
|
|
@@ -206,7 +197,7 @@ function createSlackDraftStream(params) {
|
|
|
206
197
|
onInterveningMessage: () => forceNewMessage("human")
|
|
207
198
|
});
|
|
208
199
|
await lifecycle.createMessage(async () => {
|
|
209
|
-
const sent = await
|
|
200
|
+
const sent = await sendMessageSlack(params.target, visibleUpdate.text, {
|
|
210
201
|
cfg: params.cfg,
|
|
211
202
|
token: params.token,
|
|
212
203
|
accountId: params.accountId,
|
|
@@ -251,7 +242,7 @@ function createSlackDraftStream(params) {
|
|
|
251
242
|
clearMessageId,
|
|
252
243
|
isValidMessageId: (value) => typeof value === "object" && value !== null,
|
|
253
244
|
deleteMessage: async (message) => {
|
|
254
|
-
if (!message.retained && !(preserveHumanReplies && message.detachedByHuman)) await
|
|
245
|
+
if (!message.retained && !(preserveHumanReplies && message.detachedByHuman)) await deleteSlackMessage(message.channelId, message.messageId, {
|
|
255
246
|
token: params.token,
|
|
256
247
|
accountId: params.accountId,
|
|
257
248
|
...params.eventScope ? { client: params.eventScope.client } : {}
|
|
@@ -299,7 +290,6 @@ function createSlackDraftStream(params) {
|
|
|
299
290
|
stopTrackingConversationBoundary();
|
|
300
291
|
return true;
|
|
301
292
|
};
|
|
302
|
-
params.log?.(`slack stream preview ready (maxChars=${maxChars}, throttleMs=${throttleMs})`);
|
|
303
293
|
return {
|
|
304
294
|
update,
|
|
305
295
|
flush: loop.flush,
|
|
@@ -371,12 +361,6 @@ const SLACK_PROGRESS_TASK_TITLE_MAX = 120;
|
|
|
371
361
|
const SLACK_PROGRESS_PLAN_FALLBACK_TITLE = "Thinking";
|
|
372
362
|
const SLACK_PROGRESS_LINE_DELTA_RE = /(?:^|\s)\+(\d+)\s+[−-](\d+)(?=\s|$)/u;
|
|
373
363
|
const SLACK_ATTENTION_TASK_PREFIX = "openclaw-attention-";
|
|
374
|
-
function buildSessionSources(links) {
|
|
375
|
-
return links.map((link) => ({
|
|
376
|
-
type: "url_source",
|
|
377
|
-
...link
|
|
378
|
-
}));
|
|
379
|
-
}
|
|
380
364
|
function field(text) {
|
|
381
365
|
return {
|
|
382
366
|
type: "mrkdwn",
|
|
@@ -435,10 +419,6 @@ function lineTaskTitle(line) {
|
|
|
435
419
|
if (fallback && fallback !== label) return compactTitle(lineDetailParts(line).length > 0 || line.status ? label : fallback);
|
|
436
420
|
return compactTitle(label);
|
|
437
421
|
}
|
|
438
|
-
function lineTaskDetails(line, maxLineChars) {
|
|
439
|
-
const detail = line.detail?.replace(SLACK_PROGRESS_LINE_DELTA_RE, "").replace(/\s+·\s*$/u, "").trim();
|
|
440
|
-
return detail && detail !== line.status?.trim() ? compactDetail(detail, maxLineChars) : void 0;
|
|
441
|
-
}
|
|
442
422
|
function lineTaskOutput(line) {
|
|
443
423
|
const match = line.detail ? SLACK_PROGRESS_LINE_DELTA_RE.exec(line.detail) : null;
|
|
444
424
|
if (match) return `+${match[1]} −${match[2]}`;
|
|
@@ -469,48 +449,39 @@ function resolveLineTaskIdentity(line, contentIdOccurrences) {
|
|
|
469
449
|
contentIdOccurrences.set(id, occurrence);
|
|
470
450
|
return `${id}_${occurrence}`;
|
|
471
451
|
}
|
|
472
|
-
function
|
|
452
|
+
function formatProgressAttentionTitle(line, finalStatus) {
|
|
453
|
+
if (line.kind === "approval") return line.status === "requested" && finalStatus === void 0 ? compactTitle(`Approval required: ${line.detail || line.label}`) : void 0;
|
|
454
|
+
if (lineTaskStatus(line) !== "error") return;
|
|
455
|
+
const title = [...new Set([
|
|
456
|
+
line.label,
|
|
457
|
+
line.detail,
|
|
458
|
+
line.status
|
|
459
|
+
].filter(Boolean))].join(" — ");
|
|
460
|
+
return compactTitle(finalStatus === "complete" ? `Recovered: ${title}` : title);
|
|
461
|
+
}
|
|
462
|
+
function buildSlackProgressStreamChunks(params) {
|
|
463
|
+
const approvals = params.lines.filter((line) => line.kind === "approval");
|
|
464
|
+
const taskLines = params.summaryRow ? [] : params.lines.filter((line) => line.kind !== "approval");
|
|
473
465
|
const tasks = (params.plan ?? []).map((entry, index) => ({
|
|
474
466
|
id: `plan_step_${index + 1}`,
|
|
475
467
|
title: compactTitle(entry.step),
|
|
476
468
|
status: entry.status === "completed" ? "complete" : entry.status
|
|
477
469
|
}));
|
|
478
470
|
const maxLineChars = resolveMaxLineChars(params.maxLineChars, DEFAULT_SLACK_PROGRESS_TASK_DETAIL_MAX_CHARS);
|
|
479
|
-
const
|
|
480
|
-
for (const line of
|
|
471
|
+
const taskContentIdOccurrences = /* @__PURE__ */ new Map();
|
|
472
|
+
for (const line of taskLines) {
|
|
481
473
|
const task = {
|
|
482
|
-
id: resolveLineTaskIdentity(line,
|
|
474
|
+
id: resolveLineTaskIdentity(line, taskContentIdOccurrences),
|
|
483
475
|
title: lineTaskTitle(line),
|
|
484
476
|
status: lineTaskStatus(line)
|
|
485
477
|
};
|
|
486
|
-
const
|
|
478
|
+
const detail = line.detail?.replace(SLACK_PROGRESS_LINE_DELTA_RE, "").replace(/\s+·\s*$/u, "").trim();
|
|
479
|
+
const details = detail && detail !== line.status?.trim() ? compactDetail(detail, maxLineChars) : void 0;
|
|
487
480
|
const output = lineTaskOutput(line);
|
|
488
481
|
if (details) task.details = details;
|
|
489
482
|
if (output) task.output = output;
|
|
490
483
|
tasks.push(task);
|
|
491
484
|
}
|
|
492
|
-
return tasks;
|
|
493
|
-
}
|
|
494
|
-
function formatProgressAttentionTitle(line, finalStatus) {
|
|
495
|
-
if (line.kind === "approval") return line.status === "requested" && finalStatus === void 0 ? compactTitle(`Approval required: ${line.detail || line.label}`) : void 0;
|
|
496
|
-
if (lineTaskStatus(line) !== "error") return;
|
|
497
|
-
const title = [...new Set([
|
|
498
|
-
line.label,
|
|
499
|
-
line.detail,
|
|
500
|
-
line.status
|
|
501
|
-
].filter(Boolean))].join(" — ");
|
|
502
|
-
return compactTitle(finalStatus === "complete" ? `Recovered: ${title}` : title);
|
|
503
|
-
}
|
|
504
|
-
function formatTaskDiffOutput(diffStat) {
|
|
505
|
-
return diffStat && (diffStat.added > 0 || diffStat.removed > 0) ? `+${diffStat.added} −${diffStat.removed}` : void 0;
|
|
506
|
-
}
|
|
507
|
-
function buildSlackProgressStreamChunks(params) {
|
|
508
|
-
const approvals = params.lines.filter((line) => line.kind === "approval");
|
|
509
|
-
const tasks = buildNativeTasks({
|
|
510
|
-
lines: params.summaryRow ? [] : params.lines.filter((line) => line.kind !== "approval"),
|
|
511
|
-
plan: params.plan,
|
|
512
|
-
maxLineChars: params.maxLineChars
|
|
513
|
-
});
|
|
514
485
|
const contentIdOccurrences = /* @__PURE__ */ new Map();
|
|
515
486
|
const attention = [];
|
|
516
487
|
for (const line of approvals) {
|
|
@@ -521,11 +492,11 @@ function buildSlackProgressStreamChunks(params) {
|
|
|
521
492
|
status: "pending"
|
|
522
493
|
});
|
|
523
494
|
}
|
|
524
|
-
const headline = params.title?.trim()
|
|
495
|
+
const headline = params.title?.trim();
|
|
525
496
|
const summaryTitle = params.finalInProgressStatus === "error" ? "Failed" : params.finalInProgressStatus === "complete" || !params.summaryRow ? "Completed" : "Working";
|
|
526
497
|
const newest = tasks.at(-1);
|
|
527
498
|
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);
|
|
528
|
-
const diffOutput =
|
|
499
|
+
const diffOutput = params.diffStat && (params.diffStat.added > 0 || params.diffStat.removed > 0) ? `+${params.diffStat.added} −${params.diffStat.removed}` : void 0;
|
|
529
500
|
if (tasks.length === 0 && (params.summaryRow || params.sessionLinks?.length || diffOutput)) tasks.push({
|
|
530
501
|
id: "openclaw_summary",
|
|
531
502
|
title: params.summaryRow ? compactTitle(title) : summaryTitle,
|
|
@@ -545,7 +516,10 @@ function buildSlackProgressStreamChunks(params) {
|
|
|
545
516
|
chunk.title = recovered ? compactTitle(`Recovered: ${task.title}`) : task.title;
|
|
546
517
|
chunk.status = recovered ? "complete" : task.status === "in_progress" ? params.finalInProgressStatus ?? task.status : task.status;
|
|
547
518
|
if (index === finalTaskIndex && diffOutput) chunk.output = [task.output, diffOutput].filter(Boolean).join(" · ");
|
|
548
|
-
if (index === finalTaskIndex && params.sessionLinks?.length) chunk.sources =
|
|
519
|
+
if (index === finalTaskIndex && params.sessionLinks?.length) chunk.sources = params.sessionLinks.map((link) => ({
|
|
520
|
+
type: "url_source",
|
|
521
|
+
...link
|
|
522
|
+
}));
|
|
549
523
|
return chunk;
|
|
550
524
|
});
|
|
551
525
|
return [{
|
|
@@ -564,13 +538,6 @@ function joinRecentProgressRows(rows) {
|
|
|
564
538
|
}
|
|
565
539
|
return rendered.toReversed().join("\n");
|
|
566
540
|
}
|
|
567
|
-
function buildActivityText(lines, maxLineChars) {
|
|
568
|
-
return joinRecentProgressRows(lines.slice(-50).map((line) => {
|
|
569
|
-
if (line.kind === "item" && !line.toolName) return `_${renderProgressCardText(compactDetail(line.text, maxLineChars), "italic")}_`;
|
|
570
|
-
const detail = compactDetail(lineDetailParts(line).join(" · "), maxLineChars);
|
|
571
|
-
return escapeSlackMrkdwn(detail ? `${line.label} — ${detail}` : line.label);
|
|
572
|
-
}));
|
|
573
|
-
}
|
|
574
541
|
function buildSlackProgressCardBlocks(params) {
|
|
575
542
|
const maxLineChars = resolveMaxLineChars(params.maxLineChars, DEFAULT_SLACK_PROGRESS_DETAIL_MAX_CHARS);
|
|
576
543
|
const selected = selectPlanChecklistSteps(params.detailed ? params.plan ?? [] : [], { maxLines: 50 });
|
|
@@ -600,7 +567,11 @@ function buildSlackProgressCardBlocks(params) {
|
|
|
600
567
|
});
|
|
601
568
|
const sections = [
|
|
602
569
|
planLines.map((line) => renderProgressCardText(line)).join("\n"),
|
|
603
|
-
|
|
570
|
+
joinRecentProgressRows(lines.filter((line) => line.kind !== "approval" && lineTaskStatus(line) !== "error").slice(-50).map((line) => {
|
|
571
|
+
if (line.kind === "item" && !line.toolName) return `_${renderProgressCardText(compactDetail(line.text, maxLineChars), "italic")}_`;
|
|
572
|
+
const detail = compactDetail(lineDetailParts(line).join(" · "), maxLineChars);
|
|
573
|
+
return escapeSlackMrkdwn(detail ? `${line.label} — ${detail}` : line.label);
|
|
574
|
+
})),
|
|
604
575
|
joinRecentProgressRows(attention)
|
|
605
576
|
];
|
|
606
577
|
const title = params.title?.trim();
|
|
@@ -680,6 +651,13 @@ function reconcileSlackNativeTaskChunks(params) {
|
|
|
680
651
|
const nextTasks = /* @__PURE__ */ new Map();
|
|
681
652
|
let planTitle = params.previous.planTitle;
|
|
682
653
|
const emitted = [];
|
|
654
|
+
if (!params.chunks?.length && planTitle && planTitle !== SLACK_PROGRESS_PLAN_FALLBACK_TITLE) {
|
|
655
|
+
planTitle = SLACK_PROGRESS_PLAN_FALLBACK_TITLE;
|
|
656
|
+
emitted.push({
|
|
657
|
+
type: "plan_update",
|
|
658
|
+
title: planTitle
|
|
659
|
+
});
|
|
660
|
+
}
|
|
683
661
|
for (const chunk of params.chunks ?? []) {
|
|
684
662
|
if (chunk.type === "plan_update") {
|
|
685
663
|
if (chunk.title !== planTitle) {
|
|
@@ -789,12 +767,6 @@ function isSlackProgressTitleText(text, snapshot, explicitTitle) {
|
|
|
789
767
|
return title.length > 0 && title.includes(candidate);
|
|
790
768
|
}
|
|
791
769
|
// extensions/slack/src/monitor/message-handler/preview-finalize.ts
|
|
792
|
-
function buildExpectedSlackEditText(params) {
|
|
793
|
-
const trimmedText = params.text.trim();
|
|
794
|
-
if (trimmedText) return normalizeSlackOutboundText(trimmedText);
|
|
795
|
-
if (params.blocks?.length) return normalizeSlackOutboundText(buildSlackBlocksFallbackText(params.blocks));
|
|
796
|
-
return " ";
|
|
797
|
-
}
|
|
798
770
|
function blocksMatch(expected, actual) {
|
|
799
771
|
if (!expected?.length) return !actual?.length;
|
|
800
772
|
if (!actual?.length) {
|
|
@@ -814,45 +786,6 @@ function blocksMatch(expected, actual) {
|
|
|
814
786
|
return false;
|
|
815
787
|
}
|
|
816
788
|
}
|
|
817
|
-
async function readSlackMessageAfterEditError(params) {
|
|
818
|
-
const query = {
|
|
819
|
-
token: params.token,
|
|
820
|
-
channel: params.channelId,
|
|
821
|
-
latest: params.messageId,
|
|
822
|
-
oldest: params.messageId,
|
|
823
|
-
inclusive: true,
|
|
824
|
-
limit: 1
|
|
825
|
-
};
|
|
826
|
-
const result = params.threadTs ? await params.client.conversations.replies({
|
|
827
|
-
...query,
|
|
828
|
-
ts: params.threadTs
|
|
829
|
-
}) : await params.client.conversations.history(query);
|
|
830
|
-
const message = params.threadTs ? result.messages?.find((entry) => entry?.ts === params.messageId) : result.messages?.[0];
|
|
831
|
-
return message?.ts && message.ts === params.messageId ? message : null;
|
|
832
|
-
}
|
|
833
|
-
async function didSlackPreviewEditApplyAfterError(params) {
|
|
834
|
-
const readback = await readSlackMessageAfterEditError(params);
|
|
835
|
-
if (!readback) return false;
|
|
836
|
-
const expectedText = buildExpectedSlackEditText({
|
|
837
|
-
text: params.text,
|
|
838
|
-
blocks: params.blocks
|
|
839
|
-
});
|
|
840
|
-
const acceptedTexts = /* @__PURE__ */ new Set([
|
|
841
|
-
expectedText,
|
|
842
|
-
normalizeSlackOutboundText(truncateSlackTextByUtf8Bytes(expectedText, SLACK_EDIT_TEXT_MAX_BYTES)),
|
|
843
|
-
normalizeSlackOutboundText(buildSlackEditTextPayload(params.text, params.blocks))
|
|
844
|
-
]);
|
|
845
|
-
if (params.blocks?.length && hasSlackNativeDataBlock(params.blocks)) {
|
|
846
|
-
const fallbackPlan = buildSlackNativeDataDeliveryPlan({
|
|
847
|
-
baseText: params.text,
|
|
848
|
-
blocks: params.blocks
|
|
849
|
-
});
|
|
850
|
-
for (const message of fallbackPlan.fallbackMessages) acceptedTexts.add(normalizeSlackOutboundText(message.text));
|
|
851
|
-
}
|
|
852
|
-
const actualText = normalizeSlackOutboundText((readback.text ?? "").trim());
|
|
853
|
-
if (params.blocks?.length) return acceptedTexts.has(actualText) && blocksMatch(params.blocks, readback.blocks);
|
|
854
|
-
return actualText === expectedText;
|
|
855
|
-
}
|
|
856
789
|
async function finalizeSlackPreviewEdit(params) {
|
|
857
790
|
try {
|
|
858
791
|
await editSlackRenderedMessage(params.channelId, params.messageId, params.text, {
|
|
@@ -863,9 +796,40 @@ async function finalizeSlackPreviewEdit(params) {
|
|
|
863
796
|
});
|
|
864
797
|
} catch (err) {
|
|
865
798
|
try {
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
799
|
+
const query = {
|
|
800
|
+
token: params.token,
|
|
801
|
+
channel: params.channelId,
|
|
802
|
+
latest: params.messageId,
|
|
803
|
+
oldest: params.messageId,
|
|
804
|
+
inclusive: true,
|
|
805
|
+
limit: 1
|
|
806
|
+
};
|
|
807
|
+
const result = params.threadTs ? await params.client.conversations.replies({
|
|
808
|
+
...query,
|
|
809
|
+
ts: params.threadTs
|
|
810
|
+
}) : await params.client.conversations.history(query);
|
|
811
|
+
const message = params.threadTs ? result.messages?.find((entry) => entry?.ts === params.messageId) : result.messages?.[0];
|
|
812
|
+
const readback = message?.ts && message.ts === params.messageId ? message : null;
|
|
813
|
+
if (readback) {
|
|
814
|
+
const trimmedText = params.text.trim();
|
|
815
|
+
const expectedText = trimmedText ? normalizeSlackOutboundText(trimmedText) : params.blocks?.length ? normalizeSlackOutboundText(buildSlackBlocksFallbackText(params.blocks)) : " ";
|
|
816
|
+
const acceptedTexts = /* @__PURE__ */ new Set([
|
|
817
|
+
expectedText,
|
|
818
|
+
normalizeSlackOutboundText(truncateSlackTextByUtf8Bytes(expectedText, SLACK_EDIT_TEXT_MAX_BYTES)),
|
|
819
|
+
normalizeSlackOutboundText(buildSlackEditTextPayload(params.text, params.blocks))
|
|
820
|
+
]);
|
|
821
|
+
if (params.blocks?.length && hasSlackNativeDataBlock(params.blocks)) {
|
|
822
|
+
const fallbackPlan = buildSlackNativeDataDeliveryPlan({
|
|
823
|
+
baseText: params.text,
|
|
824
|
+
blocks: params.blocks
|
|
825
|
+
});
|
|
826
|
+
for (const fallbackMessage of fallbackPlan.fallbackMessages) acceptedTexts.add(normalizeSlackOutboundText(fallbackMessage.text));
|
|
827
|
+
}
|
|
828
|
+
const actualText = normalizeSlackOutboundText((readback.text ?? "").trim());
|
|
829
|
+
if (params.blocks?.length ? acceptedTexts.has(actualText) && blocksMatch(params.blocks, readback.blocks) : actualText === expectedText) {
|
|
830
|
+
logVerbose(`slack: preview final edit response failed but readback matched message ${params.channelId}/${params.messageId}; suppressing duplicate fallback send`);
|
|
831
|
+
return;
|
|
832
|
+
}
|
|
869
833
|
}
|
|
870
834
|
} catch (readbackErr) {
|
|
871
835
|
logVerbose(`slack: preview final edit readback failed (${String(readbackErr)})`);
|
|
@@ -1041,7 +1005,7 @@ function createSlackNativeProgressTransport(params) {
|
|
|
1041
1005
|
const delivered = markDelivered(streamThreadTs);
|
|
1042
1006
|
return update.chunks?.length ? delivered : true;
|
|
1043
1007
|
} finally {
|
|
1044
|
-
|
|
1008
|
+
delivery.nativeProgressStreamStartPromise = null;
|
|
1045
1009
|
}
|
|
1046
1010
|
};
|
|
1047
1011
|
const append = async (update) => {
|
|
@@ -1072,7 +1036,6 @@ function createSlackProgressRuntime(runtimeParams) {
|
|
|
1072
1036
|
cfg,
|
|
1073
1037
|
token: ctx.botToken,
|
|
1074
1038
|
accountId: account.accountId,
|
|
1075
|
-
conversationChannelId: message.channel,
|
|
1076
1039
|
eventScope: prepared.eventScope,
|
|
1077
1040
|
...!hasSlackCustomIdentity && slackIdentity ? { identity: slackIdentity } : {},
|
|
1078
1041
|
...slackMessageMetadata ? { metadata: slackMessageMetadata } : {},
|
|
@@ -1082,7 +1045,6 @@ function createSlackProgressRuntime(runtimeParams) {
|
|
|
1082
1045
|
if (ts) delivery.usedReplyThreadTs ??= ts;
|
|
1083
1046
|
return ts;
|
|
1084
1047
|
},
|
|
1085
|
-
log: logVerbose,
|
|
1086
1048
|
warn: logVerbose
|
|
1087
1049
|
}) : void 0;
|
|
1088
1050
|
const isProgressMode = slackStreaming.mode === "progress";
|
|
@@ -1501,7 +1463,6 @@ function createSlackProgressRuntime(runtimeParams) {
|
|
|
1501
1463
|
return {
|
|
1502
1464
|
draftStream,
|
|
1503
1465
|
previewLifecycle,
|
|
1504
|
-
isProgressMode,
|
|
1505
1466
|
useDraftProgressCard,
|
|
1506
1467
|
useNativeProgressStreaming,
|
|
1507
1468
|
progressDraftActive,
|
|
@@ -1693,9 +1654,7 @@ async function createSlackDispatchSetup(prepared) {
|
|
|
1693
1654
|
status: "active",
|
|
1694
1655
|
eventScope: prepared.eventScope
|
|
1695
1656
|
});
|
|
1696
|
-
if (reportFailure && !restored)
|
|
1697
|
-
runtime.error?.("Slack session status could not return to active after processing. Enable verbose logging to inspect the Slack API failure.");
|
|
1698
|
-
} catch {}
|
|
1657
|
+
if (reportFailure && !restored) runtime.error?.("Slack session status could not return to active after processing. Enable verbose logging to inspect the Slack API failure.");
|
|
1699
1658
|
}
|
|
1700
1659
|
if (didAddTypingReaction && typingReaction && message.ts) {
|
|
1701
1660
|
didAddTypingReaction = false;
|
|
@@ -1759,6 +1718,10 @@ async function createSlackDispatchSetup(prepared) {
|
|
|
1759
1718
|
function createSlackStreamingDeliveryRuntime(setup) {
|
|
1760
1719
|
const { isThreadReply, messageSentHookContext, messageSentHookTarget, prepared, replyDeliveryMode, replyPlan, runtime, slackClient, slackClientOptions, slackIdentity, slackStreamFallbackTeamId } = setup;
|
|
1761
1720
|
const { account, ctx, forcedReplyThreadTs, message, slackMessageMetadata } = prepared;
|
|
1721
|
+
const markdownOptions = resolveSlackMarkdownOptions({
|
|
1722
|
+
cfg: ctx.cfg,
|
|
1723
|
+
accountId: account.accountId
|
|
1724
|
+
});
|
|
1762
1725
|
const state = {
|
|
1763
1726
|
streamSession: null,
|
|
1764
1727
|
streamBoundary: null,
|
|
@@ -1839,7 +1802,7 @@ function createSlackStreamingDeliveryRuntime(setup) {
|
|
|
1839
1802
|
if (key) deliveredKeys.add(key);
|
|
1840
1803
|
};
|
|
1841
1804
|
const markPreviewPayloadDelivered = (params) => {
|
|
1842
|
-
const preparedReply = prepareSlackReply(params.payload);
|
|
1805
|
+
const preparedReply = prepareSlackReply(params.payload, markdownOptions);
|
|
1843
1806
|
markDelivered(buildSlackEventDeliveryKey(params, preparedReply));
|
|
1844
1807
|
const nextThreadTs = replyPlan.peekThreadTs();
|
|
1845
1808
|
if (nextThreadTs !== params.threadTs) markDelivered(buildSlackEventDeliveryKey({
|
|
@@ -1880,7 +1843,7 @@ function createSlackStreamingDeliveryRuntime(setup) {
|
|
|
1880
1843
|
}
|
|
1881
1844
|
const fallbackText = fallbackError.pendingText.trim();
|
|
1882
1845
|
if (!fallbackText) return;
|
|
1883
|
-
const sent = await deliverPreparedReply(prepareSlackReply({ text: fallbackText }), session.threadTs, true);
|
|
1846
|
+
const sent = await deliverPreparedReply(prepareSlackReply({ text: fallbackText }, markdownOptions), session.threadTs, true);
|
|
1884
1847
|
if (!sent?.receipt.platformMessageIds.length) return;
|
|
1885
1848
|
markSlackStreamFallbackDelivered(session);
|
|
1886
1849
|
if (!session.stopped) try {
|
|
@@ -1938,16 +1901,13 @@ function createSlackStreamingDeliveryRuntime(setup) {
|
|
|
1938
1901
|
if (state.streamSession?.stoppedBySlack) return { visibleReplySent: false };
|
|
1939
1902
|
const replyThreadTs = params.forcedThreadTs ?? state.interruptedThreadTs ?? resolveDeliveryThreadTs(params);
|
|
1940
1903
|
const deliveryReplyThreadTs = replyDeliveryMode === "off" && !forcedReplyThreadTs && !isThreadReply ? void 0 : replyThreadTs;
|
|
1941
|
-
const preparedReply = prepareSlackReply(params.payload);
|
|
1904
|
+
const preparedReply = prepareSlackReply(params.payload, markdownOptions);
|
|
1942
1905
|
const deliveryKey = buildSlackEventDeliveryKey({
|
|
1943
1906
|
kind: params.kind,
|
|
1944
1907
|
payload: params.payload,
|
|
1945
1908
|
threadTs: deliveryReplyThreadTs
|
|
1946
1909
|
}, preparedReply);
|
|
1947
|
-
if (deliveryKey && deliveredKeys.has(deliveryKey)) {
|
|
1948
|
-
logVerbose("slack: suppressed duplicate normal delivery within the same turn");
|
|
1949
|
-
return { visibleReplySent: false };
|
|
1950
|
-
}
|
|
1910
|
+
if (deliveryKey && deliveredKeys.has(deliveryKey)) return { visibleReplySent: false };
|
|
1951
1911
|
const sent = await deliverPreparedReply(preparedReply, deliveryReplyThreadTs);
|
|
1952
1912
|
if (!sent?.receipt.platformMessageIds.length) return { visibleReplySent: false };
|
|
1953
1913
|
state.observedReplyDelivery = true;
|
|
@@ -1969,9 +1929,16 @@ function createSlackStreamingDeliveryRuntime(setup) {
|
|
|
1969
1929
|
};
|
|
1970
1930
|
const isStreamingEligible = (payload, options) => {
|
|
1971
1931
|
const reply = resolveSendableOutboundReplyParts(payload);
|
|
1972
|
-
const renderPlan = resolveSlackReplyRenderPlan(payload);
|
|
1932
|
+
const renderPlan = resolveSlackReplyRenderPlan(payload, payload.text, markdownOptions);
|
|
1973
1933
|
const plannedBlocks = renderPlan.mode === "single" ? renderPlan.blocks : renderPlan.blockPart?.blocks;
|
|
1974
|
-
|
|
1934
|
+
const previewThreadTs = state.streamSession?.threadTs ?? state.interruptedThreadTs ?? state.nativeProgressStreamThreadTs;
|
|
1935
|
+
const finalThreadTs = resolveSlackReplyThreadTs({
|
|
1936
|
+
replyToMode: replyDeliveryMode,
|
|
1937
|
+
replyToId: payload.replyToId,
|
|
1938
|
+
threadId: previewThreadTs,
|
|
1939
|
+
replyToCurrent: payload.replyToCurrent
|
|
1940
|
+
});
|
|
1941
|
+
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);
|
|
1975
1942
|
};
|
|
1976
1943
|
const deliverWithStreaming = async (params) => {
|
|
1977
1944
|
if (state.streamSession?.stoppedBySlack) return { visibleReplySent: false };
|
|
@@ -1984,7 +1951,12 @@ function createSlackStreamingDeliveryRuntime(setup) {
|
|
|
1984
1951
|
await rotateInterruptedStream();
|
|
1985
1952
|
if (state.streamSession?.stoppedBySlack) return { visibleReplySent: false };
|
|
1986
1953
|
let session = state.streamSession;
|
|
1987
|
-
const threadTs =
|
|
1954
|
+
const threadTs = resolveSlackReplyThreadTs({
|
|
1955
|
+
replyToMode: replyDeliveryMode,
|
|
1956
|
+
replyToId: params.payload.replyToId,
|
|
1957
|
+
threadId: session?.threadTs ?? state.interruptedThreadTs ?? replyPlan.nextThreadTs(),
|
|
1958
|
+
replyToCurrent: params.payload.replyToCurrent
|
|
1959
|
+
});
|
|
1988
1960
|
if (state.streamFailed || !threadTs) {
|
|
1989
1961
|
state.streamFailed = true;
|
|
1990
1962
|
return await deliverNormally({
|
|
@@ -1999,11 +1971,8 @@ function createSlackStreamingDeliveryRuntime(setup) {
|
|
|
1999
1971
|
...params,
|
|
2000
1972
|
threadTs,
|
|
2001
1973
|
textOverride: text
|
|
2002
|
-
});
|
|
2003
|
-
if (deliveryKey && deliveredKeys.has(deliveryKey)) {
|
|
2004
|
-
logVerbose("slack-stream: suppressed duplicate reply payload");
|
|
2005
|
-
return { visibleReplySent: false };
|
|
2006
|
-
}
|
|
1974
|
+
}, prepareSlackReply(params.payload, markdownOptions));
|
|
1975
|
+
if (deliveryKey && deliveredKeys.has(deliveryKey)) return { visibleReplySent: false };
|
|
2007
1976
|
let messageId;
|
|
2008
1977
|
let fallbackDelivery;
|
|
2009
1978
|
try {
|
|
@@ -2084,6 +2053,74 @@ function createSlackStreamingDeliveryRuntime(setup) {
|
|
|
2084
2053
|
resetDeliveryTracker: () => deliveredKeys.clear()
|
|
2085
2054
|
});
|
|
2086
2055
|
}
|
|
2056
|
+
// extensions/slack/src/monitor/message-handler/failure-notice.ts
|
|
2057
|
+
/** One outage policy for immediate replies and later origin-routed queue drains. */
|
|
2058
|
+
function createSlackFailureNoticePolicy(params, hasVisibleReply) {
|
|
2059
|
+
const { context, accountId, channelId, failureNoticeThreadTs, failureNoticeTeamId, statusThreadTs } = params;
|
|
2060
|
+
let sawTerminalFailurePayload = false;
|
|
2061
|
+
let pendingFailureNotice;
|
|
2062
|
+
const filterPassiveThreadFailure = (payload) => {
|
|
2063
|
+
if (payload.isError !== true || context.ChatType !== "channel" || isReplyPayloadNonTerminalToolErrorWarning(payload)) return payload;
|
|
2064
|
+
sawTerminalFailurePayload = true;
|
|
2065
|
+
if (hasVisibleReply()) return payload;
|
|
2066
|
+
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;
|
|
2067
|
+
const noticeThreadTs = failureNoticeThreadTs ?? (explicitlyAddressed ? statusThreadTs : void 0);
|
|
2068
|
+
const notice = {
|
|
2069
|
+
accountId,
|
|
2070
|
+
channelId,
|
|
2071
|
+
...noticeThreadTs ? { threadTs: noticeThreadTs } : {},
|
|
2072
|
+
failureText: payload.text ?? "",
|
|
2073
|
+
...failureNoticeTeamId ? { teamId: failureNoticeTeamId } : {}
|
|
2074
|
+
};
|
|
2075
|
+
if (failureNoticeThreadTs && !explicitlyAddressed && context.MentionSource !== "implicit_thread" && !hasSlackThreadParticipation(notice.accountId, notice.channelId, failureNoticeThreadTs, failureNoticeTeamId)) {
|
|
2076
|
+
logVerbose("slack: suppressed passive failure before thread participation");
|
|
2077
|
+
return null;
|
|
2078
|
+
}
|
|
2079
|
+
if (!explicitlyAddressed && hasSlackThreadFailureNotice(notice)) {
|
|
2080
|
+
logVerbose("slack: suppressed repeated passive channel or thread failure");
|
|
2081
|
+
return null;
|
|
2082
|
+
}
|
|
2083
|
+
pendingFailureNotice = notice;
|
|
2084
|
+
return payload;
|
|
2085
|
+
};
|
|
2086
|
+
return {
|
|
2087
|
+
filter: filterPassiveThreadFailure,
|
|
2088
|
+
recordDelivered(payload) {
|
|
2089
|
+
if (pendingFailureNotice && (!payload || payload.isError === true && !isReplyPayloadNonTerminalToolErrorWarning(payload) && (payload.text ?? "") === pendingFailureNotice.failureText)) {
|
|
2090
|
+
recordSlackThreadFailureNotice(pendingFailureNotice);
|
|
2091
|
+
pendingFailureNotice = void 0;
|
|
2092
|
+
}
|
|
2093
|
+
},
|
|
2094
|
+
complete() {
|
|
2095
|
+
if (!sawTerminalFailurePayload && context.ChatType === "channel") clearSlackThreadFailureNotice({
|
|
2096
|
+
accountId,
|
|
2097
|
+
channelId,
|
|
2098
|
+
...failureNoticeThreadTs ? { threadTs: failureNoticeThreadTs } : {},
|
|
2099
|
+
...failureNoticeTeamId ? { teamId: failureNoticeTeamId } : {}
|
|
2100
|
+
});
|
|
2101
|
+
}
|
|
2102
|
+
};
|
|
2103
|
+
}
|
|
2104
|
+
function createSlackQueuedFailureNoticePolicy(params, beginSessionRun) {
|
|
2105
|
+
let visibleReplySent = false;
|
|
2106
|
+
let policy = createSlackFailureNoticePolicy(params, () => visibleReplySent);
|
|
2107
|
+
return {
|
|
2108
|
+
begin() {
|
|
2109
|
+
visibleReplySent = false;
|
|
2110
|
+
policy = createSlackFailureNoticePolicy(params, () => visibleReplySent);
|
|
2111
|
+
const release = beginSessionRun();
|
|
2112
|
+
return (settlement) => {
|
|
2113
|
+
if (settlement?.completed && !settlement.failed && !settlement.transportPending) policy.complete();
|
|
2114
|
+
release();
|
|
2115
|
+
};
|
|
2116
|
+
},
|
|
2117
|
+
shouldSuppressReply: (payload) => policy.filter(payload) === null,
|
|
2118
|
+
onReplyDelivered(payload) {
|
|
2119
|
+
policy.recordDelivered(payload);
|
|
2120
|
+
visibleReplySent = true;
|
|
2121
|
+
}
|
|
2122
|
+
};
|
|
2123
|
+
}
|
|
2087
2124
|
// extensions/slack/src/monitor/message-handler/dispatch.ts
|
|
2088
2125
|
function formatSlackGroupThreadReply(text, participant) {
|
|
2089
2126
|
return `**${participant.name.replace(/[\\`*_{}[\]()<>#!|]/g, "\\$&").replace(/\s+/g, " ")}**\n${text}`;
|
|
@@ -2109,7 +2146,7 @@ async function dispatchPreparedSlackMessage(prepared) {
|
|
|
2109
2146
|
},
|
|
2110
2147
|
onSettled: () => {
|
|
2111
2148
|
releaseDeferred?.();
|
|
2112
|
-
upstreamLifecycle.onSettled?.();
|
|
2149
|
+
return upstreamLifecycle.onSettled?.();
|
|
2113
2150
|
}
|
|
2114
2151
|
};
|
|
2115
2152
|
const release = beginSessionRun();
|
|
@@ -2118,6 +2155,10 @@ async function dispatchPreparedSlackMessage(prepared) {
|
|
|
2118
2155
|
async function dispatchSlackMessageWithSetup(setup, beginSessionRun, turnAdoptionLifecycle) {
|
|
2119
2156
|
const { prepared } = setup;
|
|
2120
2157
|
const { account, ctx, message, route } = prepared;
|
|
2158
|
+
const markdownOptions = resolveSlackMarkdownOptions({
|
|
2159
|
+
cfg: ctx.cfg,
|
|
2160
|
+
accountId: account.accountId
|
|
2161
|
+
});
|
|
2121
2162
|
const { cfg, disableBlockStreaming, hasSlackCustomIdentity, hasRepliedRef, messageSentHookContext, messageSentHookTarget, onModelSelected, previewStreamingEnabled, replyPipeline, replyPlan, runtime, slackClient, slackStreaming, sourceReplyDeliveryMode, statusReactions, statusReactionsEnabled, statusThreadTs, suppressRoomEventTyping, useStreaming } = setup;
|
|
2122
2163
|
let dispatchError;
|
|
2123
2164
|
const delivery = createSlackStreamingDeliveryRuntime(setup);
|
|
@@ -2129,41 +2170,22 @@ async function dispatchSlackMessageWithSetup(setup, beginSessionRun, turnAdoptio
|
|
|
2129
2170
|
let turnCommentaryVisible = false;
|
|
2130
2171
|
const { draftStream, previewLifecycle } = progress;
|
|
2131
2172
|
setup.threadStatusGate.hasVisibleOutput = () => delivery.observedReplyDelivery || previewLifecycle.previewFinalized || Boolean(draftStream?.messageId());
|
|
2132
|
-
const
|
|
2133
|
-
|
|
2134
|
-
|
|
2135
|
-
|
|
2136
|
-
|
|
2137
|
-
|
|
2138
|
-
|
|
2139
|
-
if (delivery.observedReplyDelivery || previewLifecycle.previewFinalized) return payload;
|
|
2140
|
-
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;
|
|
2141
|
-
const noticeThreadTs = failureNoticeThreadTs ?? (explicitlyAddressed ? statusThreadTs : void 0);
|
|
2142
|
-
const notice = {
|
|
2143
|
-
accountId: account.accountId,
|
|
2144
|
-
channelId: message.channel,
|
|
2145
|
-
...noticeThreadTs ? { threadTs: noticeThreadTs } : {},
|
|
2146
|
-
failureText: payload.text ?? "",
|
|
2147
|
-
...failureNoticeTeamId ? { teamId: failureNoticeTeamId } : {}
|
|
2148
|
-
};
|
|
2149
|
-
if (failureNoticeThreadTs && !explicitlyAddressed && prepared.ctxPayload.MentionSource !== "implicit_thread" && !hasSlackThreadParticipation(notice.accountId, notice.channelId, failureNoticeThreadTs, failureNoticeTeamId)) {
|
|
2150
|
-
logVerbose("slack: suppressed passive failure before thread participation");
|
|
2151
|
-
return null;
|
|
2152
|
-
}
|
|
2153
|
-
if (!explicitlyAddressed && hasSlackThreadFailureNotice(notice)) {
|
|
2154
|
-
logVerbose("slack: suppressed repeated passive channel or thread failure");
|
|
2155
|
-
return null;
|
|
2156
|
-
}
|
|
2157
|
-
pendingFailureNotice = notice;
|
|
2158
|
-
return payload;
|
|
2173
|
+
const failurePolicyParams = {
|
|
2174
|
+
context: prepared.ctxPayload,
|
|
2175
|
+
accountId: account.accountId,
|
|
2176
|
+
channelId: message.channel,
|
|
2177
|
+
failureNoticeThreadTs: message.thread_ts,
|
|
2178
|
+
failureNoticeTeamId: prepared.eventScope?.teamId,
|
|
2179
|
+
statusThreadTs
|
|
2159
2180
|
};
|
|
2181
|
+
const failurePolicy = createSlackFailureNoticePolicy(failurePolicyParams, () => delivery.observedReplyDelivery || previewLifecycle.previewFinalized);
|
|
2160
2182
|
const deliverSlackPayload = async (incomingPayload, info) => {
|
|
2161
2183
|
let payload = incomingPayload;
|
|
2162
2184
|
if (info.participant && (payload.text || payload.mediaUrl || payload.mediaUrls?.length)) payload = {
|
|
2163
2185
|
...payload,
|
|
2164
2186
|
text: formatSlackGroupThreadReply(payload.text ?? "", info.participant)
|
|
2165
2187
|
};
|
|
2166
|
-
if (info.kind === "final" && slackStreaming.mode === "progress"
|
|
2188
|
+
if (info.kind === "final" && slackStreaming.mode === "progress") {
|
|
2167
2189
|
const supplement = getReplyPayloadTtsSupplement(payload);
|
|
2168
2190
|
const finalPayload = !progress.useDraftProgressCard && !progress.useNativeProgressStreaming && supplement && !supplement.visibleTextAlreadyDelivered && !payload.text?.trim() ? {
|
|
2169
2191
|
...payload,
|
|
@@ -2203,15 +2225,11 @@ async function dispatchSlackMessageWithSetup(setup, beginSessionRun, turnAdoptio
|
|
|
2203
2225
|
const reply = resolveSendableOutboundReplyParts(payload);
|
|
2204
2226
|
const ttsSupplement = getReplyPayloadTtsSupplement(payload);
|
|
2205
2227
|
const replySourceText = payload.text ?? ttsSupplement?.spokenText;
|
|
2206
|
-
const replyRenderPlan = resolveSlackReplyRenderPlan(payload, replySourceText);
|
|
2228
|
+
const replyRenderPlan = resolveSlackReplyRenderPlan(payload, replySourceText, markdownOptions);
|
|
2207
2229
|
const slackBlocks = replyRenderPlan.mode === "single" ? replyRenderPlan.blocks : replyRenderPlan.blockPart?.blocks;
|
|
2208
2230
|
const requiresSeparateFallbackDelivery = replyRenderPlan.mode === "split" || replyRenderPlan.textIsSlackPlainText === true;
|
|
2209
2231
|
const trimmedFinalText = replyRenderPlan.mode === "single" ? replyRenderPlan.text.trim() : replyRenderPlan.fallbackText.trim();
|
|
2210
|
-
const previewFinalText = replyRenderPlan.mode === "single" && replyRenderPlan.textIsSlackMrkdwn ? trimmedFinalText : normalizeSlackOutboundText((replySourceText ?? "").trim(),
|
|
2211
|
-
cfg,
|
|
2212
|
-
channel: "slack",
|
|
2213
|
-
accountId: account.accountId
|
|
2214
|
-
}) });
|
|
2232
|
+
const previewFinalText = replyRenderPlan.mode === "single" && replyRenderPlan.textIsSlackMrkdwn ? trimmedFinalText : normalizeSlackOutboundText((replySourceText ?? "").trim(), markdownOptions);
|
|
2215
2233
|
const previewFinalTextFitsEdit = countSlackTextUtf8Bytes(previewFinalText) <= SLACK_EDIT_TEXT_MAX_BYTES;
|
|
2216
2234
|
const shouldRestoreTtsSupplementTextForPreviewFallback = Boolean(ttsSupplement) && ttsSupplement?.visibleTextAlreadyDelivered !== true && Boolean(draftStream) && !previewLifecycle.previewFinalized && !previewLifecycle.finalDelivered && previewStreamingEnabled && !payload.text?.trim();
|
|
2217
2235
|
let ttsPreviewFinalization;
|
|
@@ -2221,11 +2239,18 @@ async function dispatchSlackMessageWithSetup(setup, beginSessionRun, turnAdoptio
|
|
|
2221
2239
|
isError: payload.isError === true,
|
|
2222
2240
|
adapter: {
|
|
2223
2241
|
buildFinalEdit: () => {
|
|
2224
|
-
|
|
2242
|
+
const threadTs = delivery.usedReplyThreadTs ?? statusThreadTs;
|
|
2243
|
+
const finalThreadTs = resolveSlackReplyThreadTs({
|
|
2244
|
+
replyToMode: setup.replyDeliveryMode,
|
|
2245
|
+
replyToId: payload.replyToId,
|
|
2246
|
+
threadId: threadTs,
|
|
2247
|
+
replyToCurrent: payload.replyToCurrent
|
|
2248
|
+
});
|
|
2249
|
+
if (hasSlackCustomIdentity || finalThreadTs !== threadTs || !previewStreamingEnabled || reply.hasMedia && !ttsSupplement || payload.isError || requiresSeparateFallbackDelivery || !previewFinalTextFitsEdit || trimmedFinalText.length === 0 && !slackBlocks?.length) return;
|
|
2225
2250
|
return {
|
|
2226
2251
|
text: previewFinalText,
|
|
2227
2252
|
blocks: slackBlocks,
|
|
2228
|
-
threadTs
|
|
2253
|
+
threadTs
|
|
2229
2254
|
};
|
|
2230
2255
|
},
|
|
2231
2256
|
editFinal: async (preview, edit) => {
|
|
@@ -2320,7 +2345,7 @@ async function dispatchSlackMessageWithSetup(setup, beginSessionRun, turnAdoptio
|
|
|
2320
2345
|
...replyPipeline,
|
|
2321
2346
|
transformReplyPayload: (payload) => {
|
|
2322
2347
|
const transformed = replyPipeline.transformReplyPayload ? replyPipeline.transformReplyPayload(payload) : payload;
|
|
2323
|
-
return transformed ?
|
|
2348
|
+
return transformed ? failurePolicy.filter(transformed) : null;
|
|
2324
2349
|
},
|
|
2325
2350
|
humanDelay: resolveHumanDelayConfig(cfg, route.agentId)
|
|
2326
2351
|
},
|
|
@@ -2337,7 +2362,7 @@ async function dispatchSlackMessageWithSetup(setup, beginSessionRun, turnAdoptio
|
|
|
2337
2362
|
replyOptions: {
|
|
2338
2363
|
onVisibleWorkSessions: progress.onVisibleWorkSessions,
|
|
2339
2364
|
groupThreadReplyFormatter: formatSlackGroupThreadReply,
|
|
2340
|
-
queuedDeliveryCorrelations: [
|
|
2365
|
+
queuedDeliveryCorrelations: [createSlackQueuedFailureNoticePolicy(failurePolicyParams, beginSessionRun)],
|
|
2341
2366
|
...turnAdoptionLifecycle ? { turnAdoptionLifecycle } : {},
|
|
2342
2367
|
skillFilter: prepared.channelConfig?.skills,
|
|
2343
2368
|
sourceReplyDeliveryMode,
|
|
@@ -2381,7 +2406,7 @@ async function dispatchSlackMessageWithSetup(setup, beginSessionRun, turnAdoptio
|
|
|
2381
2406
|
if (payload.kind === "preamble" && await shouldYieldDraftProgress()) return false;
|
|
2382
2407
|
if (prepared.turnAdoptionLifecycle?.abortSignal?.aborted) return false;
|
|
2383
2408
|
progress.progressWorkCounter.noteItem(payload);
|
|
2384
|
-
return progress.preambleOnlyProgress && payload.kind !== "preamble" ? await progress.progressDraft.noteActivity() : await progress.progressDraft.pushItemEvent(payload);
|
|
2409
|
+
return progress.preambleOnlyProgress && payload.kind !== "preamble" && payload.kind !== "model-wait" ? await progress.progressDraft.noteActivity() : await progress.progressDraft.pushItemEvent(payload);
|
|
2385
2410
|
},
|
|
2386
2411
|
onPlanUpdate: async (payload) => {
|
|
2387
2412
|
if (payload.phase !== "update") return false;
|
|
@@ -2395,12 +2420,7 @@ async function dispatchSlackMessageWithSetup(setup, beginSessionRun, turnAdoptio
|
|
|
2395
2420
|
settledDispatchResult = result;
|
|
2396
2421
|
const agentRunOutcome = readAgentRunTerminalOutcome(result);
|
|
2397
2422
|
agentRunFailed = agentRunOutcome === "failed";
|
|
2398
|
-
if (agentRunOutcome === "completed"
|
|
2399
|
-
accountId: account.accountId,
|
|
2400
|
-
channelId: message.channel,
|
|
2401
|
-
...failureNoticeThreadTs ? { threadTs: failureNoticeThreadTs } : {},
|
|
2402
|
-
...failureNoticeTeamId ? { teamId: failureNoticeTeamId } : {}
|
|
2403
|
-
});
|
|
2423
|
+
if (agentRunOutcome === "completed") failurePolicy.complete();
|
|
2404
2424
|
}
|
|
2405
2425
|
} catch (err) {
|
|
2406
2426
|
dispatchError ??= err;
|
|
@@ -2416,7 +2436,7 @@ async function dispatchSlackMessageWithSetup(setup, beginSessionRun, turnAdoptio
|
|
|
2416
2436
|
if (hasVisibleInboundReplyDispatch(settledDispatchResult)) await previewLifecycle.observeDelivery({ visibleReplySent: true });
|
|
2417
2437
|
}
|
|
2418
2438
|
await previewLifecycle.cleanup({ failed: Boolean(dispatchError || agentRunFailed) });
|
|
2419
|
-
if (
|
|
2439
|
+
if (anyReplyDelivered) failurePolicy.recordDelivered();
|
|
2420
2440
|
if (dispatchError || agentRunFailed) await progress.finalizeDraftProgressCard("error", { postIfMissing: !anyReplyDelivered });
|
|
2421
2441
|
await progress.dropDetachedProgressCards();
|
|
2422
2442
|
if (statusReactionsEnabled) {
|
|
@@ -2436,11 +2456,6 @@ async function dispatchSlackMessageWithSetup(setup, beginSessionRun, turnAdoptio
|
|
|
2436
2456
|
if (dispatchError) throw toErrorObject(dispatchError, "Slack dispatch failed");
|
|
2437
2457
|
if (!anyReplyDelivered && !previewLifecycle.previewFinalized && !(agentRunFailed && progress.useDraftProgressCard)) {
|
|
2438
2458
|
if (progress.useDraftProgressCard) await draftStream?.clear();
|
|
2439
|
-
return;
|
|
2440
|
-
}
|
|
2441
|
-
if (shouldLogVerbose()) {
|
|
2442
|
-
const finalCount = resolveInboundReplyDispatchCounts(settledDispatchResult).final;
|
|
2443
|
-
logVerbose(`slack: delivered ${finalCount} repl${finalCount === 1 ? "y" : "ies"} to ${prepared.replyTarget}`);
|
|
2444
2459
|
}
|
|
2445
2460
|
}
|
|
2446
2461
|
// extensions/slack/src/agent-context.ts
|
|
@@ -2482,13 +2497,12 @@ function normalizeSlackAppContextEntities(value) {
|
|
|
2482
2497
|
});
|
|
2483
2498
|
}
|
|
2484
2499
|
// extensions/slack/src/monitor/thread.ts
|
|
2485
|
-
const
|
|
2486
|
-
|
|
2487
|
-
|
|
2488
|
-
|
|
2489
|
-
|
|
2490
|
-
|
|
2491
|
-
}
|
|
2500
|
+
const threadStarterCache = createStaleWhileRevalidateCache({
|
|
2501
|
+
maxEntries: 2e3,
|
|
2502
|
+
maxPending: Number.POSITIVE_INFINITY,
|
|
2503
|
+
ttlMs: 216e5,
|
|
2504
|
+
cacheable: (starter) => starter !== null
|
|
2505
|
+
});
|
|
2492
2506
|
function formatSlackFilePlaceholder(files) {
|
|
2493
2507
|
return `[attached: ${formatSlackFileReferenceList(files)}]`;
|
|
2494
2508
|
}
|
|
@@ -2523,40 +2537,35 @@ function resolveSlackMessageText(message) {
|
|
|
2523
2537
|
}, { preserveMessageTextWhitespace: true });
|
|
2524
2538
|
}
|
|
2525
2539
|
async function resolveSlackThreadStarter(params) {
|
|
2526
|
-
evictThreadStarterCache();
|
|
2527
2540
|
const cacheKey = JSON.stringify([
|
|
2528
2541
|
params.workspaceScope.accountId,
|
|
2529
2542
|
params.workspaceScope.teamId,
|
|
2530
2543
|
params.channelId,
|
|
2531
2544
|
params.threadTs
|
|
2532
2545
|
]);
|
|
2533
|
-
const cached = THREAD_STARTER_CACHE.get(cacheKey);
|
|
2534
|
-
if (cached && !params.refresh) return cached.value;
|
|
2535
|
-
if (params.refresh) THREAD_STARTER_CACHE.delete(cacheKey);
|
|
2536
2546
|
try {
|
|
2537
|
-
const
|
|
2538
|
-
|
|
2539
|
-
|
|
2540
|
-
|
|
2541
|
-
|
|
2542
|
-
|
|
2543
|
-
|
|
2544
|
-
|
|
2545
|
-
|
|
2546
|
-
|
|
2547
|
-
|
|
2548
|
-
|
|
2549
|
-
|
|
2550
|
-
|
|
2551
|
-
|
|
2552
|
-
|
|
2553
|
-
|
|
2554
|
-
|
|
2555
|
-
|
|
2556
|
-
|
|
2547
|
+
const { value } = await threadStarterCache.read(cacheKey, async () => {
|
|
2548
|
+
const message = (await params.client.conversations.replies({
|
|
2549
|
+
channel: params.channelId,
|
|
2550
|
+
ts: params.threadTs,
|
|
2551
|
+
limit: 1,
|
|
2552
|
+
inclusive: true
|
|
2553
|
+
}))?.messages?.[0];
|
|
2554
|
+
const text = message ? resolveSlackMessageText(message) : void 0;
|
|
2555
|
+
const files = message?.files?.length ? message.files : void 0;
|
|
2556
|
+
if (!message || !text && !files) return null;
|
|
2557
|
+
return {
|
|
2558
|
+
text: text || formatSlackFilePlaceholder(files),
|
|
2559
|
+
userId: message.user,
|
|
2560
|
+
botId: message.bot_id,
|
|
2561
|
+
ts: message.ts,
|
|
2562
|
+
files
|
|
2563
|
+
};
|
|
2564
|
+
}, {
|
|
2565
|
+
allowStale: false,
|
|
2566
|
+
refresh: params.refresh
|
|
2557
2567
|
});
|
|
2558
|
-
|
|
2559
|
-
return starter;
|
|
2568
|
+
return value;
|
|
2560
2569
|
} catch (err) {
|
|
2561
2570
|
logVerbose(`slack thread starter fetch failed channel=${params.channelId} ts=${params.threadTs}: ${formatErrorMessage(err)}`);
|
|
2562
2571
|
return null;
|
|
@@ -2610,8 +2619,7 @@ async function resolveSlackThreadHistory(params) {
|
|
|
2610
2619
|
retained.push([msg, text]);
|
|
2611
2620
|
}
|
|
2612
2621
|
if (retained.length > maxMessages) retained.splice(0, retained.length - maxMessages);
|
|
2613
|
-
|
|
2614
|
-
cursor = typeof next === "string" && next.trim().length > 0 ? next.trim() : void 0;
|
|
2622
|
+
cursor = normalizeOptionalString(response.response_metadata?.next_cursor);
|
|
2615
2623
|
if (response.has_more && !cursor) {
|
|
2616
2624
|
params.onOmission?.("Slack returned an incomplete thread page without a cursor");
|
|
2617
2625
|
return [];
|
|
@@ -2660,7 +2668,7 @@ async function resolveSlackChannelHistory(params) {
|
|
|
2660
2668
|
cursor = response.response_metadata?.next_cursor?.trim() || void 0;
|
|
2661
2669
|
if (!cursor || scanned >= params.limit) break;
|
|
2662
2670
|
}
|
|
2663
|
-
return messages.slice(0, params.limit).
|
|
2671
|
+
return messages.slice(0, params.limit).reverse();
|
|
2664
2672
|
}
|
|
2665
2673
|
// extensions/slack/src/monitor/message-handler/preflight-audio.ts
|
|
2666
2674
|
function isSlackAudioFile(file) {
|
|
@@ -2710,7 +2718,7 @@ const SLACK_MENTION_RESOLUTION_CONCURRENCY = 4;
|
|
|
2710
2718
|
const SLACK_MENTION_RESOLUTION_MAX_LOOKUPS_PER_MESSAGE = 20;
|
|
2711
2719
|
const SLACK_USER_MENTION_RE$1 = /<@([A-Z0-9]+)(?:\|[^>]+)?>/gi;
|
|
2712
2720
|
const MAX_SLACK_UNAVAILABLE_FILE_TEXT_CHARS = 2e3;
|
|
2713
|
-
const loadSlackMediaModule$
|
|
2721
|
+
const loadSlackMediaModule$2 = createLazyRuntimeModule(() => import("./actions-s3CcFO45.mjs").then((n) => n._));
|
|
2714
2722
|
function formatSlackUnavailableMedia(params) {
|
|
2715
2723
|
let fileReferences = params.files?.map((file) => `${formatSlackFileReference(file)} unavailable (${file.reason})`).join(", ");
|
|
2716
2724
|
if (fileReferences && fileReferences.length > MAX_SLACK_UNAVAILABLE_FILE_TEXT_CHARS) fileReferences = `${truncateUtf16Safe(fileReferences, MAX_SLACK_UNAVAILABLE_FILE_TEXT_CHARS)}; … (file references truncated)`;
|
|
@@ -2731,7 +2739,6 @@ function collectUniqueSlackMentionIds(texts) {
|
|
|
2731
2739
|
const seen = /* @__PURE__ */ new Set();
|
|
2732
2740
|
for (const text of texts) {
|
|
2733
2741
|
if (!text) continue;
|
|
2734
|
-
SLACK_USER_MENTION_RE$1.lastIndex = 0;
|
|
2735
2742
|
for (const match of text.matchAll(SLACK_USER_MENTION_RE$1)) {
|
|
2736
2743
|
const userId = match[1];
|
|
2737
2744
|
if (userId) seen.add(userId);
|
|
@@ -2741,35 +2748,24 @@ function collectUniqueSlackMentionIds(texts) {
|
|
|
2741
2748
|
}
|
|
2742
2749
|
function renderSlackUserMentions(text, renderedMentions) {
|
|
2743
2750
|
if (!text || renderedMentions.size === 0) return text;
|
|
2744
|
-
SLACK_USER_MENTION_RE$1.lastIndex = 0;
|
|
2745
2751
|
return text.replace(SLACK_USER_MENTION_RE$1, (full, userId) => {
|
|
2746
2752
|
return renderedMentions.get(userId) ?? full;
|
|
2747
2753
|
});
|
|
2748
2754
|
}
|
|
2749
|
-
function filterInheritedParentFiles(params) {
|
|
2750
|
-
const { files, isThreadReply, threadStarter } = params;
|
|
2751
|
-
if (!isThreadReply || !files?.length || !threadStarter?.files?.length) return files;
|
|
2752
|
-
const starterFileIds = new Set(threadStarter.files.map((file) => file.id));
|
|
2753
|
-
const filtered = files.filter((file) => !file.id || !starterFileIds.has(file.id));
|
|
2754
|
-
if (filtered.length < files.length) logVerbose(`slack: filtered ${files.length - filtered.length} inherited parent file(s) from thread reply`);
|
|
2755
|
-
return filtered.length > 0 ? filtered : void 0;
|
|
2756
|
-
}
|
|
2757
2755
|
async function resolveSlackMessageContent(params) {
|
|
2758
|
-
|
|
2759
|
-
|
|
2760
|
-
|
|
2761
|
-
threadStarter
|
|
2762
|
-
|
|
2763
|
-
|
|
2756
|
+
let ownFiles = params.message.files;
|
|
2757
|
+
const { isThreadReply, threadStarter } = params;
|
|
2758
|
+
if (isThreadReply && ownFiles?.length && threadStarter?.files?.length) {
|
|
2759
|
+
const starterFileIds = new Set(threadStarter.files.map((file) => file.id));
|
|
2760
|
+
const filtered = ownFiles.filter((file) => !file.id || !starterFileIds.has(file.id));
|
|
2761
|
+
ownFiles = filtered.length > 0 ? filtered : void 0;
|
|
2762
|
+
}
|
|
2763
|
+
const attachmentContent = ownFiles?.length || params.message.attachments?.length ? await loadSlackMediaModule$2().then(({ resolveSlackAttachmentContent }) => resolveSlackAttachmentContent({
|
|
2764
2764
|
files: ownFiles,
|
|
2765
2765
|
attachments: params.message.attachments,
|
|
2766
2766
|
client: params.client,
|
|
2767
2767
|
token: params.botToken,
|
|
2768
2768
|
maxBytes: params.mediaMaxBytes,
|
|
2769
|
-
readIdleTimeoutMs: params.mediaReadIdleTimeoutMs,
|
|
2770
|
-
totalTimeoutMs: params.mediaTotalTimeoutMs,
|
|
2771
|
-
abortSignal: params.abortSignal,
|
|
2772
|
-
assertCurrent: params.assertCurrent,
|
|
2773
2769
|
preloadedMedia: params.preloadedMedia
|
|
2774
2770
|
})) : null;
|
|
2775
2771
|
const effectiveDirectMedia = attachmentContent?.media.length ? attachmentContent.media : null;
|
|
@@ -2824,7 +2820,7 @@ function resolveSlackDmHistoryLimit(params) {
|
|
|
2824
2820
|
return resolvePromptHistoryLimit(override ?? params.defaultLimit, 0);
|
|
2825
2821
|
}
|
|
2826
2822
|
async function resolveSlackDmHistoryContext(params) {
|
|
2827
|
-
const maxMessages =
|
|
2823
|
+
const maxMessages = params.limit;
|
|
2828
2824
|
if (maxMessages <= 0) return {
|
|
2829
2825
|
body: void 0,
|
|
2830
2826
|
inboundHistory: void 0
|
|
@@ -2845,7 +2841,7 @@ async function resolveSlackDmHistoryContext(params) {
|
|
|
2845
2841
|
message,
|
|
2846
2842
|
body
|
|
2847
2843
|
}] : [];
|
|
2848
|
-
}).slice(0, maxMessages).
|
|
2844
|
+
}).slice(0, maxMessages).reverse();
|
|
2849
2845
|
if (messages.length === 0) return {
|
|
2850
2846
|
body: void 0,
|
|
2851
2847
|
inboundHistory: void 0
|
|
@@ -2903,6 +2899,7 @@ const SLACK_HISTORY_MEDIA_MAX_ATTACHMENTS = 4;
|
|
|
2903
2899
|
const SLACK_HISTORY_MEDIA_MAX_BYTES = 10485760;
|
|
2904
2900
|
const SLACK_HISTORY_MEDIA_IDLE_TIMEOUT_MS = 1e3;
|
|
2905
2901
|
const SLACK_HISTORY_MEDIA_TOTAL_TIMEOUT_MS = 3e3;
|
|
2902
|
+
const loadSlackMediaModule$1 = createLazyRuntimeModule(() => import("./actions-s3CcFO45.mjs").then((n) => n._));
|
|
2906
2903
|
async function resolveSlackRoomHistory(params) {
|
|
2907
2904
|
if (params.ctx.historyLimit <= 0 || !params.message.ts) return [];
|
|
2908
2905
|
const warnOmission = (reason) => {
|
|
@@ -2956,26 +2953,51 @@ async function resolveSlackRoomHistory(params) {
|
|
|
2956
2953
|
sender: user?.name ?? message.userId ?? `Bot (${message.botId ?? "unknown"})`
|
|
2957
2954
|
});
|
|
2958
2955
|
}
|
|
2956
|
+
async function resolveSlackHistoryMedia(message, maxAttachments) {
|
|
2957
|
+
const { ctx, eventScope, assertCurrent, abortSignal } = params;
|
|
2958
|
+
const files = sliceSlackImageFileCandidates(message.files, maxAttachments);
|
|
2959
|
+
const attachments = [];
|
|
2960
|
+
let remaining = Math.max(0, maxAttachments - files.length);
|
|
2961
|
+
if (remaining > 0 && message.attachments?.length) for (const attachment of message.attachments) {
|
|
2962
|
+
if (attachment.is_share !== true) continue;
|
|
2963
|
+
const hasImageUrl = Boolean(normalizeOptionalString(attachment.image_url));
|
|
2964
|
+
const attachmentFiles = sliceSlackImageFileCandidates(attachment.files, remaining - (hasImageUrl ? 1 : 0));
|
|
2965
|
+
if (!hasImageUrl && attachmentFiles.length === 0) continue;
|
|
2966
|
+
attachments.push({
|
|
2967
|
+
...attachment,
|
|
2968
|
+
files: attachmentFiles
|
|
2969
|
+
});
|
|
2970
|
+
remaining -= (hasImageUrl ? 1 : 0) + attachmentFiles.length;
|
|
2971
|
+
if (remaining <= 0) break;
|
|
2972
|
+
}
|
|
2973
|
+
if (files.length === 0 && attachments.length === 0) return {
|
|
2974
|
+
media: [],
|
|
2975
|
+
attempted: 0
|
|
2976
|
+
};
|
|
2977
|
+
const { resolveSlackAttachmentContent } = await loadSlackMediaModule$1();
|
|
2978
|
+
const content = await resolveSlackAttachmentContent({
|
|
2979
|
+
files,
|
|
2980
|
+
attachments,
|
|
2981
|
+
client: eventScope?.client ?? ctx.app.client,
|
|
2982
|
+
token: ctx.botToken,
|
|
2983
|
+
maxBytes: Math.min(ctx.mediaMaxBytes, SLACK_HISTORY_MEDIA_MAX_BYTES),
|
|
2984
|
+
readIdleTimeoutMs: SLACK_HISTORY_MEDIA_IDLE_TIMEOUT_MS,
|
|
2985
|
+
totalTimeoutMs: SLACK_HISTORY_MEDIA_TOTAL_TIMEOUT_MS,
|
|
2986
|
+
assertCurrent,
|
|
2987
|
+
abortSignal
|
|
2988
|
+
});
|
|
2989
|
+
return {
|
|
2990
|
+
media: await toInboundMediaFactsWithMetadata(content?.media, {
|
|
2991
|
+
kind: "image",
|
|
2992
|
+
messageId: message.ts
|
|
2993
|
+
}),
|
|
2994
|
+
attempted: maxAttachments - remaining
|
|
2995
|
+
};
|
|
2996
|
+
}
|
|
2959
2997
|
const entries = [];
|
|
2960
2998
|
let mediaRemaining = SLACK_HISTORY_MEDIA_MAX_ATTACHMENTS;
|
|
2961
2999
|
for (const { message, sender } of permitted.slice(-params.ctx.historyLimit)) {
|
|
2962
|
-
const { media, attempted } = mediaRemaining > 0 && (message.files?.length || message.attachments?.length) ? await resolveSlackHistoryMedia({
|
|
2963
|
-
ctx: params.ctx,
|
|
2964
|
-
eventScope: params.eventScope,
|
|
2965
|
-
maxAttachments: mediaRemaining,
|
|
2966
|
-
assertCurrent: params.assertCurrent,
|
|
2967
|
-
abortSignal: params.abortSignal,
|
|
2968
|
-
message: {
|
|
2969
|
-
type: "message",
|
|
2970
|
-
channel: params.message.channel,
|
|
2971
|
-
ts: message.ts,
|
|
2972
|
-
user: message.userId,
|
|
2973
|
-
bot_id: message.botId,
|
|
2974
|
-
text: message.text,
|
|
2975
|
-
files: message.files,
|
|
2976
|
-
attachments: message.attachments
|
|
2977
|
-
}
|
|
2978
|
-
}) : {
|
|
3000
|
+
const { media, attempted } = mediaRemaining > 0 && (message.files?.length || message.attachments?.length) ? await resolveSlackHistoryMedia(message, mediaRemaining) : {
|
|
2979
3001
|
media: [],
|
|
2980
3002
|
attempted: 0
|
|
2981
3003
|
};
|
|
@@ -3002,57 +3024,6 @@ function sliceSlackImageFileCandidates(files, limit) {
|
|
|
3002
3024
|
if (limit <= 0 || !files?.length) return [];
|
|
3003
3025
|
return files.filter(isSlackImageFileCandidate).slice(0, limit);
|
|
3004
3026
|
}
|
|
3005
|
-
function sliceSlackHistoryAttachmentCandidates(attachments, limit) {
|
|
3006
|
-
if (limit <= 0 || !attachments?.length) return [];
|
|
3007
|
-
const out = [];
|
|
3008
|
-
let remaining = limit;
|
|
3009
|
-
for (const attachment of attachments) {
|
|
3010
|
-
if (attachment.is_share !== true) continue;
|
|
3011
|
-
const hasImageUrl = Boolean(normalizeOptionalString(attachment.image_url));
|
|
3012
|
-
const files = sliceSlackImageFileCandidates(attachment.files, remaining - (hasImageUrl ? 1 : 0));
|
|
3013
|
-
if (!hasImageUrl && files.length === 0) continue;
|
|
3014
|
-
out.push({
|
|
3015
|
-
...attachment,
|
|
3016
|
-
files
|
|
3017
|
-
});
|
|
3018
|
-
remaining -= (hasImageUrl ? 1 : 0) + files.length;
|
|
3019
|
-
if (remaining <= 0) break;
|
|
3020
|
-
}
|
|
3021
|
-
return out;
|
|
3022
|
-
}
|
|
3023
|
-
async function resolveSlackHistoryMedia(params) {
|
|
3024
|
-
const files = sliceSlackImageFileCandidates(params.message.files, params.maxAttachments);
|
|
3025
|
-
const attachments = sliceSlackHistoryAttachmentCandidates(params.message.attachments, Math.max(0, params.maxAttachments - files.length));
|
|
3026
|
-
if (files.length === 0 && attachments.length === 0) return {
|
|
3027
|
-
media: [],
|
|
3028
|
-
attempted: 0
|
|
3029
|
-
};
|
|
3030
|
-
const attempted = files.length + attachments.reduce((count, attachment) => count + (normalizeOptionalString(attachment.image_url) ? 1 : 0) + (attachment.files?.length ?? 0), 0);
|
|
3031
|
-
const content = await resolveSlackMessageContent({
|
|
3032
|
-
message: {
|
|
3033
|
-
...params.message,
|
|
3034
|
-
files,
|
|
3035
|
-
attachments
|
|
3036
|
-
},
|
|
3037
|
-
isThreadReply: false,
|
|
3038
|
-
threadStarter: null,
|
|
3039
|
-
isBotMessage: Boolean(params.message.bot_id),
|
|
3040
|
-
client: params.eventScope?.client ?? params.ctx.app.client,
|
|
3041
|
-
botToken: params.ctx.botToken,
|
|
3042
|
-
mediaMaxBytes: Math.min(params.ctx.mediaMaxBytes, SLACK_HISTORY_MEDIA_MAX_BYTES),
|
|
3043
|
-
mediaReadIdleTimeoutMs: SLACK_HISTORY_MEDIA_IDLE_TIMEOUT_MS,
|
|
3044
|
-
mediaTotalTimeoutMs: SLACK_HISTORY_MEDIA_TOTAL_TIMEOUT_MS,
|
|
3045
|
-
assertCurrent: params.assertCurrent,
|
|
3046
|
-
abortSignal: params.abortSignal
|
|
3047
|
-
});
|
|
3048
|
-
return {
|
|
3049
|
-
media: await toInboundMediaFactsWithMetadata(content?.effectiveDirectMedia, {
|
|
3050
|
-
kind: "image",
|
|
3051
|
-
messageId: params.message.ts
|
|
3052
|
-
}),
|
|
3053
|
-
attempted
|
|
3054
|
-
};
|
|
3055
|
-
}
|
|
3056
3027
|
// extensions/slack/src/monitor/message-handler/prepare-session-presentation.ts
|
|
3057
3028
|
function resolveSlackGroupSessionSubject(params) {
|
|
3058
3029
|
const channelName = normalizeOptionalString(params.channelName);
|
|
@@ -3061,7 +3032,7 @@ function resolveSlackGroupSessionSubject(params) {
|
|
|
3061
3032
|
return `Slack Channel (Workspace ID: ${params.workspaceId}, Channel ID: ${params.channelId})`;
|
|
3062
3033
|
}
|
|
3063
3034
|
// extensions/slack/src/monitor/message-handler/prepare-thread-context.ts
|
|
3064
|
-
const loadSlackMediaModule = createLazyRuntimeModule(() => import("./actions-
|
|
3035
|
+
const loadSlackMediaModule = createLazyRuntimeModule(() => import("./actions-s3CcFO45.mjs").then((n) => n._));
|
|
3065
3036
|
const SLACK_THREAD_CONTEXT_USER_LOOKUP_CONCURRENCY = 4;
|
|
3066
3037
|
function formatSlackThreadLabelSnippet(text) {
|
|
3067
3038
|
return truncateUtf16Safe(text.replace(/\s+/g, " "), 80);
|
|
@@ -3110,13 +3081,14 @@ async function resolveSlackThreadContextData(params) {
|
|
|
3110
3081
|
const isOutboundOnlyThreadSession = threadSessionFreshness !== void 0 && threadSessionFreshness.state !== "missing" && threadSessionFreshness.entry.lastInteractionAt === void 0 && threadSessionFreshness.entry.updatedAt !== 0;
|
|
3111
3082
|
const shouldSeedInitialThreadContext = Boolean(params.isThreadReply && params.threadTs && (threadSessionFreshness ? threadSessionFreshness.state !== "fresh" || isOutboundOnlyThreadSession : threadSessionPreviousTimestamp === void 0));
|
|
3112
3083
|
const shouldLoadInitialThreadHistory = shouldSeedInitialThreadContext || params.forceInitialHistory === true;
|
|
3113
|
-
|
|
3084
|
+
const readThreadContextData = () => ({
|
|
3114
3085
|
threadStarterBody,
|
|
3115
3086
|
threadHistoryBody,
|
|
3116
3087
|
shouldSeedInitialThreadContext,
|
|
3117
3088
|
threadLabel,
|
|
3118
3089
|
threadStarterMedia
|
|
3119
|
-
};
|
|
3090
|
+
});
|
|
3091
|
+
if (!params.isThreadReply || !params.threadTs) return readThreadContextData();
|
|
3120
3092
|
const starter = params.threadStarter;
|
|
3121
3093
|
const starterSenderName = params.allowNameMatching && params.allowFromLower.length > 0 && starter?.userId ? (await params.ctx.resolveUserName(starter.userId, params.eventScope))?.name : void 0;
|
|
3122
3094
|
params.assertHistoryCurrent?.();
|
|
@@ -3156,10 +3128,6 @@ async function resolveSlackThreadContextData(params) {
|
|
|
3156
3128
|
unavailableMediaCount: attachmentContent.unavailableMediaCount,
|
|
3157
3129
|
prependUnavailable: true
|
|
3158
3130
|
});
|
|
3159
|
-
if (threadStarterMedia) {
|
|
3160
|
-
const starterPlaceholders = threadStarterMedia.map((item) => item.placeholder).join(", ");
|
|
3161
|
-
logVerbose(`slack: hydrated thread starter file ${starterPlaceholders} from root message`);
|
|
3162
|
-
}
|
|
3163
3131
|
}
|
|
3164
3132
|
} else threadLabel = `Slack thread ${params.roomLabel}`;
|
|
3165
3133
|
const includeBotStarterAsRootContext = Boolean(starter?.text && starterIsCurrentBot && shouldSeedInitialThreadContext);
|
|
@@ -3168,7 +3136,6 @@ async function resolveSlackThreadContextData(params) {
|
|
|
3168
3136
|
else if (includeBotStarterAsRootContext) {
|
|
3169
3137
|
const snippet = formatSlackThreadLabelSnippet(starter?.text ?? "").trim();
|
|
3170
3138
|
threadLabel = `Slack thread ${params.roomLabel}${snippet ? ` (assistant root): ${snippet}` : ""}`;
|
|
3171
|
-
logVerbose("slack: retained current-bot thread starter as assistant root context");
|
|
3172
3139
|
}
|
|
3173
3140
|
const threadInitialHistoryLimit = Math.min(params.account.config?.thread?.initialHistoryLimit ?? 20, params.historyLimit ?? Number.POSITIVE_INFINITY);
|
|
3174
3141
|
if (threadInitialHistoryLimit > 0 && shouldLoadInitialThreadHistory) {
|
|
@@ -3193,28 +3160,22 @@ async function resolveSlackThreadContextData(params) {
|
|
|
3193
3160
|
}, "Slack automatic thread history omitted");
|
|
3194
3161
|
}
|
|
3195
3162
|
});
|
|
3196
|
-
if (historyOmitted) return
|
|
3197
|
-
threadStarterBody,
|
|
3198
|
-
threadHistoryBody,
|
|
3199
|
-
shouldSeedInitialThreadContext,
|
|
3200
|
-
threadLabel,
|
|
3201
|
-
threadStarterMedia
|
|
3202
|
-
};
|
|
3163
|
+
if (historyOmitted) return readThreadContextData();
|
|
3203
3164
|
const enrichedStarter = starter && threadStarterBody && threadStarterBody !== starter.text ? {
|
|
3204
3165
|
...starter,
|
|
3205
3166
|
text: threadStarterBody,
|
|
3206
3167
|
ts: currentBotRootTs
|
|
3207
3168
|
} : null;
|
|
3208
|
-
const
|
|
3209
|
-
const threadHistoryWithBotRoot = includeBotStarterAsRootContext && starter && !threadHistoryWithEnrichedRoot.some((entry) => entry.ts === currentBotRootTs) ? [{
|
|
3169
|
+
const rootContext = enrichedStarter ?? (includeBotStarterAsRootContext && starter ? {
|
|
3210
3170
|
...starter,
|
|
3211
3171
|
ts: currentBotRootTs
|
|
3212
|
-
}
|
|
3213
|
-
|
|
3172
|
+
} : null);
|
|
3173
|
+
const threadHistoryWithRoot = rootContext && !threadHistory.some((entry) => entry.ts === currentBotRootTs) ? [rootContext, ...enrichedStarter && threadHistory.length >= threadInitialHistoryLimit ? threadHistory.slice(1) : threadHistory] : threadHistory;
|
|
3174
|
+
if (threadHistoryWithRoot.length > 0) {
|
|
3214
3175
|
const retainCurrentBotHistory = params.isGroupDm && (isMissingThreadSession || isOutboundOnlyThreadSession);
|
|
3215
|
-
const threadHistoryWithoutCurrentBot =
|
|
3216
|
-
const omittedCurrentBotHistoryCount =
|
|
3217
|
-
const userMapForFilter = params.contextVisibilityMode !== "all" && params.allowNameMatching && params.allowFromLower.length > 0 ? await resolveThreadUserMap(threadHistoryWithoutCurrentBot) :
|
|
3176
|
+
const threadHistoryWithoutCurrentBot = threadHistoryWithRoot.filter((entry) => !isCurrentBotAuthor(entry) || retainCurrentBotHistory || includeBotStarterAsRootContext && entry.ts === currentBotRootTs);
|
|
3177
|
+
const omittedCurrentBotHistoryCount = threadHistoryWithRoot.length - threadHistoryWithoutCurrentBot.length;
|
|
3178
|
+
const userMapForFilter = params.contextVisibilityMode !== "all" && params.allowNameMatching && params.allowFromLower.length > 0 ? await resolveThreadUserMap(threadHistoryWithoutCurrentBot) : void 0;
|
|
3218
3179
|
params.assertHistoryCurrent?.();
|
|
3219
3180
|
const { items: filteredThreadHistory, omitted: omittedHistoryCount } = params.contextVisibilityMode === "all" ? {
|
|
3220
3181
|
items: threadHistoryWithoutCurrentBot,
|
|
@@ -3225,7 +3186,7 @@ async function resolveSlackThreadContextData(params) {
|
|
|
3225
3186
|
kind: "thread",
|
|
3226
3187
|
isSenderAllowed: (historyMsg) => {
|
|
3227
3188
|
if (isCurrentBotAuthor(historyMsg)) return true;
|
|
3228
|
-
const msgUser = historyMsg.userId ? userMapForFilter
|
|
3189
|
+
const msgUser = historyMsg.userId ? userMapForFilter?.get(historyMsg.userId) : null;
|
|
3229
3190
|
return resolveSlackUserAllowed({
|
|
3230
3191
|
allowList: params.allowFromLower,
|
|
3231
3192
|
teamId: params.eventScope?.teamId ?? params.ctx.teamId,
|
|
@@ -3235,7 +3196,7 @@ async function resolveSlackThreadContextData(params) {
|
|
|
3235
3196
|
});
|
|
3236
3197
|
}
|
|
3237
3198
|
});
|
|
3238
|
-
const userMap = await resolveThreadUserMap(filteredThreadHistory);
|
|
3199
|
+
const userMap = userMapForFilter ?? await resolveThreadUserMap(filteredThreadHistory);
|
|
3239
3200
|
params.assertHistoryCurrent?.();
|
|
3240
3201
|
if (omittedHistoryCount > 0 || omittedCurrentBotHistoryCount > 0) logVerbose(`slack: omitted ${omittedHistoryCount + omittedCurrentBotHistoryCount} thread message(s) from context (mode=${params.contextVisibilityMode})`);
|
|
3241
3202
|
const historyParts = [];
|
|
@@ -3254,19 +3215,10 @@ async function resolveSlackThreadContextData(params) {
|
|
|
3254
3215
|
envelope: params.envelopeOptions
|
|
3255
3216
|
}));
|
|
3256
3217
|
}
|
|
3257
|
-
if (historyParts.length > 0)
|
|
3258
|
-
threadHistoryBody = historyParts.join("\n\n");
|
|
3259
|
-
logVerbose(`slack: populated thread history with ${filteredThreadHistory.length} messages for new session`);
|
|
3260
|
-
}
|
|
3218
|
+
if (historyParts.length > 0) threadHistoryBody = historyParts.join("\n\n");
|
|
3261
3219
|
}
|
|
3262
3220
|
}
|
|
3263
|
-
return
|
|
3264
|
-
threadStarterBody,
|
|
3265
|
-
threadHistoryBody,
|
|
3266
|
-
shouldSeedInitialThreadContext,
|
|
3267
|
-
threadLabel,
|
|
3268
|
-
threadStarterMedia
|
|
3269
|
-
};
|
|
3221
|
+
return readThreadContextData();
|
|
3270
3222
|
}
|
|
3271
3223
|
// src/channels/mention-gating.ts
|
|
3272
3224
|
function resolveBotThreadMentionPolicy(params) {
|
|
@@ -3333,53 +3285,46 @@ function collectSlackMentionIds(text, regex) {
|
|
|
3333
3285
|
}
|
|
3334
3286
|
return [...ids];
|
|
3335
3287
|
}
|
|
3336
|
-
async function readSlackSubteamUsers(params) {
|
|
3337
|
-
let bySubteam = subteamMemberCache.get(params.client);
|
|
3338
|
-
if (!bySubteam) {
|
|
3339
|
-
bySubteam = /* @__PURE__ */ new Map();
|
|
3340
|
-
subteamMemberCache.set(params.client, bySubteam);
|
|
3341
|
-
}
|
|
3342
|
-
const cacheKey = `${normalizeSlackId(params.teamId) ?? ""}:${params.subteamId}`;
|
|
3343
|
-
const cached = bySubteam.get(cacheKey);
|
|
3344
|
-
const now = asDateTimestampMs(params.now);
|
|
3345
|
-
if (cached) {
|
|
3346
|
-
if (now !== void 0 && asDateTimestampMs(cached.expiresAt) !== void 0 && cached.expiresAt > now) return cached.users;
|
|
3347
|
-
bySubteam.delete(cacheKey);
|
|
3348
|
-
}
|
|
3349
|
-
try {
|
|
3350
|
-
const response = await params.client.usergroups.users.list({
|
|
3351
|
-
usergroup: params.subteamId,
|
|
3352
|
-
...params.teamId ? { team_id: params.teamId } : {}
|
|
3353
|
-
});
|
|
3354
|
-
if (!response.ok) {
|
|
3355
|
-
params.log?.(`slack: failed to resolve user-group mention ${params.subteamId}: ${response.error ?? "unknown_error"}`);
|
|
3356
|
-
return /* @__PURE__ */ new Set();
|
|
3357
|
-
}
|
|
3358
|
-
const users = new Set((response.users ?? []).map(normalizeSlackId).filter((userId) => userId !== void 0));
|
|
3359
|
-
const expiresAt = resolveExpiresAtMsFromDurationMs(SUBTEAM_MEMBER_CACHE_TTL_MS, { nowMs: params.now });
|
|
3360
|
-
if (expiresAt !== void 0) bySubteam.set(cacheKey, {
|
|
3361
|
-
expiresAt,
|
|
3362
|
-
users
|
|
3363
|
-
});
|
|
3364
|
-
return users;
|
|
3365
|
-
} catch (err) {
|
|
3366
|
-
params.log?.(`slack: failed to resolve user-group mention ${params.subteamId}: ${formatErrorMessage(err)}`);
|
|
3367
|
-
return /* @__PURE__ */ new Set();
|
|
3368
|
-
}
|
|
3369
|
-
}
|
|
3370
3288
|
async function isSlackSubteamMentionForBot(params) {
|
|
3371
3289
|
const botUserId = normalizeSlackId(params.botUserId);
|
|
3372
3290
|
if (!botUserId) return false;
|
|
3373
3291
|
const subteamIds = collectSlackMentionIds(params.text, SUBTEAM_MENTION_RE);
|
|
3374
3292
|
if (subteamIds.length === 0) return false;
|
|
3375
|
-
const now =
|
|
3376
|
-
for (const subteamId of subteamIds)
|
|
3377
|
-
client
|
|
3378
|
-
|
|
3379
|
-
|
|
3380
|
-
|
|
3381
|
-
|
|
3382
|
-
|
|
3293
|
+
const now = Date.now();
|
|
3294
|
+
for (const subteamId of subteamIds) {
|
|
3295
|
+
const { client, log } = params;
|
|
3296
|
+
const teamId = normalizeOptionalString(params.teamId);
|
|
3297
|
+
const bySubteam = getOrCreateWeakOwnerMap(subteamMemberCache, client);
|
|
3298
|
+
const cacheKey = `${normalizeSlackId(teamId) ?? ""}:${subteamId}`;
|
|
3299
|
+
const cached = bySubteam.get(cacheKey);
|
|
3300
|
+
if (cached) {
|
|
3301
|
+
if (cached.expiresAt > now) {
|
|
3302
|
+
if (cached.users.has(botUserId)) return true;
|
|
3303
|
+
continue;
|
|
3304
|
+
}
|
|
3305
|
+
bySubteam.delete(cacheKey);
|
|
3306
|
+
}
|
|
3307
|
+
let users;
|
|
3308
|
+
try {
|
|
3309
|
+
const response = await client.usergroups.users.list({
|
|
3310
|
+
usergroup: subteamId,
|
|
3311
|
+
...teamId ? { team_id: teamId } : {}
|
|
3312
|
+
});
|
|
3313
|
+
if (!response.ok) {
|
|
3314
|
+
log?.(`slack: failed to resolve user-group mention ${subteamId}: ${response.error ?? "unknown_error"}`);
|
|
3315
|
+
continue;
|
|
3316
|
+
}
|
|
3317
|
+
users = new Set((response.users ?? []).map(normalizeSlackId).filter((userId) => userId !== void 0));
|
|
3318
|
+
bySubteam.set(cacheKey, {
|
|
3319
|
+
expiresAt: now + SUBTEAM_MEMBER_CACHE_TTL_MS,
|
|
3320
|
+
users
|
|
3321
|
+
});
|
|
3322
|
+
} catch (err) {
|
|
3323
|
+
log?.(`slack: failed to resolve user-group mention ${subteamId}: ${formatErrorMessage(err)}`);
|
|
3324
|
+
continue;
|
|
3325
|
+
}
|
|
3326
|
+
if (users.has(botUserId)) return true;
|
|
3327
|
+
}
|
|
3383
3328
|
return false;
|
|
3384
3329
|
}
|
|
3385
3330
|
// extensions/slack/src/monitor/message-handler/prepare.ts
|
|
@@ -3389,18 +3334,6 @@ const SLACK_USER_MENTION_RE = /<@([^>|]+)(?:\|[^>]+)?>/g;
|
|
|
3389
3334
|
const SLACK_SUBTEAM_MENTION_RE = /<!subteam\^([^>|]+)(?:\|[^>]+)?>/g;
|
|
3390
3335
|
const SLACK_SUBTEAM_MENTION_MARKER = "<!subteam^";
|
|
3391
3336
|
const SLACK_CHANNEL_ACCESS_DOCS_URL = "https://docs.openclaw.ai/channels/slack#access-control-and-routing";
|
|
3392
|
-
function mergeSlackAssistantThreadContext(primary, fallback) {
|
|
3393
|
-
if (!primary) return fallback;
|
|
3394
|
-
if (!fallback) return primary;
|
|
3395
|
-
return {
|
|
3396
|
-
assistantChannelId: primary.assistantChannelId || fallback.assistantChannelId,
|
|
3397
|
-
threadTs: primary.threadTs || fallback.threadTs,
|
|
3398
|
-
userId: primary.userId ?? fallback.userId,
|
|
3399
|
-
channelId: primary.channelId ?? fallback.channelId,
|
|
3400
|
-
teamId: primary.teamId ?? fallback.teamId,
|
|
3401
|
-
enterpriseId: primary.enterpriseId !== void 0 ? primary.enterpriseId : fallback.enterpriseId
|
|
3402
|
-
};
|
|
3403
|
-
}
|
|
3404
3337
|
function hasSlackAssistantThreadMetadata(context) {
|
|
3405
3338
|
return Boolean(context?.channelId || context?.teamId || context?.enterpriseId !== void 0);
|
|
3406
3339
|
}
|
|
@@ -3414,7 +3347,6 @@ function resolveSlackMessageAssistantThreadContext(message) {
|
|
|
3414
3347
|
return {
|
|
3415
3348
|
assistantChannelId,
|
|
3416
3349
|
threadTs,
|
|
3417
|
-
userId: normalizeOptionalString(thread.user_id) ?? message.user,
|
|
3418
3350
|
channelId: normalizeOptionalString(context?.channel_id),
|
|
3419
3351
|
teamId: normalizeOptionalString(context?.team_id),
|
|
3420
3352
|
enterpriseId: context?.enterprise_id === null ? null : normalizeOptionalString(context?.enterprise_id)
|
|
@@ -3428,8 +3360,7 @@ async function restoreSlackAssistantThreadContextFromMetadata(params) {
|
|
|
3428
3360
|
return await readSlackAssistantThreadContext({
|
|
3429
3361
|
client: params.eventScope?.client ?? params.ctx.app.client,
|
|
3430
3362
|
channelId: params.message.channel,
|
|
3431
|
-
threadTs
|
|
3432
|
-
userId: params.message.user
|
|
3363
|
+
threadTs
|
|
3433
3364
|
});
|
|
3434
3365
|
} catch (err) {
|
|
3435
3366
|
logVerbose(`slack assistant context restore failed channel=${params.message.channel} ts=${threadTs}: ${formatErrorMessage(err)}`);
|
|
@@ -3442,41 +3373,40 @@ function resolveCachedMentionRegexes(ctx, agentId, options) {
|
|
|
3442
3373
|
normalizeOptionalString(options?.conversationId ?? void 0),
|
|
3443
3374
|
options?.providerPolicy ? JSON.stringify(options.providerPolicy) : ""
|
|
3444
3375
|
].join("");
|
|
3445
|
-
|
|
3446
|
-
if (!byAgent) {
|
|
3447
|
-
byAgent = /* @__PURE__ */ new Map();
|
|
3448
|
-
mentionRegexCache.set(ctx, byAgent);
|
|
3449
|
-
}
|
|
3376
|
+
const byAgent = getOrCreateWeakOwnerMap(mentionRegexCache, ctx);
|
|
3450
3377
|
const cached = byAgent.get(key);
|
|
3451
3378
|
if (cached) return cached;
|
|
3452
3379
|
const built = buildMentionRegexes(ctx.cfg, agentId, options);
|
|
3453
3380
|
byAgent.set(key, built);
|
|
3454
3381
|
return built;
|
|
3455
3382
|
}
|
|
3456
|
-
function
|
|
3457
|
-
|
|
3458
|
-
|
|
3459
|
-
|
|
3460
|
-
|
|
3461
|
-
|
|
3383
|
+
async function prepareSlackMessage(params) {
|
|
3384
|
+
const { ctx, account, message, opts } = params;
|
|
3385
|
+
const drop = (reason, parentUserId) => {
|
|
3386
|
+
ctx.logger.info({
|
|
3387
|
+
provider: "slack",
|
|
3388
|
+
accountId: account.accountId,
|
|
3389
|
+
teamId: opts.eventScope?.teamId ?? ctx.teamId,
|
|
3390
|
+
channelId: message.channel,
|
|
3391
|
+
messageTs: message.ts,
|
|
3392
|
+
source: opts.source,
|
|
3393
|
+
reason,
|
|
3394
|
+
...parentUserId ? { parentUserId } : {}
|
|
3395
|
+
}, "Slack inbound event rejected during preparation");
|
|
3396
|
+
return null;
|
|
3397
|
+
};
|
|
3398
|
+
const slackClient = opts.eventScope?.client ?? ctx.app.client;
|
|
3399
|
+
const threadStarterWorkspaceScope = {
|
|
3400
|
+
accountId: account.accountId,
|
|
3401
|
+
teamId: opts.eventScope?.teamId ?? ctx.teamId
|
|
3462
3402
|
};
|
|
3463
|
-
}
|
|
3464
|
-
function resolveSlackMentionSource(params) {
|
|
3465
|
-
if (params.explicitBotMention) return "explicit_bot";
|
|
3466
|
-
if (params.explicitSubteamMention) return "subteam";
|
|
3467
|
-
if (params.shouldBypassMention) return "command_bypass";
|
|
3468
|
-
if (params.wasMentioned) return "mention_pattern";
|
|
3469
|
-
if (params.matchedImplicitMentionKinds.length > 0) return "implicit_thread";
|
|
3470
|
-
return "none";
|
|
3471
|
-
}
|
|
3472
|
-
async function resolveSlackConversationContext(params) {
|
|
3473
|
-
const { ctx, account, message } = params;
|
|
3474
3403
|
const cfg = ctx.cfg;
|
|
3404
|
+
const conversationEventScope = opts.eventScope;
|
|
3475
3405
|
let channelInfo = {};
|
|
3476
3406
|
let resolvedChannelType = normalizeSlackChannelType(message.channel_type, message.channel);
|
|
3477
3407
|
if (resolvedChannelType !== "im" && message.channel_type !== "im") {
|
|
3478
|
-
channelInfo = await ctx.resolveChannelName(message.channel,
|
|
3479
|
-
resolvedChannelType = normalizeSlackChannelType(message.channel_type ?? channelInfo.type ?? ctx.recallSlackChannelType(message.channel,
|
|
3408
|
+
channelInfo = await ctx.resolveChannelName(message.channel, conversationEventScope);
|
|
3409
|
+
resolvedChannelType = normalizeSlackChannelType(message.channel_type ?? channelInfo.type ?? ctx.recallSlackChannelType(message.channel, conversationEventScope), message.channel);
|
|
3480
3410
|
}
|
|
3481
3411
|
const channelName = channelInfo.name;
|
|
3482
3412
|
const isDirectMessage = resolvedChannelType === "im";
|
|
@@ -3484,7 +3414,7 @@ async function resolveSlackConversationContext(params) {
|
|
|
3484
3414
|
const isRoom = resolvedChannelType === "channel" || resolvedChannelType === "group";
|
|
3485
3415
|
const isRoomish = isRoom || isGroupDm;
|
|
3486
3416
|
const channelConfig = isRoom ? resolveSlackChannelConfig({
|
|
3487
|
-
teamId:
|
|
3417
|
+
teamId: conversationEventScope?.teamId ?? ctx.teamId,
|
|
3488
3418
|
allowUnscoped: ctx.installationIdentity?.kind !== "enterprise",
|
|
3489
3419
|
channelId: message.channel,
|
|
3490
3420
|
channelName,
|
|
@@ -3494,22 +3424,19 @@ async function resolveSlackConversationContext(params) {
|
|
|
3494
3424
|
allowNameMatching: ctx.allowNameMatching
|
|
3495
3425
|
}) : null;
|
|
3496
3426
|
const allowBotsSetting = channelConfig?.allowBots ?? account.config?.allowBots ?? cfg.channels?.slack?.allowBots ?? true;
|
|
3497
|
-
|
|
3498
|
-
|
|
3499
|
-
|
|
3500
|
-
|
|
3501
|
-
|
|
3502
|
-
|
|
3503
|
-
|
|
3504
|
-
|
|
3505
|
-
channelConfig,
|
|
3506
|
-
allowBotsMode: allowBotsSetting === "mentions" ? "mentions" : allowBotsSetting ? "all" : "off",
|
|
3507
|
-
isBotMessage: Boolean(message.bot_id)
|
|
3427
|
+
const allowBotsMode = allowBotsSetting === "mentions" ? "mentions" : allowBotsSetting ? "all" : "off";
|
|
3428
|
+
const isBotMessage = Boolean(message.bot_id);
|
|
3429
|
+
const messageText = message.text ?? "";
|
|
3430
|
+
const mentionMetadata = {
|
|
3431
|
+
mentionedUserIds: collectSlackMentionIds(messageText, SLACK_USER_MENTION_RE),
|
|
3432
|
+
mentionedSubteamIds: collectSlackMentionIds(messageText, SLACK_SUBTEAM_MENTION_RE),
|
|
3433
|
+
hasAnyMention: SLACK_ANY_MENTION_RE.test(messageText),
|
|
3434
|
+
hasSubteamMention: messageText.includes(SLACK_SUBTEAM_MENTION_MARKER)
|
|
3508
3435
|
};
|
|
3509
|
-
|
|
3510
|
-
|
|
3511
|
-
const
|
|
3512
|
-
const
|
|
3436
|
+
const normalizedBotUserId = normalizeSlackId(ctx.botUserId);
|
|
3437
|
+
const explicitBotMention = opts.source === "app_mention" || Boolean(normalizedBotUserId && mentionMetadata.mentionedUserIds.includes(normalizedBotUserId));
|
|
3438
|
+
const authorizationEventScope = opts.eventScope;
|
|
3439
|
+
const onVisibleDrop = opts.onVisibleDrop;
|
|
3513
3440
|
if (isBotMessage) {
|
|
3514
3441
|
if (ctx.botUserId && message.user === ctx.botUserId || ctx.botId && message.bot_id === ctx.botId) return null;
|
|
3515
3442
|
if (allowBotsMode === "off") return drop("bot-disabled");
|
|
@@ -3518,28 +3445,28 @@ async function authorizeSlackInboundMessage(params) {
|
|
|
3518
3445
|
const senderId = message.user ?? (isBotMessage ? message.bot_id : void 0);
|
|
3519
3446
|
if (!senderId) return drop("missing-sender");
|
|
3520
3447
|
if (!ctx.isChannelAllowed({
|
|
3521
|
-
teamId:
|
|
3448
|
+
teamId: authorizationEventScope?.teamId ?? ctx.teamId,
|
|
3522
3449
|
channelId: message.channel,
|
|
3523
3450
|
channelName,
|
|
3524
3451
|
channelType: resolvedChannelType
|
|
3525
3452
|
})) {
|
|
3526
|
-
if (
|
|
3453
|
+
if (isRoom && ctx.groupPolicy === "allowlist" && explicitBotMention && !isBotMessage && message.user) {
|
|
3527
3454
|
let subject = "This OpenClaw bot";
|
|
3528
3455
|
if (ctx.botUserId) try {
|
|
3529
|
-
const botIdentity = await ctx.resolveUserName(ctx.botUserId,
|
|
3456
|
+
const botIdentity = await ctx.resolveUserName(ctx.botUserId, authorizationEventScope);
|
|
3530
3457
|
const botName = normalizeOptionalString(botIdentity?.name);
|
|
3531
3458
|
if (botName) subject = escapeSlackMrkdwn(botName);
|
|
3532
3459
|
} catch (error) {
|
|
3533
3460
|
logVerbose(`slack allowlist denial bot-name lookup failed: ${formatSlackError(error)}`);
|
|
3534
3461
|
}
|
|
3535
3462
|
try {
|
|
3536
|
-
await (
|
|
3463
|
+
await (authorizationEventScope?.client ?? ctx.app.client).chat.postEphemeral({
|
|
3537
3464
|
token: ctx.botToken,
|
|
3538
3465
|
channel: message.channel,
|
|
3539
3466
|
user: message.user,
|
|
3540
3467
|
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.>`
|
|
3541
3468
|
});
|
|
3542
|
-
|
|
3469
|
+
onVisibleDrop?.();
|
|
3543
3470
|
} catch (error) {
|
|
3544
3471
|
ctx.runtime.error?.(`slack allowlist denial notice failed for channel ${message.channel}: ${formatSlackError(error)}`);
|
|
3545
3472
|
}
|
|
@@ -3548,7 +3475,7 @@ async function authorizeSlackInboundMessage(params) {
|
|
|
3548
3475
|
}
|
|
3549
3476
|
const allowFromLower = await resolveSlackEffectiveAllowFrom(ctx, {
|
|
3550
3477
|
includePairingStore: isDirectMessage,
|
|
3551
|
-
eventScope:
|
|
3478
|
+
eventScope: authorizationEventScope
|
|
3552
3479
|
});
|
|
3553
3480
|
if (isDirectMessage) {
|
|
3554
3481
|
const directUserId = message.user;
|
|
@@ -3558,16 +3485,16 @@ async function authorizeSlackInboundMessage(params) {
|
|
|
3558
3485
|
ctx,
|
|
3559
3486
|
accountId: account.accountId,
|
|
3560
3487
|
senderId: directUserId,
|
|
3561
|
-
eventScope:
|
|
3488
|
+
eventScope: authorizationEventScope,
|
|
3562
3489
|
allowFromLower,
|
|
3563
|
-
resolveSenderName: (userId) => ctx.resolveUserName(userId,
|
|
3490
|
+
resolveSenderName: (userId) => ctx.resolveUserName(userId, authorizationEventScope),
|
|
3564
3491
|
sendPairingReply: async (text) => {
|
|
3565
3492
|
await sendMessageSlack(message.channel, text, {
|
|
3566
3493
|
cfg: ctx.cfg,
|
|
3567
3494
|
token: ctx.botToken,
|
|
3568
|
-
client:
|
|
3495
|
+
client: authorizationEventScope?.client ?? ctx.app.client,
|
|
3569
3496
|
accountId: account.accountId,
|
|
3570
|
-
eventScope:
|
|
3497
|
+
eventScope: authorizationEventScope
|
|
3571
3498
|
});
|
|
3572
3499
|
},
|
|
3573
3500
|
onDisabled: () => {
|
|
@@ -3579,54 +3506,6 @@ async function authorizeSlackInboundMessage(params) {
|
|
|
3579
3506
|
log: logVerbose
|
|
3580
3507
|
})) return drop(dropReason);
|
|
3581
3508
|
}
|
|
3582
|
-
return {
|
|
3583
|
-
senderId,
|
|
3584
|
-
allowFromLower
|
|
3585
|
-
};
|
|
3586
|
-
}
|
|
3587
|
-
async function prepareSlackMessage(params) {
|
|
3588
|
-
const { ctx, account, message, opts } = params;
|
|
3589
|
-
const drop = (reason, parentUserId) => {
|
|
3590
|
-
ctx.logger.info({
|
|
3591
|
-
provider: "slack",
|
|
3592
|
-
accountId: account.accountId,
|
|
3593
|
-
teamId: opts.eventScope?.teamId ?? ctx.teamId,
|
|
3594
|
-
channelId: message.channel,
|
|
3595
|
-
messageTs: message.ts,
|
|
3596
|
-
source: opts.source,
|
|
3597
|
-
reason,
|
|
3598
|
-
...parentUserId ? { parentUserId } : {}
|
|
3599
|
-
}, "Slack inbound event rejected during preparation");
|
|
3600
|
-
return null;
|
|
3601
|
-
};
|
|
3602
|
-
const slackClient = opts.eventScope?.client ?? ctx.app.client;
|
|
3603
|
-
const threadStarterWorkspaceScope = {
|
|
3604
|
-
accountId: account.accountId,
|
|
3605
|
-
teamId: opts.eventScope?.teamId ?? ctx.teamId
|
|
3606
|
-
};
|
|
3607
|
-
const cfg = ctx.cfg;
|
|
3608
|
-
const conversation = await resolveSlackConversationContext({
|
|
3609
|
-
ctx,
|
|
3610
|
-
account,
|
|
3611
|
-
message,
|
|
3612
|
-
eventScope: opts.eventScope
|
|
3613
|
-
});
|
|
3614
|
-
const { channelInfo, channelName, isDirectMessage, isGroupDm, isRoom, isRoomish, channelConfig, allowBotsMode, isBotMessage } = conversation;
|
|
3615
|
-
const messageText = message.text ?? "";
|
|
3616
|
-
const mentionMetadata = collectSlackMentionMetadata(messageText);
|
|
3617
|
-
const normalizedBotUserId = normalizeSlackId(ctx.botUserId);
|
|
3618
|
-
const authorization = await authorizeSlackInboundMessage({
|
|
3619
|
-
ctx,
|
|
3620
|
-
account,
|
|
3621
|
-
message,
|
|
3622
|
-
conversation,
|
|
3623
|
-
explicitBotMention: opts.source === "app_mention" || Boolean(normalizedBotUserId && mentionMetadata.mentionedUserIds.includes(normalizedBotUserId)),
|
|
3624
|
-
eventScope: opts.eventScope,
|
|
3625
|
-
onVisibleDrop: opts.onVisibleDrop,
|
|
3626
|
-
drop
|
|
3627
|
-
});
|
|
3628
|
-
if (!authorization) return null;
|
|
3629
|
-
const { senderId, allowFromLower } = authorization;
|
|
3630
3509
|
let resolvedSenderName = normalizeOptionalString(message.username);
|
|
3631
3510
|
const resolveSenderName = async () => {
|
|
3632
3511
|
if (resolvedSenderName) return resolvedSenderName;
|
|
@@ -3662,9 +3541,17 @@ async function prepareSlackMessage(params) {
|
|
|
3662
3541
|
});
|
|
3663
3542
|
const explicitlyMentioned = explicitlyMentionedBotUser || explicitlyMentionedBotSubteam || opts.source === "app_mention";
|
|
3664
3543
|
const channelRequireMention = channelConfig?.requireMention ?? ctx.defaultRequireMention ?? true;
|
|
3665
|
-
const chatType = resolveSlackChatType(
|
|
3544
|
+
const chatType = resolveSlackChatType(resolvedChannelType);
|
|
3666
3545
|
const restoredAssistantThreadContext = await restoredAssistantThreadContextPromise;
|
|
3667
|
-
const
|
|
3546
|
+
const primary = messageAssistantThreadContext;
|
|
3547
|
+
const fallback = cachedAssistantThreadContext ?? restoredAssistantThreadContext;
|
|
3548
|
+
const assistantThreadContext = !primary ? fallback : !fallback ? primary : {
|
|
3549
|
+
assistantChannelId: primary.assistantChannelId || fallback.assistantChannelId,
|
|
3550
|
+
threadTs: primary.threadTs || fallback.threadTs,
|
|
3551
|
+
channelId: primary.channelId ?? fallback.channelId,
|
|
3552
|
+
teamId: primary.teamId ?? fallback.teamId,
|
|
3553
|
+
enterpriseId: primary.enterpriseId !== void 0 ? primary.enterpriseId : fallback.enterpriseId
|
|
3554
|
+
};
|
|
3668
3555
|
const assistantThreadContextToCache = messageAssistantThreadContext || restoredAssistantThreadContext ? assistantThreadContext : void 0;
|
|
3669
3556
|
if (assistantThreadContextToCache) ctx.saveSlackAssistantThreadContext(assistantThreadContextToCache, opts.eventScope);
|
|
3670
3557
|
const canUseManagedView = isDirectMessage && !opts.eventScope && !assistantThreadContext;
|
|
@@ -3728,19 +3615,16 @@ async function prepareSlackMessage(params) {
|
|
|
3728
3615
|
let mentionRegexes = buildPolicyMentionRegexes(routing.route.agentId);
|
|
3729
3616
|
let wasMentioned = resolveWasMentioned(mentionRegexes);
|
|
3730
3617
|
const hasBoundSession = Boolean(routing.runtimeBoundSessionKey || routing.configuredBindingSessionKey);
|
|
3731
|
-
const { configuredBinding
|
|
3618
|
+
const { configuredBinding } = routing;
|
|
3732
3619
|
const isAssistantThreadMessage = Boolean(isDirectMessage && messageAssistantThreadContext);
|
|
3733
3620
|
const forcedAssistantReplyThreadTs = Boolean(assistantThreadContext?.threadTs && (routing.isThreadReply || isAssistantThreadMessage || routing.replyToMode !== "off")) ? assistantThreadContext?.threadTs : void 0;
|
|
3734
3621
|
const forcedReplyThreadTs = agentViewThreadTs ?? forcedAssistantReplyThreadTs;
|
|
3735
|
-
if (routing.runtimeBinding && shouldLogVerbose()) logVerbose(`slack: routed via bound conversation ${routing.runtimeBinding.conversation.conversationId} -> ${routing.runtimeBinding.targetSessionKey}`);
|
|
3736
3622
|
if (configuredBinding) {
|
|
3737
3623
|
const ensured = await ensureConfiguredBindingRouteReady({
|
|
3738
3624
|
cfg,
|
|
3739
3625
|
bindingResolution: configuredBinding
|
|
3740
3626
|
});
|
|
3741
|
-
if (ensured.ok) {
|
|
3742
|
-
if (shouldLogVerbose()) logVerbose(`slack: using configured ACP binding for ${configuredBinding.record.conversation.conversationId} -> ${configuredBindingSessionKey}`);
|
|
3743
|
-
} else {
|
|
3627
|
+
if (!ensured.ok) {
|
|
3744
3628
|
if (shouldLogVerbose()) logVerbose(`slack: configured ACP binding unavailable for ${configuredBinding.record.conversation.conversationId}: ${ensured.error}`);
|
|
3745
3629
|
return drop("configured-binding-unavailable");
|
|
3746
3630
|
}
|
|
@@ -3778,7 +3662,11 @@ async function prepareSlackMessage(params) {
|
|
|
3778
3662
|
ctx,
|
|
3779
3663
|
account,
|
|
3780
3664
|
message,
|
|
3781
|
-
conversation
|
|
3665
|
+
conversation: {
|
|
3666
|
+
isRoom,
|
|
3667
|
+
isDirectMessage,
|
|
3668
|
+
channelConfig
|
|
3669
|
+
},
|
|
3782
3670
|
thread: routing,
|
|
3783
3671
|
wasMentioned,
|
|
3784
3672
|
teamId: opts.eventScope?.teamId,
|
|
@@ -3796,14 +3684,14 @@ async function prepareSlackMessage(params) {
|
|
|
3796
3684
|
const textForCommandDetection = stripSlackMentionsForCommandDetection(message.text ?? "");
|
|
3797
3685
|
const hasControlCommandInMessage = hasControlCommand(textForCommandDetection, cfg);
|
|
3798
3686
|
const hasAbortRequest = isAbortRequestText(textForCommandDetection);
|
|
3799
|
-
const channelUsersAllowlistConfigured = isRoom &&
|
|
3687
|
+
const channelUsersAllowlistConfigured = isRoom && (channelConfig?.users?.length ?? 0) > 0;
|
|
3800
3688
|
const resolveMessageIngress = async (contextBinding, threadId) => await resolveSlackCommandIngress({
|
|
3801
3689
|
ctx,
|
|
3802
3690
|
teamId: opts.eventScope?.teamId ?? ctx.teamId,
|
|
3803
3691
|
senderId,
|
|
3804
3692
|
senderAuthentication: message.user ? opts.senderAuthentication : void 0,
|
|
3805
3693
|
senderName: senderNameForAuth,
|
|
3806
|
-
channelType:
|
|
3694
|
+
channelType: resolvedChannelType ?? "channel",
|
|
3807
3695
|
channelId: message.channel,
|
|
3808
3696
|
threadId,
|
|
3809
3697
|
ownerAllowFromLower: allowFromLower,
|
|
@@ -3938,13 +3826,7 @@ async function prepareSlackMessage(params) {
|
|
|
3938
3826
|
const effectiveWasMentioned = mentionDecision.effectiveWasMentioned;
|
|
3939
3827
|
const shouldBypassMention = mentionDecision.shouldBypassMention;
|
|
3940
3828
|
const matchedImplicitMentionKinds = mentionDecision.matchedImplicitMentionKinds;
|
|
3941
|
-
const mentionSource =
|
|
3942
|
-
explicitBotMention: explicitlyMentionedBotUser || opts.source === "app_mention",
|
|
3943
|
-
explicitSubteamMention: explicitlyMentionedBotSubteam,
|
|
3944
|
-
matchedImplicitMentionKinds,
|
|
3945
|
-
shouldBypassMention,
|
|
3946
|
-
wasMentioned
|
|
3947
|
-
});
|
|
3829
|
+
const mentionSource = explicitlyMentionedBotUser || opts.source === "app_mention" ? "explicit_bot" : explicitlyMentionedBotSubteam ? "subteam" : shouldBypassMention ? "command_bypass" : wasMentioned ? "mention_pattern" : matchedImplicitMentionKinds.length > 0 ? "implicit_thread" : "none";
|
|
3948
3830
|
if (isBotMessage && allowBotsMode === "mentions") {
|
|
3949
3831
|
if (!(isDirectMessage || effectiveWasMentioned || shouldBypassMention)) return drop("bot-missing-mention");
|
|
3950
3832
|
}
|
|
@@ -4275,7 +4157,6 @@ async function prepareSlackMessage(params) {
|
|
|
4275
4157
|
originatingTo: preflightChannelTarget,
|
|
4276
4158
|
messageThreadId: threadContext.messageThreadId
|
|
4277
4159
|
});
|
|
4278
|
-
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}`);
|
|
4279
4160
|
const updateLastRouteSessionKey = resolveInboundLastRouteSessionKey({
|
|
4280
4161
|
route,
|
|
4281
4162
|
sessionKey
|