@openclaw/slack 2026.10.10-beta.5 → 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-configured-zcR9TJJN.mjs → account-configured-35y0-Hso.mjs} +1 -2
- package/dist/.setup/{account-inspect-CmkKiSb9.mjs → account-inspect-DgQgj0wk.mjs} +13 -11
- package/dist/.setup/{accounts-msihSF3-.mjs → accounts-EaPP0fFY.mjs} +16 -11
- package/dist/.setup/{action-runtime-ChRfnnBu.mjs → action-runtime-CK9QZgQl.mjs} +39 -47
- package/dist/.setup/action-runtime.runtime-CpZktret.mjs +1 -0
- package/dist/.setup/{actions-By7tvpvv.mjs → actions-s3CcFO45.mjs} +98 -93
- package/dist/.setup/{approval-handler.runtime-D8ArtDQt.mjs → approval-handler.runtime-Ch7BecYK.mjs} +27 -32
- package/dist/.setup/{approval-message-updates-DT7XBPbV.mjs → approval-message-updates-CqcRoa28.mjs} +2 -3
- package/dist/.setup/{channel-6YzXl_63.mjs → channel-CAvo_WNZ.mjs} +573 -352
- package/dist/.setup/{channel-meta-C443t-lI.mjs → channel-meta-C5vsCo3a.mjs} +1 -2
- package/dist/.setup/{channel-type-BEFP2ORi.mjs → channel-type-9Lw6yLf2.mjs} +6 -11
- package/dist/.setup/{channel.setup-u6QQdbTa.mjs → channel.setup-BlgXNuCJ.mjs} +19 -23
- package/dist/.setup/{config-schema-DNnh6bWU.mjs → config-schema-Bx1tCZB0.mjs} +5 -11
- package/dist/.setup/cursor-pages-jVn3Vkfi.mjs +309 -0
- package/dist/.setup/{directory-config-Cjj0N8R0.mjs → directory-config-CGvKYg9F.mjs} +5 -6
- package/dist/.setup/{directory-live-BIKD-5B_.mjs → directory-live-DNdw97LA.mjs} +6 -7
- package/dist/.setup/{doctor-contract-Cd4-VzIM.mjs → doctor-contract-BB2KJ9Ni.mjs} +44 -58
- package/dist/.setup/{message-tool-api-BS5ekEA_.mjs → message-tool-api-B38BpEaE.mjs} +7 -8
- package/dist/.setup/{monitor-BFilOuM_.mjs → monitor-BD86SotB.mjs} +3416 -3750
- package/dist/.setup/{outbound-adapter-9dbnYtL1.mjs → outbound-adapter-BH6iPWBj.mjs} +32 -39
- package/dist/.setup/paths-CQZI_5WY.mjs +7 -0
- package/dist/.setup/{pipeline.runtime-BG5swHnj.mjs → pipeline.runtime-C4ELxaRU.mjs} +444 -590
- package/dist/.setup/{policy-yhn48xf5.mjs → policy-C6_DdlSf.mjs} +3 -6
- package/dist/.setup/{session-status-Dv8wNBEt.mjs → probe-B_Ax1vS1.mjs} +1015 -678
- package/dist/.setup/question-delivery-D3qAIwuv.mjs +38 -0
- package/dist/.setup/{relay-source-oY9SbDiX.mjs → relay-source-a8jodKuO.mjs} +12 -6
- package/dist/.setup/{replies-CJwjTqDr.mjs → replies-Bq7n0gfM.mjs} +37 -24
- package/dist/.setup/{reply-blocks-Ca-raz2z.mjs → reply-blocks-DyYYRrP_.mjs} +202 -210
- package/dist/.setup/{resolve-channels-DRRhElwz.mjs → resolve-channels-CF2JME9q.mjs} +6 -10
- package/dist/.setup/{resolve-users-Cz8e17ky.mjs → resolve-users-DDcCAjH1.mjs} +10 -19
- package/dist/.setup/{rolldown-runtime-B4FMCO8f.mjs → rolldown-runtime-nwUcYXjP.mjs} +1 -2
- package/dist/.setup/{runtime-JSVZSWAj.mjs → runtime-C6HKn7Av.mjs} +1 -2
- package/dist/.setup/runtime-setter-api-DrXr965r.mjs +2 -0
- package/dist/.setup/{scopes-DfQVi8Jw.mjs → scopes-CzHC_dwV.mjs} +3 -3
- package/dist/.setup/{secret-contract-B-Qm6aQQ.mjs → secret-contract-CqVqR7MP.mjs} +5 -4
- package/dist/.setup/{secret-contract-api-DB6CMdgc.mjs → secret-contract-api-DaCXZ47j.mjs} +1 -1
- package/dist/.setup/{security-audit-DFGiFLqd.mjs → security-audit-C3hXCfDt.mjs} +2 -3
- package/dist/.setup/{send-C-8wY0lK.mjs → send-WJZ73VSf.mjs} +306 -349
- package/dist/.setup/{send-results-eeOu_HYm.mjs → send-results-Bm6V1ekL.mjs} +4 -6
- package/dist/.setup/setup-plugin-api-DJXIB8CF.mjs +2 -0
- package/dist/.setup/{setup-surface-9WVQgYCT.mjs → setup-surface-uIqP2B0Y.mjs} +6 -8
- package/dist/.setup/{slash-dispatch.runtime-v5kQqJPh.mjs → slash-dispatch.runtime-Cwuwv7FL.mjs} +2 -2
- package/dist/.setup/{target-parsing-FFE26kOV.mjs → target-parsing-DwYAP3ts.mjs} +2 -4
- package/dist/.setup/{targets-C6LZQL1Q.mjs → targets-eeOxA_b_.mjs} +2 -3
- package/dist/.setup/{thread-ts-Cvt7WD6B.mjs → thread-ts-47Au2-Yn.mjs} +1 -2
- package/dist/.source-module-urls/c5ffd0957b234c7c12090e7de4eca2482ef339b8561e078da55b734211b0ba58.json +1 -0
- package/dist/account-inspect-api.js +2 -3
- package/dist/api.js +17 -18
- package/dist/channel-config-api.js +1 -1
- package/dist/channel-entry.js +1 -2
- package/dist/channel-plugin-api.js +1 -1
- package/dist/configured-state.js +2 -3
- package/dist/directory-contract-api.js +1 -1
- package/dist/doctor-contract-api.js +1 -1
- package/dist/index.js +1 -8
- package/dist/message-tool-api.js +1 -1
- package/dist/runtime-api.js +11 -13
- package/dist/runtime-setter-api.js +1 -1
- package/dist/secret-contract-api.js +1 -1
- package/dist/security-contract-api.js +1 -1
- package/dist/setup-entry.js +4 -5
- 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/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/README.md +25 -3
- package/node_modules/undici/docs/docs/api/CacheStore.md +24 -9
- package/node_modules/undici/docs/docs/api/Client.md +11 -6
- package/node_modules/undici/docs/docs/api/Dispatcher.md +3 -0
- package/node_modules/undici/docs/docs/api/Errors.md +76 -1
- package/node_modules/undici/docs/docs/api/H2CClient.md +3 -2
- package/node_modules/undici/docs/docs/api/Interceptors.md +28 -8
- package/node_modules/undici/docs/docs/api/RedirectHandler.md +13 -10
- package/node_modules/undici/docs/docs/index.md +12 -12
- package/node_modules/undici/docs/docs/type-map.json +66 -66
- package/node_modules/undici/lib/cache/memory-cache-store.js +48 -13
- package/node_modules/undici/lib/cache/sqlite-cache-store.js +83 -5
- package/node_modules/undici/lib/core/connect.js +10 -4
- package/node_modules/undici/lib/core/constants.js +12 -1
- package/node_modules/undici/lib/core/errors.js +38 -1
- package/node_modules/undici/lib/core/request.js +16 -1
- package/node_modules/undici/lib/core/symbols.js +2 -0
- package/node_modules/undici/lib/core/util.js +26 -1
- package/node_modules/undici/lib/dispatcher/agent.js +6 -2
- package/node_modules/undici/lib/dispatcher/client-h1.js +116 -80
- package/node_modules/undici/lib/dispatcher/client-h2.js +124 -17
- package/node_modules/undici/lib/dispatcher/client.js +4 -1
- package/node_modules/undici/lib/dispatcher/dispatcher-base.js +3 -2
- package/node_modules/undici/lib/dispatcher/dispatcher1-wrapper.js +20 -3
- package/node_modules/undici/lib/dispatcher/parser-h1.js +1064 -0
- package/node_modules/undici/lib/dispatcher/pool-base.js +85 -31
- package/node_modules/undici/lib/dispatcher/pool.js +11 -8
- package/node_modules/undici/lib/dispatcher/proxy-agent.js +18 -8
- package/node_modules/undici/lib/dispatcher/retry-agent.js +10 -0
- package/node_modules/undici/lib/dispatcher/round-robin-pool.js +15 -5
- package/node_modules/undici/lib/handler/cache-handler.js +153 -15
- package/node_modules/undici/lib/handler/deduplication-handler.js +112 -51
- package/node_modules/undici/lib/handler/redirect-handler.js +28 -8
- package/node_modules/undici/lib/handler/retry-handler.js +44 -11
- package/node_modules/undici/lib/interceptor/cache.js +11 -3
- package/node_modules/undici/lib/interceptor/decompress.js +22 -9
- package/node_modules/undici/lib/interceptor/dns.js +11 -0
- package/node_modules/undici/lib/interceptor/response-error.js +72 -28
- package/node_modules/undici/lib/milo/LICENSE.md +7 -0
- package/node_modules/undici/lib/milo/no-simd.js +1002 -0
- package/node_modules/undici/lib/milo/simd.js +1002 -0
- package/node_modules/undici/lib/mock/mock-agent.js +11 -0
- package/node_modules/undici/lib/mock/snapshot-recorder.js +3 -2
- package/node_modules/undici/lib/mock/snapshot-utils.js +3 -2
- package/node_modules/undici/lib/util/cache.js +11 -5
- package/node_modules/undici/lib/web/cookies/util.js +19 -2
- package/node_modules/undici/lib/web/eventsource/eventsource-stream.js +69 -15
- package/node_modules/undici/lib/web/eventsource/eventsource.js +25 -2
- package/node_modules/undici/lib/web/fetch/body.js +47 -38
- package/node_modules/undici/lib/web/fetch/formdata-parser.js +12 -4
- package/node_modules/undici/lib/web/fetch/headers.js +2 -2
- package/node_modules/undici/lib/web/fetch/index.js +8 -4
- package/node_modules/undici/lib/web/subresource-integrity/subresource-integrity.js +5 -5
- package/node_modules/undici/lib/web/websocket/receiver.js +25 -4
- package/node_modules/undici/package.json +9 -7
- package/node_modules/undici/types/api.d.ts +1 -1
- package/node_modules/undici/types/cache-interceptor.d.ts +10 -0
- package/node_modules/undici/types/client.d.ts +10 -4
- package/node_modules/undici/types/errors.d.ts +16 -1
- package/node_modules/undici/types/h2c-client.d.ts +1 -1
- package/node_modules/undici/types/interceptors.d.ts +6 -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-Ck_j1YTn.mjs +0 -1
- package/dist/.setup/http-C9sM-FXe.mjs +0 -2
- package/dist/.setup/plugin-routes-D4qozHVn.mjs +0 -22
- package/dist/.setup/probe-IiHogLQN.mjs +0 -694
- package/dist/.setup/registry-DizWcnNp.mjs +0 -36
- package/dist/.setup/runtime-setter-api-Cx_PV-xu.mjs +0 -2
- package/dist/.setup/setup-plugin-api-B18kDKtr.mjs +0 -2
- package/dist/.setup/shared-DpHCoKy2.mjs +0 -259
- 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
|
-
import { n as __reExport, t as __exportAll } from "./rolldown-runtime-
|
|
2
|
-
import {
|
|
3
|
-
import { n as formatSlackTarget } from "./target-parsing-
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
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-
|
|
9
|
-
import {
|
|
10
|
-
import { n as resolveSlackChannelConfig } from "./policy-
|
|
11
|
-
import { C as resolveSlackChatType, E as stripSlackMentionsForCommandDetection, S as normalizeSlackChannelType, T as readSlackAssistantThreadContext, _ as appendSlackStream, b as stopSlackStream, c as
|
|
12
|
-
import { a as emitSlackMessageSentHooks, i as sanitizeSlackMonitorReplyPayload, n as deliverReplies, t as createSlackReplyDeliveryPlan } from "./replies-
|
|
1
|
+
import { n as __reExport, t as __exportAll } from "./rolldown-runtime-nwUcYXjP.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";
|
|
5
|
+
import { n as resolveSlackReplyThreadTs } from "./thread-ts-47Au2-Yn.mjs";
|
|
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";
|
|
@@ -45,7 +45,7 @@ import { shouldHandleTextCommands } from "openclaw/plugin-sdk/command-surface";
|
|
|
45
45
|
import { resolveChannelContextVisibilityMode } from "openclaw/plugin-sdk/context-visibility-runtime";
|
|
46
46
|
import { DEFAULT_GROUP_HISTORY_LIMIT, buildHistoryContextFromEntries, buildInboundHistoryFromEntries } from "openclaw/plugin-sdk/reply-history";
|
|
47
47
|
import { createChannelPreflightAudio, formatAudioTranscriptForAgent } from "openclaw/plugin-sdk/media-understanding-runtime";
|
|
48
|
-
|
|
48
|
+
// extensions/slack/src/monitor/message-handler/timestamp.ts
|
|
49
49
|
const SLACK_TIMESTAMP_RE = /^\d+(?:\.\d+)?$/;
|
|
50
50
|
const MAX_SAFE_SLACK_TIMESTAMP_SECONDS = Number.MAX_SAFE_INTEGER / 1e3;
|
|
51
51
|
function resolveSlackTimestampMs(ts) {
|
|
@@ -57,8 +57,7 @@ function resolveSlackTimestampMs(ts) {
|
|
|
57
57
|
});
|
|
58
58
|
return seconds === void 0 ? void 0 : Math.round(seconds * 1e3);
|
|
59
59
|
}
|
|
60
|
-
|
|
61
|
-
//#region extensions/slack/src/monitor/message-handler/dispatch-helpers.ts
|
|
60
|
+
// extensions/slack/src/monitor/message-handler/dispatch-helpers.ts
|
|
62
61
|
function resolveSlackBotLoopProtection(prepared) {
|
|
63
62
|
const senderBotId = prepared.message.bot_id;
|
|
64
63
|
if (!senderBotId) return;
|
|
@@ -97,13 +96,6 @@ function resolveSlackNativeProgressTaskCards(entry, style) {
|
|
|
97
96
|
}
|
|
98
97
|
const SLACK_STREAM_RECIPIENT_TEAM_CACHE_MAX = 2e3;
|
|
99
98
|
const slackStreamRecipientTeamCaches = /* @__PURE__ */ new WeakMap();
|
|
100
|
-
function getSlackStreamRecipientTeamCache(client) {
|
|
101
|
-
const existing = slackStreamRecipientTeamCaches.get(client);
|
|
102
|
-
if (existing) return existing;
|
|
103
|
-
const cache = /* @__PURE__ */ new Map();
|
|
104
|
-
slackStreamRecipientTeamCaches.set(client, cache);
|
|
105
|
-
return cache;
|
|
106
|
-
}
|
|
107
99
|
function buildSlackEventDeliveryKey(params, preparedReply = prepareSlackReply(params.payload)) {
|
|
108
100
|
const reply = resolveSendableOutboundReplyParts(params.payload, { text: params.textOverride });
|
|
109
101
|
const renderPlan = preparedReply.resolvePreview(params.textOverride);
|
|
@@ -122,7 +114,7 @@ function buildSlackEventDeliveryKey(params, preparedReply = prepareSlackReply(pa
|
|
|
122
114
|
}
|
|
123
115
|
async function resolveSlackStreamRecipientTeamId(params) {
|
|
124
116
|
const cacheKey = params.fallbackTeamId && params.userId ? `${params.fallbackTeamId}:${params.userId}` : void 0;
|
|
125
|
-
const cache = cacheKey ?
|
|
117
|
+
const cache = cacheKey ? getOrCreateWeakOwnerMap(slackStreamRecipientTeamCaches, params.client) : void 0;
|
|
126
118
|
const cachedTeamId = cache && cacheKey ? readLruMapEntry(cache, cacheKey) : void 0;
|
|
127
119
|
if (cachedTeamId) return cachedTeamId;
|
|
128
120
|
if (params.userId) try {
|
|
@@ -140,14 +132,11 @@ async function resolveSlackStreamRecipientTeamId(params) {
|
|
|
140
132
|
}
|
|
141
133
|
return params.fallbackTeamId;
|
|
142
134
|
}
|
|
143
|
-
|
|
144
|
-
//#region extensions/slack/src/draft-stream.ts
|
|
135
|
+
// extensions/slack/src/draft-stream.ts
|
|
145
136
|
const DEFAULT_THROTTLE_MS = 1e3;
|
|
146
137
|
function createSlackDraftStream(params) {
|
|
147
138
|
const maxChars = Math.min(params.maxChars ?? 8e3, SLACK_TEXT_LIMIT);
|
|
148
139
|
const throttleMs = Math.max(250, params.throttleMs ?? DEFAULT_THROTTLE_MS);
|
|
149
|
-
const send = params.send ?? sendMessageSlack;
|
|
150
|
-
const remove = params.remove ?? deleteSlackMessage;
|
|
151
140
|
let streamMessage;
|
|
152
141
|
let untrackConversationBoundary;
|
|
153
142
|
let lastSentKey = "";
|
|
@@ -161,7 +150,7 @@ function createSlackDraftStream(params) {
|
|
|
161
150
|
streamMessage = void 0;
|
|
162
151
|
lastSentKey = "";
|
|
163
152
|
};
|
|
164
|
-
const editPreview = (message, update) => (
|
|
153
|
+
const editPreview = (message, update) => (update.textIsSlackMrkdwn ? editSlackRenderedMessage : editSlackMessage)(message.channelId, message.messageId, update.text, {
|
|
165
154
|
cfg: params.cfg,
|
|
166
155
|
token: params.token,
|
|
167
156
|
accountId: params.accountId,
|
|
@@ -208,7 +197,7 @@ function createSlackDraftStream(params) {
|
|
|
208
197
|
onInterveningMessage: () => forceNewMessage("human")
|
|
209
198
|
});
|
|
210
199
|
await lifecycle.createMessage(async () => {
|
|
211
|
-
const sent = await
|
|
200
|
+
const sent = await sendMessageSlack(params.target, visibleUpdate.text, {
|
|
212
201
|
cfg: params.cfg,
|
|
213
202
|
token: params.token,
|
|
214
203
|
accountId: params.accountId,
|
|
@@ -253,7 +242,7 @@ function createSlackDraftStream(params) {
|
|
|
253
242
|
clearMessageId,
|
|
254
243
|
isValidMessageId: (value) => typeof value === "object" && value !== null,
|
|
255
244
|
deleteMessage: async (message) => {
|
|
256
|
-
if (!message.retained && !(preserveHumanReplies && message.detachedByHuman)) await
|
|
245
|
+
if (!message.retained && !(preserveHumanReplies && message.detachedByHuman)) await deleteSlackMessage(message.channelId, message.messageId, {
|
|
257
246
|
token: params.token,
|
|
258
247
|
accountId: params.accountId,
|
|
259
248
|
...params.eventScope ? { client: params.eventScope.client } : {}
|
|
@@ -301,7 +290,6 @@ function createSlackDraftStream(params) {
|
|
|
301
290
|
stopTrackingConversationBoundary();
|
|
302
291
|
return true;
|
|
303
292
|
};
|
|
304
|
-
params.log?.(`slack stream preview ready (maxChars=${maxChars}, throttleMs=${throttleMs})`);
|
|
305
293
|
return {
|
|
306
294
|
update,
|
|
307
295
|
flush: loop.flush,
|
|
@@ -315,8 +303,7 @@ function createSlackDraftStream(params) {
|
|
|
315
303
|
channelId: () => streamMessage?.channelId
|
|
316
304
|
};
|
|
317
305
|
}
|
|
318
|
-
|
|
319
|
-
//#region extensions/slack/src/stream-mode.ts
|
|
306
|
+
// extensions/slack/src/stream-mode.ts
|
|
320
307
|
function resolveSlackStreamingConfig(params) {
|
|
321
308
|
return {
|
|
322
309
|
mode: params.streaming?.mode ?? "progress",
|
|
@@ -365,8 +352,7 @@ function applyAppendOnlyStreamUpdate(params) {
|
|
|
365
352
|
changed: true
|
|
366
353
|
};
|
|
367
354
|
}
|
|
368
|
-
|
|
369
|
-
//#region extensions/slack/src/progress-blocks.ts
|
|
355
|
+
// extensions/slack/src/progress-blocks.ts
|
|
370
356
|
const SLACK_PROGRESS_FIELD_MAX = 1800;
|
|
371
357
|
const DEFAULT_SLACK_PROGRESS_DETAIL_MAX_CHARS = 120;
|
|
372
358
|
const DEFAULT_SLACK_PROGRESS_TASK_DETAIL_MAX_CHARS = 48;
|
|
@@ -375,12 +361,6 @@ const SLACK_PROGRESS_TASK_TITLE_MAX = 120;
|
|
|
375
361
|
const SLACK_PROGRESS_PLAN_FALLBACK_TITLE = "Thinking";
|
|
376
362
|
const SLACK_PROGRESS_LINE_DELTA_RE = /(?:^|\s)\+(\d+)\s+[−-](\d+)(?=\s|$)/u;
|
|
377
363
|
const SLACK_ATTENTION_TASK_PREFIX = "openclaw-attention-";
|
|
378
|
-
function buildSessionSources(links) {
|
|
379
|
-
return links.map((link) => ({
|
|
380
|
-
type: "url_source",
|
|
381
|
-
...link
|
|
382
|
-
}));
|
|
383
|
-
}
|
|
384
364
|
function field(text) {
|
|
385
365
|
return {
|
|
386
366
|
type: "mrkdwn",
|
|
@@ -439,10 +419,6 @@ function lineTaskTitle(line) {
|
|
|
439
419
|
if (fallback && fallback !== label) return compactTitle(lineDetailParts(line).length > 0 || line.status ? label : fallback);
|
|
440
420
|
return compactTitle(label);
|
|
441
421
|
}
|
|
442
|
-
function lineTaskDetails(line, maxLineChars) {
|
|
443
|
-
const detail = line.detail?.replace(SLACK_PROGRESS_LINE_DELTA_RE, "").replace(/\s+·\s*$/u, "").trim();
|
|
444
|
-
return detail && detail !== line.status?.trim() ? compactDetail(detail, maxLineChars) : void 0;
|
|
445
|
-
}
|
|
446
422
|
function lineTaskOutput(line) {
|
|
447
423
|
const match = line.detail ? SLACK_PROGRESS_LINE_DELTA_RE.exec(line.detail) : null;
|
|
448
424
|
if (match) return `+${match[1]} −${match[2]}`;
|
|
@@ -473,48 +449,39 @@ function resolveLineTaskIdentity(line, contentIdOccurrences) {
|
|
|
473
449
|
contentIdOccurrences.set(id, occurrence);
|
|
474
450
|
return `${id}_${occurrence}`;
|
|
475
451
|
}
|
|
476
|
-
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");
|
|
477
465
|
const tasks = (params.plan ?? []).map((entry, index) => ({
|
|
478
466
|
id: `plan_step_${index + 1}`,
|
|
479
467
|
title: compactTitle(entry.step),
|
|
480
468
|
status: entry.status === "completed" ? "complete" : entry.status
|
|
481
469
|
}));
|
|
482
470
|
const maxLineChars = resolveMaxLineChars(params.maxLineChars, DEFAULT_SLACK_PROGRESS_TASK_DETAIL_MAX_CHARS);
|
|
483
|
-
const
|
|
484
|
-
for (const line of
|
|
471
|
+
const taskContentIdOccurrences = /* @__PURE__ */ new Map();
|
|
472
|
+
for (const line of taskLines) {
|
|
485
473
|
const task = {
|
|
486
|
-
id: resolveLineTaskIdentity(line,
|
|
474
|
+
id: resolveLineTaskIdentity(line, taskContentIdOccurrences),
|
|
487
475
|
title: lineTaskTitle(line),
|
|
488
476
|
status: lineTaskStatus(line)
|
|
489
477
|
};
|
|
490
|
-
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;
|
|
491
480
|
const output = lineTaskOutput(line);
|
|
492
481
|
if (details) task.details = details;
|
|
493
482
|
if (output) task.output = output;
|
|
494
483
|
tasks.push(task);
|
|
495
484
|
}
|
|
496
|
-
return tasks;
|
|
497
|
-
}
|
|
498
|
-
function formatProgressAttentionTitle(line, finalStatus) {
|
|
499
|
-
if (line.kind === "approval") return line.status === "requested" && finalStatus === void 0 ? compactTitle(`Approval required: ${line.detail || line.label}`) : void 0;
|
|
500
|
-
if (lineTaskStatus(line) !== "error") return;
|
|
501
|
-
const title = [...new Set([
|
|
502
|
-
line.label,
|
|
503
|
-
line.detail,
|
|
504
|
-
line.status
|
|
505
|
-
].filter(Boolean))].join(" — ");
|
|
506
|
-
return compactTitle(finalStatus === "complete" ? `Recovered: ${title}` : title);
|
|
507
|
-
}
|
|
508
|
-
function formatTaskDiffOutput(diffStat) {
|
|
509
|
-
return diffStat && (diffStat.added > 0 || diffStat.removed > 0) ? `+${diffStat.added} −${diffStat.removed}` : void 0;
|
|
510
|
-
}
|
|
511
|
-
function buildSlackProgressStreamChunks(params) {
|
|
512
|
-
const approvals = params.lines.filter((line) => line.kind === "approval");
|
|
513
|
-
const tasks = buildNativeTasks({
|
|
514
|
-
lines: params.summaryRow ? [] : params.lines.filter((line) => line.kind !== "approval"),
|
|
515
|
-
plan: params.plan,
|
|
516
|
-
maxLineChars: params.maxLineChars
|
|
517
|
-
});
|
|
518
485
|
const contentIdOccurrences = /* @__PURE__ */ new Map();
|
|
519
486
|
const attention = [];
|
|
520
487
|
for (const line of approvals) {
|
|
@@ -525,11 +492,11 @@ function buildSlackProgressStreamChunks(params) {
|
|
|
525
492
|
status: "pending"
|
|
526
493
|
});
|
|
527
494
|
}
|
|
528
|
-
const headline = params.title?.trim()
|
|
495
|
+
const headline = params.title?.trim();
|
|
529
496
|
const summaryTitle = params.finalInProgressStatus === "error" ? "Failed" : params.finalInProgressStatus === "complete" || !params.summaryRow ? "Completed" : "Working";
|
|
530
497
|
const newest = tasks.at(-1);
|
|
531
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);
|
|
532
|
-
const diffOutput =
|
|
499
|
+
const diffOutput = params.diffStat && (params.diffStat.added > 0 || params.diffStat.removed > 0) ? `+${params.diffStat.added} −${params.diffStat.removed}` : void 0;
|
|
533
500
|
if (tasks.length === 0 && (params.summaryRow || params.sessionLinks?.length || diffOutput)) tasks.push({
|
|
534
501
|
id: "openclaw_summary",
|
|
535
502
|
title: params.summaryRow ? compactTitle(title) : summaryTitle,
|
|
@@ -549,7 +516,10 @@ function buildSlackProgressStreamChunks(params) {
|
|
|
549
516
|
chunk.title = recovered ? compactTitle(`Recovered: ${task.title}`) : task.title;
|
|
550
517
|
chunk.status = recovered ? "complete" : task.status === "in_progress" ? params.finalInProgressStatus ?? task.status : task.status;
|
|
551
518
|
if (index === finalTaskIndex && diffOutput) chunk.output = [task.output, diffOutput].filter(Boolean).join(" · ");
|
|
552
|
-
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
|
+
}));
|
|
553
523
|
return chunk;
|
|
554
524
|
});
|
|
555
525
|
return [{
|
|
@@ -568,13 +538,6 @@ function joinRecentProgressRows(rows) {
|
|
|
568
538
|
}
|
|
569
539
|
return rendered.toReversed().join("\n");
|
|
570
540
|
}
|
|
571
|
-
function buildActivityText(lines, maxLineChars) {
|
|
572
|
-
return joinRecentProgressRows(lines.slice(-50).map((line) => {
|
|
573
|
-
if (line.kind === "item" && !line.toolName) return `_${renderProgressCardText(compactDetail(line.text, maxLineChars), "italic")}_`;
|
|
574
|
-
const detail = compactDetail(lineDetailParts(line).join(" · "), maxLineChars);
|
|
575
|
-
return escapeSlackMrkdwn(detail ? `${line.label} — ${detail}` : line.label);
|
|
576
|
-
}));
|
|
577
|
-
}
|
|
578
541
|
function buildSlackProgressCardBlocks(params) {
|
|
579
542
|
const maxLineChars = resolveMaxLineChars(params.maxLineChars, DEFAULT_SLACK_PROGRESS_DETAIL_MAX_CHARS);
|
|
580
543
|
const selected = selectPlanChecklistSteps(params.detailed ? params.plan ?? [] : [], { maxLines: 50 });
|
|
@@ -604,7 +567,11 @@ function buildSlackProgressCardBlocks(params) {
|
|
|
604
567
|
});
|
|
605
568
|
const sections = [
|
|
606
569
|
planLines.map((line) => renderProgressCardText(line)).join("\n"),
|
|
607
|
-
|
|
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
|
+
})),
|
|
608
575
|
joinRecentProgressRows(attention)
|
|
609
576
|
];
|
|
610
577
|
const title = params.title?.trim();
|
|
@@ -684,6 +651,13 @@ function reconcileSlackNativeTaskChunks(params) {
|
|
|
684
651
|
const nextTasks = /* @__PURE__ */ new Map();
|
|
685
652
|
let planTitle = params.previous.planTitle;
|
|
686
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
|
+
}
|
|
687
661
|
for (const chunk of params.chunks ?? []) {
|
|
688
662
|
if (chunk.type === "plan_update") {
|
|
689
663
|
if (chunk.title !== planTitle) {
|
|
@@ -751,8 +725,7 @@ function reconcileSlackNativeTaskChunks(params) {
|
|
|
751
725
|
}
|
|
752
726
|
};
|
|
753
727
|
}
|
|
754
|
-
|
|
755
|
-
//#region extensions/slack/src/monitor/message-handler/dispatch-progress-render.ts
|
|
728
|
+
// extensions/slack/src/monitor/message-handler/dispatch-progress-render.ts
|
|
756
729
|
function resolveStructuredProgressLines(lines) {
|
|
757
730
|
return lines.map((line) => {
|
|
758
731
|
if (typeof line !== "string") return line;
|
|
@@ -793,14 +766,7 @@ function isSlackProgressTitleText(text, snapshot, explicitTitle) {
|
|
|
793
766
|
const title = normalizeProgressText(combineProgressHeadlineAndExplanation(explicitTitle ?? (snapshot.statusHeadlineFormat === "plain" ? void 0 : snapshot.statusHeadline), snapshot.planExplanationFormat === "plain" ? void 0 : snapshot.planExplanation));
|
|
794
767
|
return title.length > 0 && title.includes(candidate);
|
|
795
768
|
}
|
|
796
|
-
|
|
797
|
-
//#region extensions/slack/src/monitor/message-handler/preview-finalize.ts
|
|
798
|
-
function buildExpectedSlackEditText(params) {
|
|
799
|
-
const trimmedText = params.text.trim();
|
|
800
|
-
if (trimmedText) return normalizeSlackOutboundText(trimmedText);
|
|
801
|
-
if (params.blocks?.length) return normalizeSlackOutboundText(buildSlackBlocksFallbackText(params.blocks));
|
|
802
|
-
return " ";
|
|
803
|
-
}
|
|
769
|
+
// extensions/slack/src/monitor/message-handler/preview-finalize.ts
|
|
804
770
|
function blocksMatch(expected, actual) {
|
|
805
771
|
if (!expected?.length) return !actual?.length;
|
|
806
772
|
if (!actual?.length) {
|
|
@@ -820,45 +786,6 @@ function blocksMatch(expected, actual) {
|
|
|
820
786
|
return false;
|
|
821
787
|
}
|
|
822
788
|
}
|
|
823
|
-
async function readSlackMessageAfterEditError(params) {
|
|
824
|
-
const query = {
|
|
825
|
-
token: params.token,
|
|
826
|
-
channel: params.channelId,
|
|
827
|
-
latest: params.messageId,
|
|
828
|
-
oldest: params.messageId,
|
|
829
|
-
inclusive: true,
|
|
830
|
-
limit: 1
|
|
831
|
-
};
|
|
832
|
-
const result = params.threadTs ? await params.client.conversations.replies({
|
|
833
|
-
...query,
|
|
834
|
-
ts: params.threadTs
|
|
835
|
-
}) : await params.client.conversations.history(query);
|
|
836
|
-
const message = params.threadTs ? result.messages?.find((entry) => entry?.ts === params.messageId) : result.messages?.[0];
|
|
837
|
-
return message?.ts && message.ts === params.messageId ? message : null;
|
|
838
|
-
}
|
|
839
|
-
async function didSlackPreviewEditApplyAfterError(params) {
|
|
840
|
-
const readback = await readSlackMessageAfterEditError(params);
|
|
841
|
-
if (!readback) return false;
|
|
842
|
-
const expectedText = buildExpectedSlackEditText({
|
|
843
|
-
text: params.text,
|
|
844
|
-
blocks: params.blocks
|
|
845
|
-
});
|
|
846
|
-
const acceptedTexts = /* @__PURE__ */ new Set([
|
|
847
|
-
expectedText,
|
|
848
|
-
normalizeSlackOutboundText(truncateSlackTextByUtf8Bytes(expectedText, SLACK_EDIT_TEXT_MAX_BYTES)),
|
|
849
|
-
normalizeSlackOutboundText(buildSlackEditTextPayload(params.text, params.blocks))
|
|
850
|
-
]);
|
|
851
|
-
if (params.blocks?.length && hasSlackNativeDataBlock(params.blocks)) {
|
|
852
|
-
const fallbackPlan = buildSlackNativeDataDeliveryPlan({
|
|
853
|
-
baseText: params.text,
|
|
854
|
-
blocks: params.blocks
|
|
855
|
-
});
|
|
856
|
-
for (const message of fallbackPlan.fallbackMessages) acceptedTexts.add(normalizeSlackOutboundText(message.text));
|
|
857
|
-
}
|
|
858
|
-
const actualText = normalizeSlackOutboundText((readback.text ?? "").trim());
|
|
859
|
-
if (params.blocks?.length) return acceptedTexts.has(actualText) && blocksMatch(params.blocks, readback.blocks);
|
|
860
|
-
return actualText === expectedText;
|
|
861
|
-
}
|
|
862
789
|
async function finalizeSlackPreviewEdit(params) {
|
|
863
790
|
try {
|
|
864
791
|
await editSlackRenderedMessage(params.channelId, params.messageId, params.text, {
|
|
@@ -869,9 +796,40 @@ async function finalizeSlackPreviewEdit(params) {
|
|
|
869
796
|
});
|
|
870
797
|
} catch (err) {
|
|
871
798
|
try {
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
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
|
+
}
|
|
875
833
|
}
|
|
876
834
|
} catch (readbackErr) {
|
|
877
835
|
logVerbose(`slack: preview final edit readback failed (${String(readbackErr)})`);
|
|
@@ -879,8 +837,7 @@ async function finalizeSlackPreviewEdit(params) {
|
|
|
879
837
|
throw err;
|
|
880
838
|
}
|
|
881
839
|
}
|
|
882
|
-
|
|
883
|
-
//#region extensions/slack/src/monitor/message-handler/dispatch-progress-card.ts
|
|
840
|
+
// extensions/slack/src/monitor/message-handler/dispatch-progress-card.ts
|
|
884
841
|
const MAX_VISIBLE_WORK_LINKS = 5;
|
|
885
842
|
function createSlackDraftProgressCardRuntime(params) {
|
|
886
843
|
const { cfg, prepared, slackClient } = params.setup;
|
|
@@ -1008,8 +965,7 @@ function formatSlackProgressDraftLine(line) {
|
|
|
1008
965
|
enclosingStyle: "italic"
|
|
1009
966
|
})}_`;
|
|
1010
967
|
}
|
|
1011
|
-
|
|
1012
|
-
//#region extensions/slack/src/monitor/message-handler/dispatch-progress-native.ts
|
|
968
|
+
// extensions/slack/src/monitor/message-handler/dispatch-progress-native.ts
|
|
1013
969
|
function createSlackNativeProgressTransport(params) {
|
|
1014
970
|
const { replyPlan } = params.setup;
|
|
1015
971
|
const { delivery } = params;
|
|
@@ -1049,7 +1005,7 @@ function createSlackNativeProgressTransport(params) {
|
|
|
1049
1005
|
const delivered = markDelivered(streamThreadTs);
|
|
1050
1006
|
return update.chunks?.length ? delivered : true;
|
|
1051
1007
|
} finally {
|
|
1052
|
-
|
|
1008
|
+
delivery.nativeProgressStreamStartPromise = null;
|
|
1053
1009
|
}
|
|
1054
1010
|
};
|
|
1055
1011
|
const append = async (update) => {
|
|
@@ -1070,8 +1026,7 @@ function createSlackNativeProgressTransport(params) {
|
|
|
1070
1026
|
waitForStart
|
|
1071
1027
|
};
|
|
1072
1028
|
}
|
|
1073
|
-
|
|
1074
|
-
//#region extensions/slack/src/monitor/message-handler/dispatch-progress.ts
|
|
1029
|
+
// extensions/slack/src/monitor/message-handler/dispatch-progress.ts
|
|
1075
1030
|
function createSlackProgressRuntime(runtimeParams) {
|
|
1076
1031
|
const { setup, delivery } = runtimeParams;
|
|
1077
1032
|
const { cfg, hasSlackCustomIdentity, prepared, replyPlan, runtime, slackIdentity, slackStreaming, slackProgressStyle, quietProgress, shouldUseDraftStream, useStreaming, previewStreamingEnabled } = setup;
|
|
@@ -1081,7 +1036,6 @@ function createSlackProgressRuntime(runtimeParams) {
|
|
|
1081
1036
|
cfg,
|
|
1082
1037
|
token: ctx.botToken,
|
|
1083
1038
|
accountId: account.accountId,
|
|
1084
|
-
conversationChannelId: message.channel,
|
|
1085
1039
|
eventScope: prepared.eventScope,
|
|
1086
1040
|
...!hasSlackCustomIdentity && slackIdentity ? { identity: slackIdentity } : {},
|
|
1087
1041
|
...slackMessageMetadata ? { metadata: slackMessageMetadata } : {},
|
|
@@ -1091,7 +1045,6 @@ function createSlackProgressRuntime(runtimeParams) {
|
|
|
1091
1045
|
if (ts) delivery.usedReplyThreadTs ??= ts;
|
|
1092
1046
|
return ts;
|
|
1093
1047
|
},
|
|
1094
|
-
log: logVerbose,
|
|
1095
1048
|
warn: logVerbose
|
|
1096
1049
|
}) : void 0;
|
|
1097
1050
|
const isProgressMode = slackStreaming.mode === "progress";
|
|
@@ -1510,7 +1463,6 @@ function createSlackProgressRuntime(runtimeParams) {
|
|
|
1510
1463
|
return {
|
|
1511
1464
|
draftStream,
|
|
1512
1465
|
previewLifecycle,
|
|
1513
|
-
isProgressMode,
|
|
1514
1466
|
useDraftProgressCard,
|
|
1515
1467
|
useNativeProgressStreaming,
|
|
1516
1468
|
progressDraftActive,
|
|
@@ -1546,8 +1498,7 @@ function createSlackProgressRuntime(runtimeParams) {
|
|
|
1546
1498
|
updateDraftFromPartial
|
|
1547
1499
|
};
|
|
1548
1500
|
}
|
|
1549
|
-
|
|
1550
|
-
//#region extensions/slack/src/monitor/message-handler/dispatch-setup.ts
|
|
1501
|
+
// extensions/slack/src/monitor/message-handler/dispatch-setup.ts
|
|
1551
1502
|
async function createSlackDispatchSetup(prepared) {
|
|
1552
1503
|
const { ctx, account, message, route } = prepared;
|
|
1553
1504
|
const slackClient = prepared.eventScope?.client ?? ctx.app.client;
|
|
@@ -1703,9 +1654,7 @@ async function createSlackDispatchSetup(prepared) {
|
|
|
1703
1654
|
status: "active",
|
|
1704
1655
|
eventScope: prepared.eventScope
|
|
1705
1656
|
});
|
|
1706
|
-
if (reportFailure && !restored)
|
|
1707
|
-
runtime.error?.("Slack session status could not return to active after processing. Enable verbose logging to inspect the Slack API failure.");
|
|
1708
|
-
} catch {}
|
|
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.");
|
|
1709
1658
|
}
|
|
1710
1659
|
if (didAddTypingReaction && typingReaction && message.ts) {
|
|
1711
1660
|
didAddTypingReaction = false;
|
|
@@ -1765,11 +1714,14 @@ async function createSlackDispatchSetup(prepared) {
|
|
|
1765
1714
|
useStreaming
|
|
1766
1715
|
};
|
|
1767
1716
|
}
|
|
1768
|
-
|
|
1769
|
-
//#region extensions/slack/src/monitor/message-handler/dispatch-streaming.ts
|
|
1717
|
+
// extensions/slack/src/monitor/message-handler/dispatch-streaming.ts
|
|
1770
1718
|
function createSlackStreamingDeliveryRuntime(setup) {
|
|
1771
1719
|
const { isThreadReply, messageSentHookContext, messageSentHookTarget, prepared, replyDeliveryMode, replyPlan, runtime, slackClient, slackClientOptions, slackIdentity, slackStreamFallbackTeamId } = setup;
|
|
1772
1720
|
const { account, ctx, forcedReplyThreadTs, message, slackMessageMetadata } = prepared;
|
|
1721
|
+
const markdownOptions = resolveSlackMarkdownOptions({
|
|
1722
|
+
cfg: ctx.cfg,
|
|
1723
|
+
accountId: account.accountId
|
|
1724
|
+
});
|
|
1773
1725
|
const state = {
|
|
1774
1726
|
streamSession: null,
|
|
1775
1727
|
streamBoundary: null,
|
|
@@ -1850,7 +1802,7 @@ function createSlackStreamingDeliveryRuntime(setup) {
|
|
|
1850
1802
|
if (key) deliveredKeys.add(key);
|
|
1851
1803
|
};
|
|
1852
1804
|
const markPreviewPayloadDelivered = (params) => {
|
|
1853
|
-
const preparedReply = prepareSlackReply(params.payload);
|
|
1805
|
+
const preparedReply = prepareSlackReply(params.payload, markdownOptions);
|
|
1854
1806
|
markDelivered(buildSlackEventDeliveryKey(params, preparedReply));
|
|
1855
1807
|
const nextThreadTs = replyPlan.peekThreadTs();
|
|
1856
1808
|
if (nextThreadTs !== params.threadTs) markDelivered(buildSlackEventDeliveryKey({
|
|
@@ -1891,7 +1843,7 @@ function createSlackStreamingDeliveryRuntime(setup) {
|
|
|
1891
1843
|
}
|
|
1892
1844
|
const fallbackText = fallbackError.pendingText.trim();
|
|
1893
1845
|
if (!fallbackText) return;
|
|
1894
|
-
const sent = await deliverPreparedReply(prepareSlackReply({ text: fallbackText }), session.threadTs, true);
|
|
1846
|
+
const sent = await deliverPreparedReply(prepareSlackReply({ text: fallbackText }, markdownOptions), session.threadTs, true);
|
|
1895
1847
|
if (!sent?.receipt.platformMessageIds.length) return;
|
|
1896
1848
|
markSlackStreamFallbackDelivered(session);
|
|
1897
1849
|
if (!session.stopped) try {
|
|
@@ -1949,16 +1901,13 @@ function createSlackStreamingDeliveryRuntime(setup) {
|
|
|
1949
1901
|
if (state.streamSession?.stoppedBySlack) return { visibleReplySent: false };
|
|
1950
1902
|
const replyThreadTs = params.forcedThreadTs ?? state.interruptedThreadTs ?? resolveDeliveryThreadTs(params);
|
|
1951
1903
|
const deliveryReplyThreadTs = replyDeliveryMode === "off" && !forcedReplyThreadTs && !isThreadReply ? void 0 : replyThreadTs;
|
|
1952
|
-
const preparedReply = prepareSlackReply(params.payload);
|
|
1904
|
+
const preparedReply = prepareSlackReply(params.payload, markdownOptions);
|
|
1953
1905
|
const deliveryKey = buildSlackEventDeliveryKey({
|
|
1954
1906
|
kind: params.kind,
|
|
1955
1907
|
payload: params.payload,
|
|
1956
1908
|
threadTs: deliveryReplyThreadTs
|
|
1957
1909
|
}, preparedReply);
|
|
1958
|
-
if (deliveryKey && deliveredKeys.has(deliveryKey)) {
|
|
1959
|
-
logVerbose("slack: suppressed duplicate normal delivery within the same turn");
|
|
1960
|
-
return { visibleReplySent: false };
|
|
1961
|
-
}
|
|
1910
|
+
if (deliveryKey && deliveredKeys.has(deliveryKey)) return { visibleReplySent: false };
|
|
1962
1911
|
const sent = await deliverPreparedReply(preparedReply, deliveryReplyThreadTs);
|
|
1963
1912
|
if (!sent?.receipt.platformMessageIds.length) return { visibleReplySent: false };
|
|
1964
1913
|
state.observedReplyDelivery = true;
|
|
@@ -1980,9 +1929,16 @@ function createSlackStreamingDeliveryRuntime(setup) {
|
|
|
1980
1929
|
};
|
|
1981
1930
|
const isStreamingEligible = (payload, options) => {
|
|
1982
1931
|
const reply = resolveSendableOutboundReplyParts(payload);
|
|
1983
|
-
const renderPlan = resolveSlackReplyRenderPlan(payload);
|
|
1932
|
+
const renderPlan = resolveSlackReplyRenderPlan(payload, payload.text, markdownOptions);
|
|
1984
1933
|
const plannedBlocks = renderPlan.mode === "single" ? renderPlan.blocks : renderPlan.blockPart?.blocks;
|
|
1985
|
-
|
|
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);
|
|
1986
1942
|
};
|
|
1987
1943
|
const deliverWithStreaming = async (params) => {
|
|
1988
1944
|
if (state.streamSession?.stoppedBySlack) return { visibleReplySent: false };
|
|
@@ -1995,7 +1951,12 @@ function createSlackStreamingDeliveryRuntime(setup) {
|
|
|
1995
1951
|
await rotateInterruptedStream();
|
|
1996
1952
|
if (state.streamSession?.stoppedBySlack) return { visibleReplySent: false };
|
|
1997
1953
|
let session = state.streamSession;
|
|
1998
|
-
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
|
+
});
|
|
1999
1960
|
if (state.streamFailed || !threadTs) {
|
|
2000
1961
|
state.streamFailed = true;
|
|
2001
1962
|
return await deliverNormally({
|
|
@@ -2010,11 +1971,8 @@ function createSlackStreamingDeliveryRuntime(setup) {
|
|
|
2010
1971
|
...params,
|
|
2011
1972
|
threadTs,
|
|
2012
1973
|
textOverride: text
|
|
2013
|
-
});
|
|
2014
|
-
if (deliveryKey && deliveredKeys.has(deliveryKey)) {
|
|
2015
|
-
logVerbose("slack-stream: suppressed duplicate reply payload");
|
|
2016
|
-
return { visibleReplySent: false };
|
|
2017
|
-
}
|
|
1974
|
+
}, prepareSlackReply(params.payload, markdownOptions));
|
|
1975
|
+
if (deliveryKey && deliveredKeys.has(deliveryKey)) return { visibleReplySent: false };
|
|
2018
1976
|
let messageId;
|
|
2019
1977
|
let fallbackDelivery;
|
|
2020
1978
|
try {
|
|
@@ -2095,8 +2053,75 @@ function createSlackStreamingDeliveryRuntime(setup) {
|
|
|
2095
2053
|
resetDeliveryTracker: () => deliveredKeys.clear()
|
|
2096
2054
|
});
|
|
2097
2055
|
}
|
|
2098
|
-
|
|
2099
|
-
|
|
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
|
+
}
|
|
2124
|
+
// extensions/slack/src/monitor/message-handler/dispatch.ts
|
|
2100
2125
|
function formatSlackGroupThreadReply(text, participant) {
|
|
2101
2126
|
return `**${participant.name.replace(/[\\`*_{}[\]()<>#!|]/g, "\\$&").replace(/\s+/g, " ")}**\n${text}`;
|
|
2102
2127
|
}
|
|
@@ -2121,7 +2146,7 @@ async function dispatchPreparedSlackMessage(prepared) {
|
|
|
2121
2146
|
},
|
|
2122
2147
|
onSettled: () => {
|
|
2123
2148
|
releaseDeferred?.();
|
|
2124
|
-
upstreamLifecycle.onSettled?.();
|
|
2149
|
+
return upstreamLifecycle.onSettled?.();
|
|
2125
2150
|
}
|
|
2126
2151
|
};
|
|
2127
2152
|
const release = beginSessionRun();
|
|
@@ -2130,6 +2155,10 @@ async function dispatchPreparedSlackMessage(prepared) {
|
|
|
2130
2155
|
async function dispatchSlackMessageWithSetup(setup, beginSessionRun, turnAdoptionLifecycle) {
|
|
2131
2156
|
const { prepared } = setup;
|
|
2132
2157
|
const { account, ctx, message, route } = prepared;
|
|
2158
|
+
const markdownOptions = resolveSlackMarkdownOptions({
|
|
2159
|
+
cfg: ctx.cfg,
|
|
2160
|
+
accountId: account.accountId
|
|
2161
|
+
});
|
|
2133
2162
|
const { cfg, disableBlockStreaming, hasSlackCustomIdentity, hasRepliedRef, messageSentHookContext, messageSentHookTarget, onModelSelected, previewStreamingEnabled, replyPipeline, replyPlan, runtime, slackClient, slackStreaming, sourceReplyDeliveryMode, statusReactions, statusReactionsEnabled, statusThreadTs, suppressRoomEventTyping, useStreaming } = setup;
|
|
2134
2163
|
let dispatchError;
|
|
2135
2164
|
const delivery = createSlackStreamingDeliveryRuntime(setup);
|
|
@@ -2141,41 +2170,22 @@ async function dispatchSlackMessageWithSetup(setup, beginSessionRun, turnAdoptio
|
|
|
2141
2170
|
let turnCommentaryVisible = false;
|
|
2142
2171
|
const { draftStream, previewLifecycle } = progress;
|
|
2143
2172
|
setup.threadStatusGate.hasVisibleOutput = () => delivery.observedReplyDelivery || previewLifecycle.previewFinalized || Boolean(draftStream?.messageId());
|
|
2144
|
-
const
|
|
2145
|
-
|
|
2146
|
-
|
|
2147
|
-
|
|
2148
|
-
|
|
2149
|
-
|
|
2150
|
-
|
|
2151
|
-
if (delivery.observedReplyDelivery || previewLifecycle.previewFinalized) return payload;
|
|
2152
|
-
const explicitlyAddressed = prepared.ctxPayload.ExplicitlyMentionedBot === true || prepared.ctxPayload.MentionSource === "explicit_bot" || prepared.ctxPayload.MentionSource === "subteam" || prepared.ctxPayload.MentionSource === "mention_pattern" || prepared.ctxPayload.MentionSource === "command_bypass" || prepared.ctxPayload.CommandTurn?.kind !== void 0 && prepared.ctxPayload.CommandTurn.kind !== "normal" && prepared.ctxPayload.CommandTurn.authorized;
|
|
2153
|
-
const noticeThreadTs = failureNoticeThreadTs ?? (explicitlyAddressed ? statusThreadTs : void 0);
|
|
2154
|
-
const notice = {
|
|
2155
|
-
accountId: account.accountId,
|
|
2156
|
-
channelId: message.channel,
|
|
2157
|
-
...noticeThreadTs ? { threadTs: noticeThreadTs } : {},
|
|
2158
|
-
failureText: payload.text ?? "",
|
|
2159
|
-
...failureNoticeTeamId ? { teamId: failureNoticeTeamId } : {}
|
|
2160
|
-
};
|
|
2161
|
-
if (failureNoticeThreadTs && !explicitlyAddressed && prepared.ctxPayload.MentionSource !== "implicit_thread" && !hasSlackThreadParticipation(notice.accountId, notice.channelId, failureNoticeThreadTs, failureNoticeTeamId)) {
|
|
2162
|
-
logVerbose("slack: suppressed passive failure before thread participation");
|
|
2163
|
-
return null;
|
|
2164
|
-
}
|
|
2165
|
-
if (!explicitlyAddressed && hasSlackThreadFailureNotice(notice)) {
|
|
2166
|
-
logVerbose("slack: suppressed repeated passive channel or thread failure");
|
|
2167
|
-
return null;
|
|
2168
|
-
}
|
|
2169
|
-
pendingFailureNotice = notice;
|
|
2170
|
-
return payload;
|
|
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
|
|
2171
2180
|
};
|
|
2181
|
+
const failurePolicy = createSlackFailureNoticePolicy(failurePolicyParams, () => delivery.observedReplyDelivery || previewLifecycle.previewFinalized);
|
|
2172
2182
|
const deliverSlackPayload = async (incomingPayload, info) => {
|
|
2173
2183
|
let payload = incomingPayload;
|
|
2174
2184
|
if (info.participant && (payload.text || payload.mediaUrl || payload.mediaUrls?.length)) payload = {
|
|
2175
2185
|
...payload,
|
|
2176
2186
|
text: formatSlackGroupThreadReply(payload.text ?? "", info.participant)
|
|
2177
2187
|
};
|
|
2178
|
-
if (info.kind === "final" && slackStreaming.mode === "progress"
|
|
2188
|
+
if (info.kind === "final" && slackStreaming.mode === "progress") {
|
|
2179
2189
|
const supplement = getReplyPayloadTtsSupplement(payload);
|
|
2180
2190
|
const finalPayload = !progress.useDraftProgressCard && !progress.useNativeProgressStreaming && supplement && !supplement.visibleTextAlreadyDelivered && !payload.text?.trim() ? {
|
|
2181
2191
|
...payload,
|
|
@@ -2215,15 +2225,11 @@ async function dispatchSlackMessageWithSetup(setup, beginSessionRun, turnAdoptio
|
|
|
2215
2225
|
const reply = resolveSendableOutboundReplyParts(payload);
|
|
2216
2226
|
const ttsSupplement = getReplyPayloadTtsSupplement(payload);
|
|
2217
2227
|
const replySourceText = payload.text ?? ttsSupplement?.spokenText;
|
|
2218
|
-
const replyRenderPlan = resolveSlackReplyRenderPlan(payload, replySourceText);
|
|
2228
|
+
const replyRenderPlan = resolveSlackReplyRenderPlan(payload, replySourceText, markdownOptions);
|
|
2219
2229
|
const slackBlocks = replyRenderPlan.mode === "single" ? replyRenderPlan.blocks : replyRenderPlan.blockPart?.blocks;
|
|
2220
2230
|
const requiresSeparateFallbackDelivery = replyRenderPlan.mode === "split" || replyRenderPlan.textIsSlackPlainText === true;
|
|
2221
2231
|
const trimmedFinalText = replyRenderPlan.mode === "single" ? replyRenderPlan.text.trim() : replyRenderPlan.fallbackText.trim();
|
|
2222
|
-
const previewFinalText = replyRenderPlan.mode === "single" && replyRenderPlan.textIsSlackMrkdwn ? trimmedFinalText : normalizeSlackOutboundText((replySourceText ?? "").trim(),
|
|
2223
|
-
cfg,
|
|
2224
|
-
channel: "slack",
|
|
2225
|
-
accountId: account.accountId
|
|
2226
|
-
}) });
|
|
2232
|
+
const previewFinalText = replyRenderPlan.mode === "single" && replyRenderPlan.textIsSlackMrkdwn ? trimmedFinalText : normalizeSlackOutboundText((replySourceText ?? "").trim(), markdownOptions);
|
|
2227
2233
|
const previewFinalTextFitsEdit = countSlackTextUtf8Bytes(previewFinalText) <= SLACK_EDIT_TEXT_MAX_BYTES;
|
|
2228
2234
|
const shouldRestoreTtsSupplementTextForPreviewFallback = Boolean(ttsSupplement) && ttsSupplement?.visibleTextAlreadyDelivered !== true && Boolean(draftStream) && !previewLifecycle.previewFinalized && !previewLifecycle.finalDelivered && previewStreamingEnabled && !payload.text?.trim();
|
|
2229
2235
|
let ttsPreviewFinalization;
|
|
@@ -2233,11 +2239,18 @@ async function dispatchSlackMessageWithSetup(setup, beginSessionRun, turnAdoptio
|
|
|
2233
2239
|
isError: payload.isError === true,
|
|
2234
2240
|
adapter: {
|
|
2235
2241
|
buildFinalEdit: () => {
|
|
2236
|
-
|
|
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;
|
|
2237
2250
|
return {
|
|
2238
2251
|
text: previewFinalText,
|
|
2239
2252
|
blocks: slackBlocks,
|
|
2240
|
-
threadTs
|
|
2253
|
+
threadTs
|
|
2241
2254
|
};
|
|
2242
2255
|
},
|
|
2243
2256
|
editFinal: async (preview, edit) => {
|
|
@@ -2332,7 +2345,7 @@ async function dispatchSlackMessageWithSetup(setup, beginSessionRun, turnAdoptio
|
|
|
2332
2345
|
...replyPipeline,
|
|
2333
2346
|
transformReplyPayload: (payload) => {
|
|
2334
2347
|
const transformed = replyPipeline.transformReplyPayload ? replyPipeline.transformReplyPayload(payload) : payload;
|
|
2335
|
-
return transformed ?
|
|
2348
|
+
return transformed ? failurePolicy.filter(transformed) : null;
|
|
2336
2349
|
},
|
|
2337
2350
|
humanDelay: resolveHumanDelayConfig(cfg, route.agentId)
|
|
2338
2351
|
},
|
|
@@ -2349,7 +2362,7 @@ async function dispatchSlackMessageWithSetup(setup, beginSessionRun, turnAdoptio
|
|
|
2349
2362
|
replyOptions: {
|
|
2350
2363
|
onVisibleWorkSessions: progress.onVisibleWorkSessions,
|
|
2351
2364
|
groupThreadReplyFormatter: formatSlackGroupThreadReply,
|
|
2352
|
-
queuedDeliveryCorrelations: [
|
|
2365
|
+
queuedDeliveryCorrelations: [createSlackQueuedFailureNoticePolicy(failurePolicyParams, beginSessionRun)],
|
|
2353
2366
|
...turnAdoptionLifecycle ? { turnAdoptionLifecycle } : {},
|
|
2354
2367
|
skillFilter: prepared.channelConfig?.skills,
|
|
2355
2368
|
sourceReplyDeliveryMode,
|
|
@@ -2393,7 +2406,7 @@ async function dispatchSlackMessageWithSetup(setup, beginSessionRun, turnAdoptio
|
|
|
2393
2406
|
if (payload.kind === "preamble" && await shouldYieldDraftProgress()) return false;
|
|
2394
2407
|
if (prepared.turnAdoptionLifecycle?.abortSignal?.aborted) return false;
|
|
2395
2408
|
progress.progressWorkCounter.noteItem(payload);
|
|
2396
|
-
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);
|
|
2397
2410
|
},
|
|
2398
2411
|
onPlanUpdate: async (payload) => {
|
|
2399
2412
|
if (payload.phase !== "update") return false;
|
|
@@ -2407,12 +2420,7 @@ async function dispatchSlackMessageWithSetup(setup, beginSessionRun, turnAdoptio
|
|
|
2407
2420
|
settledDispatchResult = result;
|
|
2408
2421
|
const agentRunOutcome = readAgentRunTerminalOutcome(result);
|
|
2409
2422
|
agentRunFailed = agentRunOutcome === "failed";
|
|
2410
|
-
if (agentRunOutcome === "completed"
|
|
2411
|
-
accountId: account.accountId,
|
|
2412
|
-
channelId: message.channel,
|
|
2413
|
-
...failureNoticeThreadTs ? { threadTs: failureNoticeThreadTs } : {},
|
|
2414
|
-
...failureNoticeTeamId ? { teamId: failureNoticeTeamId } : {}
|
|
2415
|
-
});
|
|
2423
|
+
if (agentRunOutcome === "completed") failurePolicy.complete();
|
|
2416
2424
|
}
|
|
2417
2425
|
} catch (err) {
|
|
2418
2426
|
dispatchError ??= err;
|
|
@@ -2428,7 +2436,7 @@ async function dispatchSlackMessageWithSetup(setup, beginSessionRun, turnAdoptio
|
|
|
2428
2436
|
if (hasVisibleInboundReplyDispatch(settledDispatchResult)) await previewLifecycle.observeDelivery({ visibleReplySent: true });
|
|
2429
2437
|
}
|
|
2430
2438
|
await previewLifecycle.cleanup({ failed: Boolean(dispatchError || agentRunFailed) });
|
|
2431
|
-
if (
|
|
2439
|
+
if (anyReplyDelivered) failurePolicy.recordDelivered();
|
|
2432
2440
|
if (dispatchError || agentRunFailed) await progress.finalizeDraftProgressCard("error", { postIfMissing: !anyReplyDelivered });
|
|
2433
2441
|
await progress.dropDetachedProgressCards();
|
|
2434
2442
|
if (statusReactionsEnabled) {
|
|
@@ -2448,15 +2456,9 @@ async function dispatchSlackMessageWithSetup(setup, beginSessionRun, turnAdoptio
|
|
|
2448
2456
|
if (dispatchError) throw toErrorObject(dispatchError, "Slack dispatch failed");
|
|
2449
2457
|
if (!anyReplyDelivered && !previewLifecycle.previewFinalized && !(agentRunFailed && progress.useDraftProgressCard)) {
|
|
2450
2458
|
if (progress.useDraftProgressCard) await draftStream?.clear();
|
|
2451
|
-
return;
|
|
2452
|
-
}
|
|
2453
|
-
if (shouldLogVerbose()) {
|
|
2454
|
-
const finalCount = resolveInboundReplyDispatchCounts(settledDispatchResult).final;
|
|
2455
|
-
logVerbose(`slack: delivered ${finalCount} repl${finalCount === 1 ? "y" : "ies"} to ${prepared.replyTarget}`);
|
|
2456
2459
|
}
|
|
2457
2460
|
}
|
|
2458
|
-
|
|
2459
|
-
//#region extensions/slack/src/agent-context.ts
|
|
2461
|
+
// extensions/slack/src/agent-context.ts
|
|
2460
2462
|
function normalizeEntity(value) {
|
|
2461
2463
|
const entity = asOptionalRecord(value);
|
|
2462
2464
|
const type = normalizeOptionalString(entity?.type);
|
|
@@ -2494,15 +2496,13 @@ function normalizeSlackAppContextEntities(value) {
|
|
|
2494
2496
|
return normalized ? [normalized] : [];
|
|
2495
2497
|
});
|
|
2496
2498
|
}
|
|
2497
|
-
|
|
2498
|
-
|
|
2499
|
-
|
|
2500
|
-
|
|
2501
|
-
|
|
2502
|
-
|
|
2503
|
-
|
|
2504
|
-
pruneMapToMaxSize(THREAD_STARTER_CACHE, THREAD_STARTER_CACHE_MAX);
|
|
2505
|
-
}
|
|
2499
|
+
// extensions/slack/src/monitor/thread.ts
|
|
2500
|
+
const threadStarterCache = createStaleWhileRevalidateCache({
|
|
2501
|
+
maxEntries: 2e3,
|
|
2502
|
+
maxPending: Number.POSITIVE_INFINITY,
|
|
2503
|
+
ttlMs: 216e5,
|
|
2504
|
+
cacheable: (starter) => starter !== null
|
|
2505
|
+
});
|
|
2506
2506
|
function formatSlackFilePlaceholder(files) {
|
|
2507
2507
|
return `[attached: ${formatSlackFileReferenceList(files)}]`;
|
|
2508
2508
|
}
|
|
@@ -2537,40 +2537,35 @@ function resolveSlackMessageText(message) {
|
|
|
2537
2537
|
}, { preserveMessageTextWhitespace: true });
|
|
2538
2538
|
}
|
|
2539
2539
|
async function resolveSlackThreadStarter(params) {
|
|
2540
|
-
evictThreadStarterCache();
|
|
2541
2540
|
const cacheKey = JSON.stringify([
|
|
2542
2541
|
params.workspaceScope.accountId,
|
|
2543
2542
|
params.workspaceScope.teamId,
|
|
2544
2543
|
params.channelId,
|
|
2545
2544
|
params.threadTs
|
|
2546
2545
|
]);
|
|
2547
|
-
const cached = THREAD_STARTER_CACHE.get(cacheKey);
|
|
2548
|
-
if (cached && !params.refresh) return cached.value;
|
|
2549
|
-
if (params.refresh) THREAD_STARTER_CACHE.delete(cacheKey);
|
|
2550
2546
|
try {
|
|
2551
|
-
const
|
|
2552
|
-
|
|
2553
|
-
|
|
2554
|
-
|
|
2555
|
-
|
|
2556
|
-
|
|
2557
|
-
|
|
2558
|
-
|
|
2559
|
-
|
|
2560
|
-
|
|
2561
|
-
|
|
2562
|
-
|
|
2563
|
-
|
|
2564
|
-
|
|
2565
|
-
|
|
2566
|
-
|
|
2567
|
-
|
|
2568
|
-
|
|
2569
|
-
|
|
2570
|
-
|
|
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
|
|
2571
2567
|
});
|
|
2572
|
-
|
|
2573
|
-
return starter;
|
|
2568
|
+
return value;
|
|
2574
2569
|
} catch (err) {
|
|
2575
2570
|
logVerbose(`slack thread starter fetch failed channel=${params.channelId} ts=${params.threadTs}: ${formatErrorMessage(err)}`);
|
|
2576
2571
|
return null;
|
|
@@ -2624,8 +2619,7 @@ async function resolveSlackThreadHistory(params) {
|
|
|
2624
2619
|
retained.push([msg, text]);
|
|
2625
2620
|
}
|
|
2626
2621
|
if (retained.length > maxMessages) retained.splice(0, retained.length - maxMessages);
|
|
2627
|
-
|
|
2628
|
-
cursor = typeof next === "string" && next.trim().length > 0 ? next.trim() : void 0;
|
|
2622
|
+
cursor = normalizeOptionalString(response.response_metadata?.next_cursor);
|
|
2629
2623
|
if (response.has_more && !cursor) {
|
|
2630
2624
|
params.onOmission?.("Slack returned an incomplete thread page without a cursor");
|
|
2631
2625
|
return [];
|
|
@@ -2674,10 +2668,9 @@ async function resolveSlackChannelHistory(params) {
|
|
|
2674
2668
|
cursor = response.response_metadata?.next_cursor?.trim() || void 0;
|
|
2675
2669
|
if (!cursor || scanned >= params.limit) break;
|
|
2676
2670
|
}
|
|
2677
|
-
return messages.slice(0, params.limit).
|
|
2671
|
+
return messages.slice(0, params.limit).reverse();
|
|
2678
2672
|
}
|
|
2679
|
-
|
|
2680
|
-
//#region extensions/slack/src/monitor/message-handler/preflight-audio.ts
|
|
2673
|
+
// extensions/slack/src/monitor/message-handler/preflight-audio.ts
|
|
2681
2674
|
function isSlackAudioFile(file) {
|
|
2682
2675
|
if (file.subtype === "slack_audio") return true;
|
|
2683
2676
|
if ((file.mimetype?.split(";")[0]?.trim().toLowerCase())?.startsWith("audio/")) return true;
|
|
@@ -2720,13 +2713,12 @@ const sendSlackPreflightAudioTranscriptEcho = slackPreflightAudio.send.bind(slac
|
|
|
2720
2713
|
async function discardSlackPreflightMedia(media) {
|
|
2721
2714
|
await Promise.allSettled((media ?? []).map((entry) => fs.rm(entry.path, { force: true })));
|
|
2722
2715
|
}
|
|
2723
|
-
|
|
2724
|
-
//#region extensions/slack/src/monitor/message-handler/prepare-content.ts
|
|
2716
|
+
// extensions/slack/src/monitor/message-handler/prepare-content.ts
|
|
2725
2717
|
const SLACK_MENTION_RESOLUTION_CONCURRENCY = 4;
|
|
2726
2718
|
const SLACK_MENTION_RESOLUTION_MAX_LOOKUPS_PER_MESSAGE = 20;
|
|
2727
2719
|
const SLACK_USER_MENTION_RE$1 = /<@([A-Z0-9]+)(?:\|[^>]+)?>/gi;
|
|
2728
2720
|
const MAX_SLACK_UNAVAILABLE_FILE_TEXT_CHARS = 2e3;
|
|
2729
|
-
const loadSlackMediaModule$
|
|
2721
|
+
const loadSlackMediaModule$2 = createLazyRuntimeModule(() => import("./actions-s3CcFO45.mjs").then((n) => n._));
|
|
2730
2722
|
function formatSlackUnavailableMedia(params) {
|
|
2731
2723
|
let fileReferences = params.files?.map((file) => `${formatSlackFileReference(file)} unavailable (${file.reason})`).join(", ");
|
|
2732
2724
|
if (fileReferences && fileReferences.length > MAX_SLACK_UNAVAILABLE_FILE_TEXT_CHARS) fileReferences = `${truncateUtf16Safe(fileReferences, MAX_SLACK_UNAVAILABLE_FILE_TEXT_CHARS)}; … (file references truncated)`;
|
|
@@ -2747,7 +2739,6 @@ function collectUniqueSlackMentionIds(texts) {
|
|
|
2747
2739
|
const seen = /* @__PURE__ */ new Set();
|
|
2748
2740
|
for (const text of texts) {
|
|
2749
2741
|
if (!text) continue;
|
|
2750
|
-
SLACK_USER_MENTION_RE$1.lastIndex = 0;
|
|
2751
2742
|
for (const match of text.matchAll(SLACK_USER_MENTION_RE$1)) {
|
|
2752
2743
|
const userId = match[1];
|
|
2753
2744
|
if (userId) seen.add(userId);
|
|
@@ -2757,35 +2748,24 @@ function collectUniqueSlackMentionIds(texts) {
|
|
|
2757
2748
|
}
|
|
2758
2749
|
function renderSlackUserMentions(text, renderedMentions) {
|
|
2759
2750
|
if (!text || renderedMentions.size === 0) return text;
|
|
2760
|
-
SLACK_USER_MENTION_RE$1.lastIndex = 0;
|
|
2761
2751
|
return text.replace(SLACK_USER_MENTION_RE$1, (full, userId) => {
|
|
2762
2752
|
return renderedMentions.get(userId) ?? full;
|
|
2763
2753
|
});
|
|
2764
2754
|
}
|
|
2765
|
-
function filterInheritedParentFiles(params) {
|
|
2766
|
-
const { files, isThreadReply, threadStarter } = params;
|
|
2767
|
-
if (!isThreadReply || !files?.length || !threadStarter?.files?.length) return files;
|
|
2768
|
-
const starterFileIds = new Set(threadStarter.files.map((file) => file.id));
|
|
2769
|
-
const filtered = files.filter((file) => !file.id || !starterFileIds.has(file.id));
|
|
2770
|
-
if (filtered.length < files.length) logVerbose(`slack: filtered ${files.length - filtered.length} inherited parent file(s) from thread reply`);
|
|
2771
|
-
return filtered.length > 0 ? filtered : void 0;
|
|
2772
|
-
}
|
|
2773
2755
|
async function resolveSlackMessageContent(params) {
|
|
2774
|
-
|
|
2775
|
-
|
|
2776
|
-
|
|
2777
|
-
threadStarter
|
|
2778
|
-
|
|
2779
|
-
|
|
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({
|
|
2780
2764
|
files: ownFiles,
|
|
2781
2765
|
attachments: params.message.attachments,
|
|
2782
2766
|
client: params.client,
|
|
2783
2767
|
token: params.botToken,
|
|
2784
2768
|
maxBytes: params.mediaMaxBytes,
|
|
2785
|
-
readIdleTimeoutMs: params.mediaReadIdleTimeoutMs,
|
|
2786
|
-
totalTimeoutMs: params.mediaTotalTimeoutMs,
|
|
2787
|
-
abortSignal: params.abortSignal,
|
|
2788
|
-
assertCurrent: params.assertCurrent,
|
|
2789
2769
|
preloadedMedia: params.preloadedMedia
|
|
2790
2770
|
})) : null;
|
|
2791
2771
|
const effectiveDirectMedia = attachmentContent?.media.length ? attachmentContent.media : null;
|
|
@@ -2834,14 +2814,13 @@ async function resolveSlackMessageContent(params) {
|
|
|
2834
2814
|
mentionStripPatterns
|
|
2835
2815
|
} : null;
|
|
2836
2816
|
}
|
|
2837
|
-
|
|
2838
|
-
//#region extensions/slack/src/monitor/message-handler/prepare-dm-history.ts
|
|
2817
|
+
// extensions/slack/src/monitor/message-handler/prepare-dm-history.ts
|
|
2839
2818
|
function resolveSlackDmHistoryLimit(params) {
|
|
2840
2819
|
const override = params.userId ? params.account.config.dms?.[params.userId]?.historyLimit : void 0;
|
|
2841
2820
|
return resolvePromptHistoryLimit(override ?? params.defaultLimit, 0);
|
|
2842
2821
|
}
|
|
2843
2822
|
async function resolveSlackDmHistoryContext(params) {
|
|
2844
|
-
const maxMessages =
|
|
2823
|
+
const maxMessages = params.limit;
|
|
2845
2824
|
if (maxMessages <= 0) return {
|
|
2846
2825
|
body: void 0,
|
|
2847
2826
|
inboundHistory: void 0
|
|
@@ -2862,7 +2841,7 @@ async function resolveSlackDmHistoryContext(params) {
|
|
|
2862
2841
|
message,
|
|
2863
2842
|
body
|
|
2864
2843
|
}] : [];
|
|
2865
|
-
}).slice(0, maxMessages).
|
|
2844
|
+
}).slice(0, maxMessages).reverse();
|
|
2866
2845
|
if (messages.length === 0) return {
|
|
2867
2846
|
body: void 0,
|
|
2868
2847
|
inboundHistory: void 0
|
|
@@ -2908,20 +2887,19 @@ async function resolveSlackDmHistoryContext(params) {
|
|
|
2908
2887
|
};
|
|
2909
2888
|
}
|
|
2910
2889
|
}
|
|
2911
|
-
|
|
2912
|
-
//#region extensions/slack/src/monitor/message-handler/prepare-thread-context-root.ts
|
|
2890
|
+
// extensions/slack/src/monitor/message-handler/prepare-thread-context-root.ts
|
|
2913
2891
|
function isSlackThreadAuthorCurrentBot(params) {
|
|
2914
2892
|
const { identity, author } = params;
|
|
2915
2893
|
if (identity.botUserId && author.userId && author.userId === identity.botUserId) return true;
|
|
2916
2894
|
if (identity.botId && author.botId && author.botId === identity.botId) return true;
|
|
2917
2895
|
return false;
|
|
2918
2896
|
}
|
|
2919
|
-
|
|
2920
|
-
//#region extensions/slack/src/monitor/message-handler/prepare-room-history.ts
|
|
2897
|
+
// extensions/slack/src/monitor/message-handler/prepare-room-history.ts
|
|
2921
2898
|
const SLACK_HISTORY_MEDIA_MAX_ATTACHMENTS = 4;
|
|
2922
2899
|
const SLACK_HISTORY_MEDIA_MAX_BYTES = 10485760;
|
|
2923
2900
|
const SLACK_HISTORY_MEDIA_IDLE_TIMEOUT_MS = 1e3;
|
|
2924
2901
|
const SLACK_HISTORY_MEDIA_TOTAL_TIMEOUT_MS = 3e3;
|
|
2902
|
+
const loadSlackMediaModule$1 = createLazyRuntimeModule(() => import("./actions-s3CcFO45.mjs").then((n) => n._));
|
|
2925
2903
|
async function resolveSlackRoomHistory(params) {
|
|
2926
2904
|
if (params.ctx.historyLimit <= 0 || !params.message.ts) return [];
|
|
2927
2905
|
const warnOmission = (reason) => {
|
|
@@ -2975,26 +2953,51 @@ async function resolveSlackRoomHistory(params) {
|
|
|
2975
2953
|
sender: user?.name ?? message.userId ?? `Bot (${message.botId ?? "unknown"})`
|
|
2976
2954
|
});
|
|
2977
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
|
+
}
|
|
2978
2997
|
const entries = [];
|
|
2979
2998
|
let mediaRemaining = SLACK_HISTORY_MEDIA_MAX_ATTACHMENTS;
|
|
2980
2999
|
for (const { message, sender } of permitted.slice(-params.ctx.historyLimit)) {
|
|
2981
|
-
const { media, attempted } = mediaRemaining > 0 && (message.files?.length || message.attachments?.length) ? await resolveSlackHistoryMedia({
|
|
2982
|
-
ctx: params.ctx,
|
|
2983
|
-
eventScope: params.eventScope,
|
|
2984
|
-
maxAttachments: mediaRemaining,
|
|
2985
|
-
assertCurrent: params.assertCurrent,
|
|
2986
|
-
abortSignal: params.abortSignal,
|
|
2987
|
-
message: {
|
|
2988
|
-
type: "message",
|
|
2989
|
-
channel: params.message.channel,
|
|
2990
|
-
ts: message.ts,
|
|
2991
|
-
user: message.userId,
|
|
2992
|
-
bot_id: message.botId,
|
|
2993
|
-
text: message.text,
|
|
2994
|
-
files: message.files,
|
|
2995
|
-
attachments: message.attachments
|
|
2996
|
-
}
|
|
2997
|
-
}) : {
|
|
3000
|
+
const { media, attempted } = mediaRemaining > 0 && (message.files?.length || message.attachments?.length) ? await resolveSlackHistoryMedia(message, mediaRemaining) : {
|
|
2998
3001
|
media: [],
|
|
2999
3002
|
attempted: 0
|
|
3000
3003
|
};
|
|
@@ -3021,68 +3024,15 @@ function sliceSlackImageFileCandidates(files, limit) {
|
|
|
3021
3024
|
if (limit <= 0 || !files?.length) return [];
|
|
3022
3025
|
return files.filter(isSlackImageFileCandidate).slice(0, limit);
|
|
3023
3026
|
}
|
|
3024
|
-
|
|
3025
|
-
if (limit <= 0 || !attachments?.length) return [];
|
|
3026
|
-
const out = [];
|
|
3027
|
-
let remaining = limit;
|
|
3028
|
-
for (const attachment of attachments) {
|
|
3029
|
-
if (attachment.is_share !== true) continue;
|
|
3030
|
-
const hasImageUrl = Boolean(normalizeOptionalString(attachment.image_url));
|
|
3031
|
-
const files = sliceSlackImageFileCandidates(attachment.files, remaining - (hasImageUrl ? 1 : 0));
|
|
3032
|
-
if (!hasImageUrl && files.length === 0) continue;
|
|
3033
|
-
out.push({
|
|
3034
|
-
...attachment,
|
|
3035
|
-
files
|
|
3036
|
-
});
|
|
3037
|
-
remaining -= (hasImageUrl ? 1 : 0) + files.length;
|
|
3038
|
-
if (remaining <= 0) break;
|
|
3039
|
-
}
|
|
3040
|
-
return out;
|
|
3041
|
-
}
|
|
3042
|
-
async function resolveSlackHistoryMedia(params) {
|
|
3043
|
-
const files = sliceSlackImageFileCandidates(params.message.files, params.maxAttachments);
|
|
3044
|
-
const attachments = sliceSlackHistoryAttachmentCandidates(params.message.attachments, Math.max(0, params.maxAttachments - files.length));
|
|
3045
|
-
if (files.length === 0 && attachments.length === 0) return {
|
|
3046
|
-
media: [],
|
|
3047
|
-
attempted: 0
|
|
3048
|
-
};
|
|
3049
|
-
const attempted = files.length + attachments.reduce((count, attachment) => count + (normalizeOptionalString(attachment.image_url) ? 1 : 0) + (attachment.files?.length ?? 0), 0);
|
|
3050
|
-
const content = await resolveSlackMessageContent({
|
|
3051
|
-
message: {
|
|
3052
|
-
...params.message,
|
|
3053
|
-
files,
|
|
3054
|
-
attachments
|
|
3055
|
-
},
|
|
3056
|
-
isThreadReply: false,
|
|
3057
|
-
threadStarter: null,
|
|
3058
|
-
isBotMessage: Boolean(params.message.bot_id),
|
|
3059
|
-
client: params.eventScope?.client ?? params.ctx.app.client,
|
|
3060
|
-
botToken: params.ctx.botToken,
|
|
3061
|
-
mediaMaxBytes: Math.min(params.ctx.mediaMaxBytes, SLACK_HISTORY_MEDIA_MAX_BYTES),
|
|
3062
|
-
mediaReadIdleTimeoutMs: SLACK_HISTORY_MEDIA_IDLE_TIMEOUT_MS,
|
|
3063
|
-
mediaTotalTimeoutMs: SLACK_HISTORY_MEDIA_TOTAL_TIMEOUT_MS,
|
|
3064
|
-
assertCurrent: params.assertCurrent,
|
|
3065
|
-
abortSignal: params.abortSignal
|
|
3066
|
-
});
|
|
3067
|
-
return {
|
|
3068
|
-
media: await toInboundMediaFactsWithMetadata(content?.effectiveDirectMedia, {
|
|
3069
|
-
kind: "image",
|
|
3070
|
-
messageId: params.message.ts
|
|
3071
|
-
}),
|
|
3072
|
-
attempted
|
|
3073
|
-
};
|
|
3074
|
-
}
|
|
3075
|
-
//#endregion
|
|
3076
|
-
//#region extensions/slack/src/monitor/message-handler/prepare-session-presentation.ts
|
|
3027
|
+
// extensions/slack/src/monitor/message-handler/prepare-session-presentation.ts
|
|
3077
3028
|
function resolveSlackGroupSessionSubject(params) {
|
|
3078
3029
|
const channelName = normalizeOptionalString(params.channelName);
|
|
3079
3030
|
const workspaceName = normalizeOptionalString(params.installationIdentity?.kind === "workspace" && params.installationIdentity.teamId === params.workspaceId ? params.installationIdentity.teamName : void 0);
|
|
3080
3031
|
if (channelName && workspaceName) return `${workspaceName} #${channelName}`;
|
|
3081
3032
|
return `Slack Channel (Workspace ID: ${params.workspaceId}, Channel ID: ${params.channelId})`;
|
|
3082
3033
|
}
|
|
3083
|
-
|
|
3084
|
-
|
|
3085
|
-
const loadSlackMediaModule = createLazyRuntimeModule(() => import("./actions-By7tvpvv.mjs").then((n) => n._));
|
|
3034
|
+
// extensions/slack/src/monitor/message-handler/prepare-thread-context.ts
|
|
3035
|
+
const loadSlackMediaModule = createLazyRuntimeModule(() => import("./actions-s3CcFO45.mjs").then((n) => n._));
|
|
3086
3036
|
const SLACK_THREAD_CONTEXT_USER_LOOKUP_CONCURRENCY = 4;
|
|
3087
3037
|
function formatSlackThreadLabelSnippet(text) {
|
|
3088
3038
|
return truncateUtf16Safe(text.replace(/\s+/g, " "), 80);
|
|
@@ -3131,13 +3081,14 @@ async function resolveSlackThreadContextData(params) {
|
|
|
3131
3081
|
const isOutboundOnlyThreadSession = threadSessionFreshness !== void 0 && threadSessionFreshness.state !== "missing" && threadSessionFreshness.entry.lastInteractionAt === void 0 && threadSessionFreshness.entry.updatedAt !== 0;
|
|
3132
3082
|
const shouldSeedInitialThreadContext = Boolean(params.isThreadReply && params.threadTs && (threadSessionFreshness ? threadSessionFreshness.state !== "fresh" || isOutboundOnlyThreadSession : threadSessionPreviousTimestamp === void 0));
|
|
3133
3083
|
const shouldLoadInitialThreadHistory = shouldSeedInitialThreadContext || params.forceInitialHistory === true;
|
|
3134
|
-
|
|
3084
|
+
const readThreadContextData = () => ({
|
|
3135
3085
|
threadStarterBody,
|
|
3136
3086
|
threadHistoryBody,
|
|
3137
3087
|
shouldSeedInitialThreadContext,
|
|
3138
3088
|
threadLabel,
|
|
3139
3089
|
threadStarterMedia
|
|
3140
|
-
};
|
|
3090
|
+
});
|
|
3091
|
+
if (!params.isThreadReply || !params.threadTs) return readThreadContextData();
|
|
3141
3092
|
const starter = params.threadStarter;
|
|
3142
3093
|
const starterSenderName = params.allowNameMatching && params.allowFromLower.length > 0 && starter?.userId ? (await params.ctx.resolveUserName(starter.userId, params.eventScope))?.name : void 0;
|
|
3143
3094
|
params.assertHistoryCurrent?.();
|
|
@@ -3177,10 +3128,6 @@ async function resolveSlackThreadContextData(params) {
|
|
|
3177
3128
|
unavailableMediaCount: attachmentContent.unavailableMediaCount,
|
|
3178
3129
|
prependUnavailable: true
|
|
3179
3130
|
});
|
|
3180
|
-
if (threadStarterMedia) {
|
|
3181
|
-
const starterPlaceholders = threadStarterMedia.map((item) => item.placeholder).join(", ");
|
|
3182
|
-
logVerbose(`slack: hydrated thread starter file ${starterPlaceholders} from root message`);
|
|
3183
|
-
}
|
|
3184
3131
|
}
|
|
3185
3132
|
} else threadLabel = `Slack thread ${params.roomLabel}`;
|
|
3186
3133
|
const includeBotStarterAsRootContext = Boolean(starter?.text && starterIsCurrentBot && shouldSeedInitialThreadContext);
|
|
@@ -3189,7 +3136,6 @@ async function resolveSlackThreadContextData(params) {
|
|
|
3189
3136
|
else if (includeBotStarterAsRootContext) {
|
|
3190
3137
|
const snippet = formatSlackThreadLabelSnippet(starter?.text ?? "").trim();
|
|
3191
3138
|
threadLabel = `Slack thread ${params.roomLabel}${snippet ? ` (assistant root): ${snippet}` : ""}`;
|
|
3192
|
-
logVerbose("slack: retained current-bot thread starter as assistant root context");
|
|
3193
3139
|
}
|
|
3194
3140
|
const threadInitialHistoryLimit = Math.min(params.account.config?.thread?.initialHistoryLimit ?? 20, params.historyLimit ?? Number.POSITIVE_INFINITY);
|
|
3195
3141
|
if (threadInitialHistoryLimit > 0 && shouldLoadInitialThreadHistory) {
|
|
@@ -3214,28 +3160,22 @@ async function resolveSlackThreadContextData(params) {
|
|
|
3214
3160
|
}, "Slack automatic thread history omitted");
|
|
3215
3161
|
}
|
|
3216
3162
|
});
|
|
3217
|
-
if (historyOmitted) return
|
|
3218
|
-
threadStarterBody,
|
|
3219
|
-
threadHistoryBody,
|
|
3220
|
-
shouldSeedInitialThreadContext,
|
|
3221
|
-
threadLabel,
|
|
3222
|
-
threadStarterMedia
|
|
3223
|
-
};
|
|
3163
|
+
if (historyOmitted) return readThreadContextData();
|
|
3224
3164
|
const enrichedStarter = starter && threadStarterBody && threadStarterBody !== starter.text ? {
|
|
3225
3165
|
...starter,
|
|
3226
3166
|
text: threadStarterBody,
|
|
3227
3167
|
ts: currentBotRootTs
|
|
3228
3168
|
} : null;
|
|
3229
|
-
const
|
|
3230
|
-
const threadHistoryWithBotRoot = includeBotStarterAsRootContext && starter && !threadHistoryWithEnrichedRoot.some((entry) => entry.ts === currentBotRootTs) ? [{
|
|
3169
|
+
const rootContext = enrichedStarter ?? (includeBotStarterAsRootContext && starter ? {
|
|
3231
3170
|
...starter,
|
|
3232
3171
|
ts: currentBotRootTs
|
|
3233
|
-
}
|
|
3234
|
-
|
|
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) {
|
|
3235
3175
|
const retainCurrentBotHistory = params.isGroupDm && (isMissingThreadSession || isOutboundOnlyThreadSession);
|
|
3236
|
-
const threadHistoryWithoutCurrentBot =
|
|
3237
|
-
const omittedCurrentBotHistoryCount =
|
|
3238
|
-
const userMapForFilter = params.contextVisibilityMode !== "all" && params.allowNameMatching && params.allowFromLower.length > 0 ? await resolveThreadUserMap(threadHistoryWithoutCurrentBot) :
|
|
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;
|
|
3239
3179
|
params.assertHistoryCurrent?.();
|
|
3240
3180
|
const { items: filteredThreadHistory, omitted: omittedHistoryCount } = params.contextVisibilityMode === "all" ? {
|
|
3241
3181
|
items: threadHistoryWithoutCurrentBot,
|
|
@@ -3246,7 +3186,7 @@ async function resolveSlackThreadContextData(params) {
|
|
|
3246
3186
|
kind: "thread",
|
|
3247
3187
|
isSenderAllowed: (historyMsg) => {
|
|
3248
3188
|
if (isCurrentBotAuthor(historyMsg)) return true;
|
|
3249
|
-
const msgUser = historyMsg.userId ? userMapForFilter
|
|
3189
|
+
const msgUser = historyMsg.userId ? userMapForFilter?.get(historyMsg.userId) : null;
|
|
3250
3190
|
return resolveSlackUserAllowed({
|
|
3251
3191
|
allowList: params.allowFromLower,
|
|
3252
3192
|
teamId: params.eventScope?.teamId ?? params.ctx.teamId,
|
|
@@ -3256,7 +3196,7 @@ async function resolveSlackThreadContextData(params) {
|
|
|
3256
3196
|
});
|
|
3257
3197
|
}
|
|
3258
3198
|
});
|
|
3259
|
-
const userMap = await resolveThreadUserMap(filteredThreadHistory);
|
|
3199
|
+
const userMap = userMapForFilter ?? await resolveThreadUserMap(filteredThreadHistory);
|
|
3260
3200
|
params.assertHistoryCurrent?.();
|
|
3261
3201
|
if (omittedHistoryCount > 0 || omittedCurrentBotHistoryCount > 0) logVerbose(`slack: omitted ${omittedHistoryCount + omittedCurrentBotHistoryCount} thread message(s) from context (mode=${params.contextVisibilityMode})`);
|
|
3262
3202
|
const historyParts = [];
|
|
@@ -3275,22 +3215,12 @@ async function resolveSlackThreadContextData(params) {
|
|
|
3275
3215
|
envelope: params.envelopeOptions
|
|
3276
3216
|
}));
|
|
3277
3217
|
}
|
|
3278
|
-
if (historyParts.length > 0)
|
|
3279
|
-
threadHistoryBody = historyParts.join("\n\n");
|
|
3280
|
-
logVerbose(`slack: populated thread history with ${filteredThreadHistory.length} messages for new session`);
|
|
3281
|
-
}
|
|
3218
|
+
if (historyParts.length > 0) threadHistoryBody = historyParts.join("\n\n");
|
|
3282
3219
|
}
|
|
3283
3220
|
}
|
|
3284
|
-
return
|
|
3285
|
-
threadStarterBody,
|
|
3286
|
-
threadHistoryBody,
|
|
3287
|
-
shouldSeedInitialThreadContext,
|
|
3288
|
-
threadLabel,
|
|
3289
|
-
threadStarterMedia
|
|
3290
|
-
};
|
|
3221
|
+
return readThreadContextData();
|
|
3291
3222
|
}
|
|
3292
|
-
|
|
3293
|
-
//#region src/channels/mention-gating.ts
|
|
3223
|
+
// src/channels/mention-gating.ts
|
|
3294
3224
|
function resolveBotThreadMentionPolicy(params) {
|
|
3295
3225
|
if (!params.isBotOwnedThread || params.requireMentionInBotThreads === void 0) return {
|
|
3296
3226
|
requireMention: params.requireMention,
|
|
@@ -3301,13 +3231,11 @@ function resolveBotThreadMentionPolicy(params) {
|
|
|
3301
3231
|
implicitMentionKinds: params.requireMentionInBotThreads ? params.implicitMentionKinds?.filter((kind) => kind === "native") : params.implicitMentionKinds
|
|
3302
3232
|
};
|
|
3303
3233
|
}
|
|
3304
|
-
|
|
3305
|
-
//#region \0openclaw:bundled-sdk:openclaw/plugin-sdk/channel-mention-gating
|
|
3234
|
+
// \0openclaw:bundled-sdk:openclaw/plugin-sdk/channel-mention-gating
|
|
3306
3235
|
var channel_mention_gating_exports = /* @__PURE__ */ __exportAll({ resolveBotThreadMentionPolicy: () => resolveBotThreadMentionPolicy });
|
|
3307
3236
|
import * as import_openclaw_plugin_sdk_channel_mention_gating from "openclaw/plugin-sdk/channel-mention-gating";
|
|
3308
3237
|
__reExport(channel_mention_gating_exports, import_openclaw_plugin_sdk_channel_mention_gating);
|
|
3309
|
-
|
|
3310
|
-
//#region extensions/slack/src/monitor/message-handler/prepare-thread-mentions.ts
|
|
3238
|
+
// extensions/slack/src/monitor/message-handler/prepare-thread-mentions.ts
|
|
3311
3239
|
async function resolveSlackThreadMentionPolicy(params) {
|
|
3312
3240
|
const { ctx, account, message, conversation, thread } = params;
|
|
3313
3241
|
const { isRoom, isDirectMessage, channelConfig } = conversation;
|
|
@@ -3341,8 +3269,7 @@ async function resolveSlackThreadMentionPolicy(params) {
|
|
|
3341
3269
|
implicitMentionKinds
|
|
3342
3270
|
});
|
|
3343
3271
|
}
|
|
3344
|
-
|
|
3345
|
-
//#region extensions/slack/src/monitor/message-handler/subteam-mentions.ts
|
|
3272
|
+
// extensions/slack/src/monitor/message-handler/subteam-mentions.ts
|
|
3346
3273
|
const SUBTEAM_MENTION_RE = /<!subteam\^([A-Z0-9]+)(?:\|[^>]*)?>/gi;
|
|
3347
3274
|
const SUBTEAM_MEMBER_CACHE_TTL_MS = 3e5;
|
|
3348
3275
|
const subteamMemberCache = /* @__PURE__ */ new WeakMap();
|
|
@@ -3358,75 +3285,55 @@ function collectSlackMentionIds(text, regex) {
|
|
|
3358
3285
|
}
|
|
3359
3286
|
return [...ids];
|
|
3360
3287
|
}
|
|
3361
|
-
async function readSlackSubteamUsers(params) {
|
|
3362
|
-
let bySubteam = subteamMemberCache.get(params.client);
|
|
3363
|
-
if (!bySubteam) {
|
|
3364
|
-
bySubteam = /* @__PURE__ */ new Map();
|
|
3365
|
-
subteamMemberCache.set(params.client, bySubteam);
|
|
3366
|
-
}
|
|
3367
|
-
const cacheKey = `${normalizeSlackId(params.teamId) ?? ""}:${params.subteamId}`;
|
|
3368
|
-
const cached = bySubteam.get(cacheKey);
|
|
3369
|
-
const now = asDateTimestampMs(params.now);
|
|
3370
|
-
if (cached) {
|
|
3371
|
-
if (now !== void 0 && asDateTimestampMs(cached.expiresAt) !== void 0 && cached.expiresAt > now) return cached.users;
|
|
3372
|
-
bySubteam.delete(cacheKey);
|
|
3373
|
-
}
|
|
3374
|
-
try {
|
|
3375
|
-
const response = await params.client.usergroups.users.list({
|
|
3376
|
-
usergroup: params.subteamId,
|
|
3377
|
-
...params.teamId ? { team_id: params.teamId } : {}
|
|
3378
|
-
});
|
|
3379
|
-
if (!response.ok) {
|
|
3380
|
-
params.log?.(`slack: failed to resolve user-group mention ${params.subteamId}: ${response.error ?? "unknown_error"}`);
|
|
3381
|
-
return /* @__PURE__ */ new Set();
|
|
3382
|
-
}
|
|
3383
|
-
const users = new Set((response.users ?? []).map(normalizeSlackId).filter((userId) => userId !== void 0));
|
|
3384
|
-
const expiresAt = resolveExpiresAtMsFromDurationMs(SUBTEAM_MEMBER_CACHE_TTL_MS, { nowMs: params.now });
|
|
3385
|
-
if (expiresAt !== void 0) bySubteam.set(cacheKey, {
|
|
3386
|
-
expiresAt,
|
|
3387
|
-
users
|
|
3388
|
-
});
|
|
3389
|
-
return users;
|
|
3390
|
-
} catch (err) {
|
|
3391
|
-
params.log?.(`slack: failed to resolve user-group mention ${params.subteamId}: ${formatErrorMessage(err)}`);
|
|
3392
|
-
return /* @__PURE__ */ new Set();
|
|
3393
|
-
}
|
|
3394
|
-
}
|
|
3395
3288
|
async function isSlackSubteamMentionForBot(params) {
|
|
3396
3289
|
const botUserId = normalizeSlackId(params.botUserId);
|
|
3397
3290
|
if (!botUserId) return false;
|
|
3398
3291
|
const subteamIds = collectSlackMentionIds(params.text, SUBTEAM_MENTION_RE);
|
|
3399
3292
|
if (subteamIds.length === 0) return false;
|
|
3400
|
-
const now =
|
|
3401
|
-
for (const subteamId of subteamIds)
|
|
3402
|
-
client
|
|
3403
|
-
|
|
3404
|
-
|
|
3405
|
-
|
|
3406
|
-
|
|
3407
|
-
|
|
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
|
+
}
|
|
3408
3328
|
return false;
|
|
3409
3329
|
}
|
|
3410
|
-
|
|
3411
|
-
//#region extensions/slack/src/monitor/message-handler/prepare.ts
|
|
3330
|
+
// extensions/slack/src/monitor/message-handler/prepare.ts
|
|
3412
3331
|
const mentionRegexCache = /* @__PURE__ */ new WeakMap();
|
|
3413
3332
|
const SLACK_ANY_MENTION_RE = /<@[^>]+>|<!subteam\^[^>]+>/;
|
|
3414
3333
|
const SLACK_USER_MENTION_RE = /<@([^>|]+)(?:\|[^>]+)?>/g;
|
|
3415
3334
|
const SLACK_SUBTEAM_MENTION_RE = /<!subteam\^([^>|]+)(?:\|[^>]+)?>/g;
|
|
3416
3335
|
const SLACK_SUBTEAM_MENTION_MARKER = "<!subteam^";
|
|
3417
3336
|
const SLACK_CHANNEL_ACCESS_DOCS_URL = "https://docs.openclaw.ai/channels/slack#access-control-and-routing";
|
|
3418
|
-
function mergeSlackAssistantThreadContext(primary, fallback) {
|
|
3419
|
-
if (!primary) return fallback;
|
|
3420
|
-
if (!fallback) return primary;
|
|
3421
|
-
return {
|
|
3422
|
-
assistantChannelId: primary.assistantChannelId || fallback.assistantChannelId,
|
|
3423
|
-
threadTs: primary.threadTs || fallback.threadTs,
|
|
3424
|
-
userId: primary.userId ?? fallback.userId,
|
|
3425
|
-
channelId: primary.channelId ?? fallback.channelId,
|
|
3426
|
-
teamId: primary.teamId ?? fallback.teamId,
|
|
3427
|
-
enterpriseId: primary.enterpriseId !== void 0 ? primary.enterpriseId : fallback.enterpriseId
|
|
3428
|
-
};
|
|
3429
|
-
}
|
|
3430
3337
|
function hasSlackAssistantThreadMetadata(context) {
|
|
3431
3338
|
return Boolean(context?.channelId || context?.teamId || context?.enterpriseId !== void 0);
|
|
3432
3339
|
}
|
|
@@ -3440,7 +3347,6 @@ function resolveSlackMessageAssistantThreadContext(message) {
|
|
|
3440
3347
|
return {
|
|
3441
3348
|
assistantChannelId,
|
|
3442
3349
|
threadTs,
|
|
3443
|
-
userId: normalizeOptionalString(thread.user_id) ?? message.user,
|
|
3444
3350
|
channelId: normalizeOptionalString(context?.channel_id),
|
|
3445
3351
|
teamId: normalizeOptionalString(context?.team_id),
|
|
3446
3352
|
enterpriseId: context?.enterprise_id === null ? null : normalizeOptionalString(context?.enterprise_id)
|
|
@@ -3454,8 +3360,7 @@ async function restoreSlackAssistantThreadContextFromMetadata(params) {
|
|
|
3454
3360
|
return await readSlackAssistantThreadContext({
|
|
3455
3361
|
client: params.eventScope?.client ?? params.ctx.app.client,
|
|
3456
3362
|
channelId: params.message.channel,
|
|
3457
|
-
threadTs
|
|
3458
|
-
userId: params.message.user
|
|
3363
|
+
threadTs
|
|
3459
3364
|
});
|
|
3460
3365
|
} catch (err) {
|
|
3461
3366
|
logVerbose(`slack assistant context restore failed channel=${params.message.channel} ts=${threadTs}: ${formatErrorMessage(err)}`);
|
|
@@ -3468,41 +3373,40 @@ function resolveCachedMentionRegexes(ctx, agentId, options) {
|
|
|
3468
3373
|
normalizeOptionalString(options?.conversationId ?? void 0),
|
|
3469
3374
|
options?.providerPolicy ? JSON.stringify(options.providerPolicy) : ""
|
|
3470
3375
|
].join("");
|
|
3471
|
-
|
|
3472
|
-
if (!byAgent) {
|
|
3473
|
-
byAgent = /* @__PURE__ */ new Map();
|
|
3474
|
-
mentionRegexCache.set(ctx, byAgent);
|
|
3475
|
-
}
|
|
3376
|
+
const byAgent = getOrCreateWeakOwnerMap(mentionRegexCache, ctx);
|
|
3476
3377
|
const cached = byAgent.get(key);
|
|
3477
3378
|
if (cached) return cached;
|
|
3478
3379
|
const built = buildMentionRegexes(ctx.cfg, agentId, options);
|
|
3479
3380
|
byAgent.set(key, built);
|
|
3480
3381
|
return built;
|
|
3481
3382
|
}
|
|
3482
|
-
function
|
|
3483
|
-
|
|
3484
|
-
|
|
3485
|
-
|
|
3486
|
-
|
|
3487
|
-
|
|
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
|
|
3488
3402
|
};
|
|
3489
|
-
}
|
|
3490
|
-
function resolveSlackMentionSource(params) {
|
|
3491
|
-
if (params.explicitBotMention) return "explicit_bot";
|
|
3492
|
-
if (params.explicitSubteamMention) return "subteam";
|
|
3493
|
-
if (params.shouldBypassMention) return "command_bypass";
|
|
3494
|
-
if (params.wasMentioned) return "mention_pattern";
|
|
3495
|
-
if (params.matchedImplicitMentionKinds.length > 0) return "implicit_thread";
|
|
3496
|
-
return "none";
|
|
3497
|
-
}
|
|
3498
|
-
async function resolveSlackConversationContext(params) {
|
|
3499
|
-
const { ctx, account, message } = params;
|
|
3500
3403
|
const cfg = ctx.cfg;
|
|
3404
|
+
const conversationEventScope = opts.eventScope;
|
|
3501
3405
|
let channelInfo = {};
|
|
3502
3406
|
let resolvedChannelType = normalizeSlackChannelType(message.channel_type, message.channel);
|
|
3503
3407
|
if (resolvedChannelType !== "im" && message.channel_type !== "im") {
|
|
3504
|
-
channelInfo = await ctx.resolveChannelName(message.channel,
|
|
3505
|
-
resolvedChannelType = normalizeSlackChannelType(message.channel_type ?? channelInfo.type ?? ctx.recallSlackChannelType(message.channel,
|
|
3408
|
+
channelInfo = await ctx.resolveChannelName(message.channel, conversationEventScope);
|
|
3409
|
+
resolvedChannelType = normalizeSlackChannelType(message.channel_type ?? channelInfo.type ?? ctx.recallSlackChannelType(message.channel, conversationEventScope), message.channel);
|
|
3506
3410
|
}
|
|
3507
3411
|
const channelName = channelInfo.name;
|
|
3508
3412
|
const isDirectMessage = resolvedChannelType === "im";
|
|
@@ -3510,7 +3414,7 @@ async function resolveSlackConversationContext(params) {
|
|
|
3510
3414
|
const isRoom = resolvedChannelType === "channel" || resolvedChannelType === "group";
|
|
3511
3415
|
const isRoomish = isRoom || isGroupDm;
|
|
3512
3416
|
const channelConfig = isRoom ? resolveSlackChannelConfig({
|
|
3513
|
-
teamId:
|
|
3417
|
+
teamId: conversationEventScope?.teamId ?? ctx.teamId,
|
|
3514
3418
|
allowUnscoped: ctx.installationIdentity?.kind !== "enterprise",
|
|
3515
3419
|
channelId: message.channel,
|
|
3516
3420
|
channelName,
|
|
@@ -3520,22 +3424,19 @@ async function resolveSlackConversationContext(params) {
|
|
|
3520
3424
|
allowNameMatching: ctx.allowNameMatching
|
|
3521
3425
|
}) : null;
|
|
3522
3426
|
const allowBotsSetting = channelConfig?.allowBots ?? account.config?.allowBots ?? cfg.channels?.slack?.allowBots ?? true;
|
|
3523
|
-
|
|
3524
|
-
|
|
3525
|
-
|
|
3526
|
-
|
|
3527
|
-
|
|
3528
|
-
|
|
3529
|
-
|
|
3530
|
-
|
|
3531
|
-
channelConfig,
|
|
3532
|
-
allowBotsMode: allowBotsSetting === "mentions" ? "mentions" : allowBotsSetting ? "all" : "off",
|
|
3533
|
-
isBotMessage: Boolean(message.bot_id)
|
|
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)
|
|
3534
3435
|
};
|
|
3535
|
-
|
|
3536
|
-
|
|
3537
|
-
const
|
|
3538
|
-
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;
|
|
3539
3440
|
if (isBotMessage) {
|
|
3540
3441
|
if (ctx.botUserId && message.user === ctx.botUserId || ctx.botId && message.bot_id === ctx.botId) return null;
|
|
3541
3442
|
if (allowBotsMode === "off") return drop("bot-disabled");
|
|
@@ -3544,28 +3445,28 @@ async function authorizeSlackInboundMessage(params) {
|
|
|
3544
3445
|
const senderId = message.user ?? (isBotMessage ? message.bot_id : void 0);
|
|
3545
3446
|
if (!senderId) return drop("missing-sender");
|
|
3546
3447
|
if (!ctx.isChannelAllowed({
|
|
3547
|
-
teamId:
|
|
3448
|
+
teamId: authorizationEventScope?.teamId ?? ctx.teamId,
|
|
3548
3449
|
channelId: message.channel,
|
|
3549
3450
|
channelName,
|
|
3550
3451
|
channelType: resolvedChannelType
|
|
3551
3452
|
})) {
|
|
3552
|
-
if (
|
|
3453
|
+
if (isRoom && ctx.groupPolicy === "allowlist" && explicitBotMention && !isBotMessage && message.user) {
|
|
3553
3454
|
let subject = "This OpenClaw bot";
|
|
3554
3455
|
if (ctx.botUserId) try {
|
|
3555
|
-
const botIdentity = await ctx.resolveUserName(ctx.botUserId,
|
|
3456
|
+
const botIdentity = await ctx.resolveUserName(ctx.botUserId, authorizationEventScope);
|
|
3556
3457
|
const botName = normalizeOptionalString(botIdentity?.name);
|
|
3557
3458
|
if (botName) subject = escapeSlackMrkdwn(botName);
|
|
3558
3459
|
} catch (error) {
|
|
3559
3460
|
logVerbose(`slack allowlist denial bot-name lookup failed: ${formatSlackError(error)}`);
|
|
3560
3461
|
}
|
|
3561
3462
|
try {
|
|
3562
|
-
await (
|
|
3463
|
+
await (authorizationEventScope?.client ?? ctx.app.client).chat.postEphemeral({
|
|
3563
3464
|
token: ctx.botToken,
|
|
3564
3465
|
channel: message.channel,
|
|
3565
3466
|
user: message.user,
|
|
3566
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.>`
|
|
3567
3468
|
});
|
|
3568
|
-
|
|
3469
|
+
onVisibleDrop?.();
|
|
3569
3470
|
} catch (error) {
|
|
3570
3471
|
ctx.runtime.error?.(`slack allowlist denial notice failed for channel ${message.channel}: ${formatSlackError(error)}`);
|
|
3571
3472
|
}
|
|
@@ -3574,7 +3475,7 @@ async function authorizeSlackInboundMessage(params) {
|
|
|
3574
3475
|
}
|
|
3575
3476
|
const allowFromLower = await resolveSlackEffectiveAllowFrom(ctx, {
|
|
3576
3477
|
includePairingStore: isDirectMessage,
|
|
3577
|
-
eventScope:
|
|
3478
|
+
eventScope: authorizationEventScope
|
|
3578
3479
|
});
|
|
3579
3480
|
if (isDirectMessage) {
|
|
3580
3481
|
const directUserId = message.user;
|
|
@@ -3584,16 +3485,16 @@ async function authorizeSlackInboundMessage(params) {
|
|
|
3584
3485
|
ctx,
|
|
3585
3486
|
accountId: account.accountId,
|
|
3586
3487
|
senderId: directUserId,
|
|
3587
|
-
eventScope:
|
|
3488
|
+
eventScope: authorizationEventScope,
|
|
3588
3489
|
allowFromLower,
|
|
3589
|
-
resolveSenderName: (userId) => ctx.resolveUserName(userId,
|
|
3490
|
+
resolveSenderName: (userId) => ctx.resolveUserName(userId, authorizationEventScope),
|
|
3590
3491
|
sendPairingReply: async (text) => {
|
|
3591
3492
|
await sendMessageSlack(message.channel, text, {
|
|
3592
3493
|
cfg: ctx.cfg,
|
|
3593
3494
|
token: ctx.botToken,
|
|
3594
|
-
client:
|
|
3495
|
+
client: authorizationEventScope?.client ?? ctx.app.client,
|
|
3595
3496
|
accountId: account.accountId,
|
|
3596
|
-
eventScope:
|
|
3497
|
+
eventScope: authorizationEventScope
|
|
3597
3498
|
});
|
|
3598
3499
|
},
|
|
3599
3500
|
onDisabled: () => {
|
|
@@ -3605,54 +3506,6 @@ async function authorizeSlackInboundMessage(params) {
|
|
|
3605
3506
|
log: logVerbose
|
|
3606
3507
|
})) return drop(dropReason);
|
|
3607
3508
|
}
|
|
3608
|
-
return {
|
|
3609
|
-
senderId,
|
|
3610
|
-
allowFromLower
|
|
3611
|
-
};
|
|
3612
|
-
}
|
|
3613
|
-
async function prepareSlackMessage(params) {
|
|
3614
|
-
const { ctx, account, message, opts } = params;
|
|
3615
|
-
const drop = (reason, parentUserId) => {
|
|
3616
|
-
ctx.logger.info({
|
|
3617
|
-
provider: "slack",
|
|
3618
|
-
accountId: account.accountId,
|
|
3619
|
-
teamId: opts.eventScope?.teamId ?? ctx.teamId,
|
|
3620
|
-
channelId: message.channel,
|
|
3621
|
-
messageTs: message.ts,
|
|
3622
|
-
source: opts.source,
|
|
3623
|
-
reason,
|
|
3624
|
-
...parentUserId ? { parentUserId } : {}
|
|
3625
|
-
}, "Slack inbound event rejected during preparation");
|
|
3626
|
-
return null;
|
|
3627
|
-
};
|
|
3628
|
-
const slackClient = opts.eventScope?.client ?? ctx.app.client;
|
|
3629
|
-
const threadStarterWorkspaceScope = {
|
|
3630
|
-
accountId: account.accountId,
|
|
3631
|
-
teamId: opts.eventScope?.teamId ?? ctx.teamId
|
|
3632
|
-
};
|
|
3633
|
-
const cfg = ctx.cfg;
|
|
3634
|
-
const conversation = await resolveSlackConversationContext({
|
|
3635
|
-
ctx,
|
|
3636
|
-
account,
|
|
3637
|
-
message,
|
|
3638
|
-
eventScope: opts.eventScope
|
|
3639
|
-
});
|
|
3640
|
-
const { channelInfo, channelName, isDirectMessage, isGroupDm, isRoom, isRoomish, channelConfig, allowBotsMode, isBotMessage } = conversation;
|
|
3641
|
-
const messageText = message.text ?? "";
|
|
3642
|
-
const mentionMetadata = collectSlackMentionMetadata(messageText);
|
|
3643
|
-
const normalizedBotUserId = normalizeSlackId(ctx.botUserId);
|
|
3644
|
-
const authorization = await authorizeSlackInboundMessage({
|
|
3645
|
-
ctx,
|
|
3646
|
-
account,
|
|
3647
|
-
message,
|
|
3648
|
-
conversation,
|
|
3649
|
-
explicitBotMention: opts.source === "app_mention" || Boolean(normalizedBotUserId && mentionMetadata.mentionedUserIds.includes(normalizedBotUserId)),
|
|
3650
|
-
eventScope: opts.eventScope,
|
|
3651
|
-
onVisibleDrop: opts.onVisibleDrop,
|
|
3652
|
-
drop
|
|
3653
|
-
});
|
|
3654
|
-
if (!authorization) return null;
|
|
3655
|
-
const { senderId, allowFromLower } = authorization;
|
|
3656
3509
|
let resolvedSenderName = normalizeOptionalString(message.username);
|
|
3657
3510
|
const resolveSenderName = async () => {
|
|
3658
3511
|
if (resolvedSenderName) return resolvedSenderName;
|
|
@@ -3688,9 +3541,17 @@ async function prepareSlackMessage(params) {
|
|
|
3688
3541
|
});
|
|
3689
3542
|
const explicitlyMentioned = explicitlyMentionedBotUser || explicitlyMentionedBotSubteam || opts.source === "app_mention";
|
|
3690
3543
|
const channelRequireMention = channelConfig?.requireMention ?? ctx.defaultRequireMention ?? true;
|
|
3691
|
-
const chatType = resolveSlackChatType(
|
|
3544
|
+
const chatType = resolveSlackChatType(resolvedChannelType);
|
|
3692
3545
|
const restoredAssistantThreadContext = await restoredAssistantThreadContextPromise;
|
|
3693
|
-
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
|
+
};
|
|
3694
3555
|
const assistantThreadContextToCache = messageAssistantThreadContext || restoredAssistantThreadContext ? assistantThreadContext : void 0;
|
|
3695
3556
|
if (assistantThreadContextToCache) ctx.saveSlackAssistantThreadContext(assistantThreadContextToCache, opts.eventScope);
|
|
3696
3557
|
const canUseManagedView = isDirectMessage && !opts.eventScope && !assistantThreadContext;
|
|
@@ -3754,19 +3615,16 @@ async function prepareSlackMessage(params) {
|
|
|
3754
3615
|
let mentionRegexes = buildPolicyMentionRegexes(routing.route.agentId);
|
|
3755
3616
|
let wasMentioned = resolveWasMentioned(mentionRegexes);
|
|
3756
3617
|
const hasBoundSession = Boolean(routing.runtimeBoundSessionKey || routing.configuredBindingSessionKey);
|
|
3757
|
-
const { configuredBinding
|
|
3618
|
+
const { configuredBinding } = routing;
|
|
3758
3619
|
const isAssistantThreadMessage = Boolean(isDirectMessage && messageAssistantThreadContext);
|
|
3759
3620
|
const forcedAssistantReplyThreadTs = Boolean(assistantThreadContext?.threadTs && (routing.isThreadReply || isAssistantThreadMessage || routing.replyToMode !== "off")) ? assistantThreadContext?.threadTs : void 0;
|
|
3760
3621
|
const forcedReplyThreadTs = agentViewThreadTs ?? forcedAssistantReplyThreadTs;
|
|
3761
|
-
if (routing.runtimeBinding && shouldLogVerbose()) logVerbose(`slack: routed via bound conversation ${routing.runtimeBinding.conversation.conversationId} -> ${routing.runtimeBinding.targetSessionKey}`);
|
|
3762
3622
|
if (configuredBinding) {
|
|
3763
3623
|
const ensured = await ensureConfiguredBindingRouteReady({
|
|
3764
3624
|
cfg,
|
|
3765
3625
|
bindingResolution: configuredBinding
|
|
3766
3626
|
});
|
|
3767
|
-
if (ensured.ok) {
|
|
3768
|
-
if (shouldLogVerbose()) logVerbose(`slack: using configured ACP binding for ${configuredBinding.record.conversation.conversationId} -> ${configuredBindingSessionKey}`);
|
|
3769
|
-
} else {
|
|
3627
|
+
if (!ensured.ok) {
|
|
3770
3628
|
if (shouldLogVerbose()) logVerbose(`slack: configured ACP binding unavailable for ${configuredBinding.record.conversation.conversationId}: ${ensured.error}`);
|
|
3771
3629
|
return drop("configured-binding-unavailable");
|
|
3772
3630
|
}
|
|
@@ -3804,7 +3662,11 @@ async function prepareSlackMessage(params) {
|
|
|
3804
3662
|
ctx,
|
|
3805
3663
|
account,
|
|
3806
3664
|
message,
|
|
3807
|
-
conversation
|
|
3665
|
+
conversation: {
|
|
3666
|
+
isRoom,
|
|
3667
|
+
isDirectMessage,
|
|
3668
|
+
channelConfig
|
|
3669
|
+
},
|
|
3808
3670
|
thread: routing,
|
|
3809
3671
|
wasMentioned,
|
|
3810
3672
|
teamId: opts.eventScope?.teamId,
|
|
@@ -3822,14 +3684,14 @@ async function prepareSlackMessage(params) {
|
|
|
3822
3684
|
const textForCommandDetection = stripSlackMentionsForCommandDetection(message.text ?? "");
|
|
3823
3685
|
const hasControlCommandInMessage = hasControlCommand(textForCommandDetection, cfg);
|
|
3824
3686
|
const hasAbortRequest = isAbortRequestText(textForCommandDetection);
|
|
3825
|
-
const channelUsersAllowlistConfigured = isRoom &&
|
|
3687
|
+
const channelUsersAllowlistConfigured = isRoom && (channelConfig?.users?.length ?? 0) > 0;
|
|
3826
3688
|
const resolveMessageIngress = async (contextBinding, threadId) => await resolveSlackCommandIngress({
|
|
3827
3689
|
ctx,
|
|
3828
3690
|
teamId: opts.eventScope?.teamId ?? ctx.teamId,
|
|
3829
3691
|
senderId,
|
|
3830
3692
|
senderAuthentication: message.user ? opts.senderAuthentication : void 0,
|
|
3831
3693
|
senderName: senderNameForAuth,
|
|
3832
|
-
channelType:
|
|
3694
|
+
channelType: resolvedChannelType ?? "channel",
|
|
3833
3695
|
channelId: message.channel,
|
|
3834
3696
|
threadId,
|
|
3835
3697
|
ownerAllowFromLower: allowFromLower,
|
|
@@ -3964,13 +3826,7 @@ async function prepareSlackMessage(params) {
|
|
|
3964
3826
|
const effectiveWasMentioned = mentionDecision.effectiveWasMentioned;
|
|
3965
3827
|
const shouldBypassMention = mentionDecision.shouldBypassMention;
|
|
3966
3828
|
const matchedImplicitMentionKinds = mentionDecision.matchedImplicitMentionKinds;
|
|
3967
|
-
const mentionSource =
|
|
3968
|
-
explicitBotMention: explicitlyMentionedBotUser || opts.source === "app_mention",
|
|
3969
|
-
explicitSubteamMention: explicitlyMentionedBotSubteam,
|
|
3970
|
-
matchedImplicitMentionKinds,
|
|
3971
|
-
shouldBypassMention,
|
|
3972
|
-
wasMentioned
|
|
3973
|
-
});
|
|
3829
|
+
const mentionSource = explicitlyMentionedBotUser || opts.source === "app_mention" ? "explicit_bot" : explicitlyMentionedBotSubteam ? "subteam" : shouldBypassMention ? "command_bypass" : wasMentioned ? "mention_pattern" : matchedImplicitMentionKinds.length > 0 ? "implicit_thread" : "none";
|
|
3974
3830
|
if (isBotMessage && allowBotsMode === "mentions") {
|
|
3975
3831
|
if (!(isDirectMessage || effectiveWasMentioned || shouldBypassMention)) return drop("bot-missing-mention");
|
|
3976
3832
|
}
|
|
@@ -4301,7 +4157,6 @@ async function prepareSlackMessage(params) {
|
|
|
4301
4157
|
originatingTo: preflightChannelTarget,
|
|
4302
4158
|
messageThreadId: threadContext.messageThreadId
|
|
4303
4159
|
});
|
|
4304
|
-
if (shouldLogVerbose()) logVerbose(`slack inbound: account=${route.accountId} agent=${route.agentId} channel=${message.channel} message_ts=${message.ts ?? "unknown"} thread_ts=${effectiveMessageThreadId ?? "none"} from=${slackFrom} chat=${chatType} chars=${rawBody.length}`);
|
|
4305
4160
|
const updateLastRouteSessionKey = resolveInboundLastRouteSessionKey({
|
|
4306
4161
|
route,
|
|
4307
4162
|
sessionKey
|
|
@@ -4350,5 +4205,4 @@ async function prepareSlackMessage(params) {
|
|
|
4350
4205
|
ackReactionPromise
|
|
4351
4206
|
};
|
|
4352
4207
|
}
|
|
4353
|
-
//#endregion
|
|
4354
4208
|
export { dispatchPreparedSlackMessage, prepareSlackMessage };
|