@openclaw/slack 2026.9.5 → 2026.9.7
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/assets/icon.png +0 -0
- package/dist/.setup/{account-inspect-B86OaUEt.mjs → account-inspect-DWBXpER6.mjs} +1 -1
- package/dist/.setup/{accounts-C1FspRF-.mjs → accounts-D_N9IqNA.mjs} +33 -10
- package/dist/.setup/{action-runtime-Aa-h24Fq.mjs → action-runtime-DfWvuiZd.mjs} +46 -65
- package/dist/.setup/action-runtime.runtime-Ck4bAWOX.mjs +2 -0
- package/dist/.setup/{actions-BvGUGk3w.mjs → actions-Df0CzcDl.mjs} +148 -204
- package/dist/.setup/{approval-handler.runtime-BcZNF-VP.mjs → approval-handler.runtime-Ed6Sw5VK.mjs} +37 -47
- package/dist/.setup/{approval-message-updates-Cy1cxfBn.mjs → approval-message-updates-BadvtA7R.mjs} +1 -2
- package/dist/.setup/{channel-DrBm0NFw.mjs → channel-C7bgPSTE.mjs} +192 -280
- package/dist/.setup/channel-meta-C443t-lI.mjs +27 -0
- package/dist/.setup/{channel-type-osC0XOES.mjs → channel-type-ClOttrZ5.mjs} +13 -21
- package/dist/.setup/{channel.setup-BSY5hzVz.mjs → channel.setup-Dh2jzAjN.mjs} +35 -42
- package/dist/.setup/{config-schema-DrY3S7Ee.mjs → config-schema-BZCxmHKG.mjs} +32 -21
- package/dist/.setup/{directory-config-CTs7YyuU.mjs → directory-config-BOUWH3hR.mjs} +7 -10
- package/dist/.setup/{directory-live-Btq0063Q.mjs → directory-live-B2O4B_Ho.mjs} +9 -21
- package/dist/.setup/doctor-contract-CRN1Z_c7.mjs +342 -0
- package/dist/.setup/{message-tool-api-DRnDCVdY.mjs → message-tool-api-Cu4lwlGy.mjs} +34 -48
- package/dist/.setup/{provider-w36VTgZ3.mjs → monitor-BPVfkumU.mjs} +2191 -2704
- package/dist/.setup/{outbound-adapter-K3Ek1iSR.mjs → outbound-adapter-Bv48XUjq.mjs} +10 -21
- package/dist/.setup/{pipeline.runtime-BZqGcbfi.mjs → pipeline.runtime-B1H63Frf.mjs} +901 -892
- package/dist/.setup/{plugin-routes-C3X0eVaK.mjs → plugin-routes-B8tooDLj.mjs} +1 -1
- package/dist/.setup/{policy-Db_QWCZZ.mjs → policy-D-jfM174.mjs} +5 -5
- package/dist/.setup/{probe-64C6k3_Q.mjs → probe-B2Y9qc_z.mjs} +101 -39
- package/dist/.setup/{registry-bbjH7IHX.mjs → registry-CIbMfuf8.mjs} +6 -2
- package/dist/.setup/{relay-source-CDqY76Vp.mjs → relay-source-BpKdjsll.mjs} +10 -12
- package/dist/.setup/{replies-CWFhjS9S.mjs → replies-BAnUtr2f.mjs} +16 -76
- package/dist/.setup/{reply-blocks-9uCeAJts.mjs → reply-blocks-SE1kTE3I.mjs} +27 -154
- package/dist/.setup/{resolve-channels-x8fX1SEt.mjs → resolve-channels-XXBn8UU_.mjs} +4 -5
- package/dist/.setup/{resolve-users-B8BpBnH2.mjs → resolve-users-DW0ngD03.mjs} +20 -22
- package/dist/.setup/{scopes-CJ-6l4v4.mjs → scopes-CasuDvaa.mjs} +6 -17
- package/dist/.setup/{secret-contract-DxmvbxBF.mjs → secret-contract-BaZcu6P_.mjs} +15 -20
- package/dist/.setup/{secret-contract-api-D9UfYujm.mjs → secret-contract-api-Dp6290Vg.mjs} +1 -1
- package/dist/.setup/{security-audit-BypHqcq5.mjs → security-audit-BqDc-6VL.mjs} +1 -1
- package/dist/.setup/{send-6GCb3lBP.mjs → send-BOVLQi3n.mjs} +102 -199
- package/dist/.setup/{session-status-BhG6pdiH.mjs → session-status-DscajIsd.mjs} +323 -250
- package/dist/.setup/{setup-plugin-api-DtCEByQB.mjs → setup-plugin-api-DTtbTKNk.mjs} +1 -1
- package/dist/.setup/{setup-surface-DsE0hsYY.mjs → setup-surface-Dn7QgWRE.mjs} +24 -56
- package/dist/.setup/{shared-BNmqCPgQ.mjs → shared-qau-uDGl.mjs} +30 -56
- package/dist/.setup/{slash-dispatch.runtime-Io4ASZsY.mjs → slash-dispatch.runtime--AEzLVBF.mjs} +1 -1
- package/dist/.setup/{streaming-compat-B-e0mqM0.mjs → streaming-compat-C5Wut626.mjs} +31 -8
- package/dist/.setup/{target-parsing-DEsPjngB.mjs → target-parsing-FFE26kOV.mjs} +1 -7
- package/dist/.setup/{targets-Cku2KCvg.mjs → targets-C6LZQL1Q.mjs} +1 -1
- package/dist/.setup/{thread-ts-CukseRVL.mjs → thread-ts-Cvt7WD6B.mjs} +0 -1
- package/dist/account-inspect-api.js +1 -1
- package/dist/api.js +18 -17
- package/dist/channel-config-api.js +1 -1
- package/dist/channel-plugin-api.js +1 -1
- package/dist/directory-contract-api.js +1 -1
- package/dist/doctor-contract-api.js +1 -1
- package/dist/http-routes-api.js +1 -1
- package/dist/index.js +1 -1
- package/dist/message-tool-api.js +1 -1
- package/dist/runtime-api.js +11 -12
- package/dist/secret-contract-api.js +1 -1
- package/dist/security-contract-api.js +1 -1
- package/dist/setup-entry.js +2 -2
- package/dist/setup-plugin-api.js +1 -1
- package/node_modules/@slack/bolt/node_modules/@types/node/README.md +1 -1
- package/node_modules/@slack/bolt/node_modules/@types/node/child_process.d.ts +1 -1
- package/node_modules/@slack/bolt/node_modules/@types/node/crypto.d.ts +20 -8
- package/node_modules/@slack/bolt/node_modules/@types/node/ffi.d.ts +14 -0
- package/node_modules/@slack/bolt/node_modules/@types/node/http2.d.ts +3 -2
- package/node_modules/@slack/bolt/node_modules/@types/node/net.d.ts +16 -4
- package/node_modules/@slack/bolt/node_modules/@types/node/package.json +2 -2
- package/node_modules/@slack/bolt/node_modules/@types/node/process.d.ts +1 -0
- package/node_modules/@slack/bolt/node_modules/@types/node/quic.d.ts +39 -1
- package/node_modules/@slack/bolt/node_modules/@types/node/stream/iter.d.ts +9 -12
- package/node_modules/@slack/bolt/node_modules/@types/node/test/reporters.d.ts +1 -0
- package/node_modules/@slack/bolt/node_modules/@types/node/test.d.ts +72 -0
- package/node_modules/@slack/bolt/node_modules/@types/node/tls.d.ts +14 -10
- package/node_modules/@slack/bolt/node_modules/@types/node/vm.d.ts +2 -1
- package/node_modules/@slack/bolt/node_modules/@types/node/web-globals/streams.d.ts +4 -0
- package/node_modules/@slack/bolt/node_modules/@types/node/worker_threads.d.ts +4 -1
- package/node_modules/@slack/web-api/node_modules/@types/node/README.md +1 -1
- package/node_modules/@slack/web-api/node_modules/@types/node/child_process.d.ts +1 -1
- package/node_modules/@slack/web-api/node_modules/@types/node/crypto.d.ts +20 -8
- package/node_modules/@slack/web-api/node_modules/@types/node/ffi.d.ts +14 -0
- package/node_modules/@slack/web-api/node_modules/@types/node/http2.d.ts +3 -2
- package/node_modules/@slack/web-api/node_modules/@types/node/net.d.ts +16 -4
- package/node_modules/@slack/web-api/node_modules/@types/node/package.json +2 -2
- package/node_modules/@slack/web-api/node_modules/@types/node/process.d.ts +1 -0
- package/node_modules/@slack/web-api/node_modules/@types/node/quic.d.ts +39 -1
- package/node_modules/@slack/web-api/node_modules/@types/node/stream/iter.d.ts +9 -12
- package/node_modules/@slack/web-api/node_modules/@types/node/test/reporters.d.ts +1 -0
- package/node_modules/@slack/web-api/node_modules/@types/node/test.d.ts +72 -0
- package/node_modules/@slack/web-api/node_modules/@types/node/tls.d.ts +14 -10
- package/node_modules/@slack/web-api/node_modules/@types/node/vm.d.ts +2 -1
- package/node_modules/@slack/web-api/node_modules/@types/node/web-globals/streams.d.ts +4 -0
- package/node_modules/@slack/web-api/node_modules/@types/node/worker_threads.d.ts +4 -1
- package/node_modules/get-east-asian-width/index.js +8 -3
- package/node_modules/get-east-asian-width/lookup-data.js +1 -1
- package/node_modules/get-east-asian-width/lookup.js +4 -4
- package/node_modules/get-east-asian-width/package.json +1 -1
- package/node_modules/typebox/build/compile/code.mjs +1 -2
- package/node_modules/typebox/build/compile/validator.mjs +5 -1
- package/node_modules/typebox/build/format/iri.mjs +16 -9
- package/node_modules/typebox/build/guard/emit.mjs +2 -2
- package/node_modules/typebox/build/guard/guard.d.mts +7 -5
- package/node_modules/typebox/build/guard/guard.mjs +14 -9
- package/node_modules/typebox/build/guard/index.mjs +6 -0
- package/node_modules/typebox/build/guard/unicode/unicode.d.mts +6 -0
- package/node_modules/typebox/build/guard/unicode/unicode.mjs +35 -0
- package/node_modules/typebox/build/guard/{string.mjs → unicode/unicode_segment.mjs} +16 -19
- package/node_modules/typebox/build/schema/build.mjs +2 -3
- package/node_modules/typebox/build/schema/engine/_pathing.d.mts +1 -0
- package/node_modules/typebox/build/schema/engine/_pathing.mjs +11 -0
- package/node_modules/typebox/build/schema/engine/_refine.mjs +13 -5
- package/node_modules/typebox/build/schema/engine/additionalProperties.mjs +2 -1
- package/node_modules/typebox/build/schema/engine/dependencies.mjs +2 -1
- package/node_modules/typebox/build/schema/engine/dependentSchemas.mjs +2 -1
- package/node_modules/typebox/build/schema/engine/dynamicRef.d.mts +1 -1
- package/node_modules/typebox/build/schema/engine/dynamicRef.mjs +2 -2
- package/node_modules/typebox/build/schema/engine/format.mjs +9 -2
- package/node_modules/typebox/build/schema/engine/patternProperties.mjs +3 -2
- package/node_modules/typebox/build/schema/engine/properties.mjs +3 -2
- package/node_modules/typebox/build/schema/engine/propertyNames.mjs +2 -1
- package/node_modules/typebox/build/schema/engine/recursiveRef.d.mts +1 -1
- package/node_modules/typebox/build/schema/engine/recursiveRef.mjs +2 -2
- package/node_modules/typebox/build/schema/engine/ref.d.mts +1 -1
- package/node_modules/typebox/build/schema/engine/ref.mjs +2 -2
- package/node_modules/typebox/build/schema/engine/schema.mjs +24 -24
- package/node_modules/typebox/build/schema/parse.mjs +3 -0
- package/node_modules/typebox/build/schema/pointer/pointer.d.mts +1 -6
- package/node_modules/typebox/build/schema/pointer/pointer.mjs +47 -64
- package/node_modules/typebox/build/system/settings/internal.d.mts +2 -0
- package/node_modules/typebox/build/system/settings/internal.mjs +20 -0
- package/node_modules/typebox/build/system/settings/settings.d.mts +11 -0
- package/node_modules/typebox/build/system/settings/settings.mjs +14 -0
- package/node_modules/typebox/build/type/extends/inference.d.mts +1 -1
- package/node_modules/typebox/build/type/extends/inference.mjs +15 -2
- package/node_modules/typebox/build/type/extends/tuple.d.mts +2 -1
- package/node_modules/typebox/build/type/extends/tuple.mjs +21 -1
- package/node_modules/typebox/build/value/parse/parse.mjs +10 -4
- package/node_modules/typebox/package.json +1 -1
- package/node_modules/typebox/readme.md +3 -1
- package/node_modules/undici/README.md +81 -25
- package/node_modules/undici/docs/docs/api/Agent.md +249 -42
- package/node_modules/undici/docs/docs/api/BalancedPool.md +246 -48
- package/node_modules/undici/docs/docs/api/CacheStorage.md +171 -13
- package/node_modules/undici/docs/docs/api/CacheStore.md +294 -98
- package/node_modules/undici/docs/docs/api/Client.md +407 -162
- package/node_modules/undici/docs/docs/api/ClientStats.md +80 -14
- package/node_modules/undici/docs/docs/api/Connector.md +118 -35
- package/node_modules/undici/docs/docs/api/ContentType.md +65 -25
- package/node_modules/undici/docs/docs/api/Cookies.md +122 -71
- package/node_modules/undici/docs/docs/api/Debug.md +34 -18
- package/node_modules/undici/docs/docs/api/DiagnosticsChannel.md +364 -164
- package/node_modules/undici/docs/docs/api/Dispatcher.md +490 -1055
- package/node_modules/undici/docs/docs/api/EnvHttpProxyAgent.md +105 -93
- package/node_modules/undici/docs/docs/api/Errors.md +503 -28
- package/node_modules/undici/docs/docs/api/EventSource.md +326 -13
- package/node_modules/undici/docs/docs/api/Fetch.md +681 -30
- package/node_modules/undici/docs/docs/api/GlobalInstallation.md +78 -96
- package/node_modules/undici/docs/docs/api/H2CClient.md +298 -176
- package/node_modules/undici/docs/docs/api/Interceptors.md +418 -0
- package/node_modules/undici/docs/docs/api/MockAgent.md +333 -314
- package/node_modules/undici/docs/docs/api/MockCallHistory.md +272 -98
- package/node_modules/undici/docs/docs/api/MockCallHistoryLog.md +189 -26
- package/node_modules/undici/docs/docs/api/MockClient.md +151 -33
- package/node_modules/undici/docs/docs/api/MockErrors.md +56 -5
- package/node_modules/undici/docs/docs/api/MockPool.md +321 -258
- package/node_modules/undici/docs/docs/api/Pool.md +236 -41
- package/node_modules/undici/docs/docs/api/PoolStats.md +119 -13
- package/node_modules/undici/docs/docs/api/ProxyAgent.md +179 -160
- package/node_modules/undici/docs/docs/api/RedirectHandler.md +238 -55
- package/node_modules/undici/docs/docs/api/RetryAgent.md +113 -27
- package/node_modules/undici/docs/docs/api/RetryHandler.md +161 -79
- package/node_modules/undici/docs/docs/api/RoundRobinPool.md +166 -72
- package/node_modules/undici/docs/docs/api/SnapshotAgent.md +262 -517
- package/node_modules/undici/docs/docs/api/Socks5ProxyAgent.md +177 -196
- package/node_modules/undici/docs/docs/api/Util.md +68 -11
- package/node_modules/undici/docs/docs/api/WebSocket.md +475 -80
- package/node_modules/undici/docs/docs/api/api-lifecycle.md +100 -32
- package/node_modules/undici/docs/docs/best-practices/client-certificate.md +2 -0
- package/node_modules/undici/docs/docs/best-practices/crawling.md +3 -1
- package/node_modules/undici/docs/docs/best-practices/migrating-from-v7-to-v8.md +233 -0
- package/node_modules/undici/docs/docs/best-practices/mocking-request.md +9 -7
- package/node_modules/undici/docs/docs/best-practices/proxy.md +3 -1
- package/node_modules/undici/docs/docs/best-practices/undici-vs-builtin-fetch.md +10 -8
- package/node_modules/undici/docs/docs/best-practices/writing-tests.md +2 -0
- package/node_modules/undici/docs/docs/getting-started.md +281 -0
- package/node_modules/undici/docs/docs/index.md +784 -0
- package/node_modules/undici/docs/docs/site.json +125 -0
- package/node_modules/undici/docs/docs/type-map.json +79 -0
- package/node_modules/undici/index.js +4 -2
- package/node_modules/undici/lib/api/api-connect.js +13 -11
- package/node_modules/undici/lib/api/api-pipeline.js +26 -13
- package/node_modules/undici/lib/api/api-request.js +51 -21
- package/node_modules/undici/lib/api/api-stream.js +81 -20
- package/node_modules/undici/lib/api/api-upgrade.js +21 -11
- package/node_modules/undici/lib/api/readable.js +45 -9
- package/node_modules/undici/lib/cache/memory-cache-store.js +3 -3
- package/node_modules/undici/lib/cache/sqlite-cache-store.js +3 -1
- package/node_modules/undici/lib/core/connect.js +46 -7
- package/node_modules/undici/lib/core/constants.js +1 -24
- package/node_modules/undici/lib/core/errors.js +22 -2
- package/node_modules/undici/lib/core/request.js +100 -18
- package/node_modules/undici/lib/core/symbols.js +4 -0
- package/node_modules/undici/lib/core/util.js +105 -48
- package/node_modules/undici/lib/dispatcher/agent.js +51 -32
- package/node_modules/undici/lib/dispatcher/balanced-pool.js +23 -27
- package/node_modules/undici/lib/dispatcher/client-h1.js +86 -24
- package/node_modules/undici/lib/dispatcher/client-h2.js +1091 -361
- package/node_modules/undici/lib/dispatcher/client.js +109 -36
- package/node_modules/undici/lib/dispatcher/dispatcher-base.js +19 -6
- package/node_modules/undici/lib/dispatcher/dispatcher.js +15 -5
- package/node_modules/undici/lib/dispatcher/dispatcher1-wrapper.js +110 -0
- package/node_modules/undici/lib/dispatcher/env-http-proxy-agent.js +37 -8
- package/node_modules/undici/lib/dispatcher/h2c-client.js +4 -4
- package/node_modules/undici/lib/dispatcher/pool-base.js +28 -10
- package/node_modules/undici/lib/dispatcher/pool.js +30 -5
- package/node_modules/undici/lib/dispatcher/proxy-agent.js +95 -19
- package/node_modules/undici/lib/dispatcher/retry-agent.js +3 -0
- package/node_modules/undici/lib/dispatcher/round-robin-pool.js +32 -10
- package/node_modules/undici/lib/dispatcher/socks5-proxy-agent.js +153 -63
- package/node_modules/undici/lib/global.js +37 -14
- package/node_modules/undici/lib/handler/cache-handler.js +49 -7
- package/node_modules/undici/lib/handler/cache-revalidation-handler.js +10 -0
- package/node_modules/undici/lib/handler/decorator-handler.js +8 -3
- package/node_modules/undici/lib/handler/deduplication-handler.js +12 -6
- package/node_modules/undici/lib/handler/redirect-handler.js +66 -66
- package/node_modules/undici/lib/handler/retry-handler.js +191 -50
- package/node_modules/undici/lib/interceptor/cache.js +75 -25
- package/node_modules/undici/lib/interceptor/decompress.js +5 -2
- package/node_modules/undici/lib/interceptor/deduplicate.js +5 -4
- package/node_modules/undici/lib/interceptor/dns.js +12 -1
- package/node_modules/undici/lib/interceptor/redirect.js +3 -3
- package/node_modules/undici/lib/llhttp/llhttp-wasm.js +1 -1
- package/node_modules/undici/lib/llhttp/llhttp_simd-wasm.js +1 -1
- package/node_modules/undici/lib/mock/mock-agent.js +21 -9
- package/node_modules/undici/lib/mock/mock-call-history.js +1 -1
- package/node_modules/undici/lib/mock/mock-interceptor.js +25 -7
- package/node_modules/undici/lib/mock/mock-utils.js +281 -47
- package/node_modules/undici/lib/mock/snapshot-agent.js +25 -7
- package/node_modules/undici/lib/mock/snapshot-recorder.js +38 -3
- package/node_modules/undici/lib/util/cache.js +92 -10
- package/node_modules/undici/lib/util/runtime-features.js +3 -34
- package/node_modules/undici/lib/web/cache/cache.js +6 -8
- package/node_modules/undici/lib/web/cookies/parse.js +150 -146
- package/node_modules/undici/lib/web/cookies/util.js +1 -1
- package/node_modules/undici/lib/web/eventsource/eventsource-stream.js +28 -1
- package/node_modules/undici/lib/web/eventsource/eventsource.js +20 -21
- package/node_modules/undici/lib/web/eventsource/util.js +32 -1
- package/node_modules/undici/lib/web/fetch/body.js +48 -10
- package/node_modules/undici/lib/web/fetch/constants.js +1 -1
- package/node_modules/undici/lib/web/fetch/formdata.js +21 -2
- package/node_modules/undici/lib/web/fetch/index.js +242 -223
- package/node_modules/undici/lib/web/fetch/request.js +35 -6
- package/node_modules/undici/lib/web/fetch/response.js +1 -3
- package/node_modules/undici/lib/web/fetch/util.js +10 -2
- package/node_modules/undici/lib/web/webidl/index.js +5 -7
- package/node_modules/undici/lib/web/websocket/frame.js +1 -7
- package/node_modules/undici/lib/web/websocket/receiver.js +1 -1
- package/node_modules/undici/lib/web/websocket/stream/websocketstream.js +10 -10
- package/node_modules/undici/lib/web/websocket/websocket.js +25 -3
- package/node_modules/undici/package.json +10 -10
- package/node_modules/undici/types/agent.d.ts +0 -2
- package/node_modules/undici/types/client.d.ts +69 -24
- package/node_modules/undici/types/connector.d.ts +1 -0
- package/node_modules/undici/types/cookies.d.ts +1 -1
- package/node_modules/undici/types/dispatcher.d.ts +8 -30
- package/node_modules/undici/types/dispatcher1-wrapper.d.ts +7 -0
- package/node_modules/undici/types/errors.d.ts +10 -0
- package/node_modules/undici/types/fetch.d.ts +5 -1
- package/node_modules/undici/types/formdata.d.ts +0 -6
- package/node_modules/undici/types/h2c-client.d.ts +6 -6
- package/node_modules/undici/types/handlers.d.ts +2 -0
- package/node_modules/undici/types/header.d.ts +5 -0
- package/node_modules/undici/types/index.d.ts +3 -1
- package/node_modules/undici/types/interceptors.d.ts +1 -1
- package/node_modules/undici/types/mock-agent.d.ts +11 -10
- package/node_modules/undici/types/mock-interceptor.d.ts +5 -1
- package/node_modules/undici/types/pool.d.ts +0 -2
- package/node_modules/undici/types/proxy-agent.d.ts +9 -2
- package/node_modules/undici/types/round-robin-pool.d.ts +0 -2
- package/node_modules/undici/types/snapshot-agent.d.ts +4 -0
- package/node_modules/undici/types/socks5-proxy-agent.d.ts +4 -2
- package/node_modules/undici/types/webidl.d.ts +0 -1
- package/node_modules/zod/README.md +2 -2
- package/node_modules/zod/compile.cjs +19 -0
- package/node_modules/zod/index.cjs +19 -0
- package/node_modules/zod/locales/index.cjs +19 -0
- package/node_modules/zod/mini/index.cjs +19 -0
- package/node_modules/zod/package.json +8 -7
- package/node_modules/zod/src/v3/helpers/errorUtil.ts +1 -1
- package/node_modules/zod/src/v4/classic/external.ts +2 -0
- package/node_modules/zod/src/v4/classic/from-json-schema.ts +248 -25
- package/node_modules/zod/src/v4/classic/schemas.ts +243 -168
- package/node_modules/zod/src/v4/classic/tests/assignability.test.ts +60 -9
- package/node_modules/zod/src/v4/classic/tests/bigint.test.ts +6 -0
- package/node_modules/zod/src/v4/classic/tests/continuability.test.ts +2 -2
- package/node_modules/zod/src/v4/classic/tests/cyclic-data.test.ts +265 -0
- package/node_modules/zod/src/v4/classic/tests/discriminated-unions.test.ts +112 -6
- package/node_modules/zod/src/v4/classic/tests/enum.test.ts +9 -0
- package/node_modules/zod/src/v4/classic/tests/error.test.ts +130 -1
- package/node_modules/zod/src/v4/classic/tests/from-json-schema.test.ts +157 -0
- package/node_modules/zod/src/v4/classic/tests/iban.test.ts +81 -0
- package/node_modules/zod/src/v4/classic/tests/instance-footprint.test.ts +40 -2
- package/node_modules/zod/src/v4/classic/tests/instanceof.test.ts +27 -7
- package/node_modules/zod/src/v4/classic/tests/issue-schema.test.ts +88 -56
- package/node_modules/zod/src/v4/classic/tests/number.test.ts +39 -0
- package/node_modules/zod/src/v4/classic/tests/object.test.ts +56 -0
- package/node_modules/zod/src/v4/classic/tests/optin-ladder.test.ts +3 -2
- package/node_modules/zod/src/v4/classic/tests/prefault.test.ts +70 -0
- package/node_modules/zod/src/v4/classic/tests/properties.test.ts +141 -0
- package/node_modules/zod/src/v4/classic/tests/recursive-types.test.ts +46 -1
- package/node_modules/zod/src/v4/classic/tests/standard-schema.test.ts +19 -0
- package/node_modules/zod/src/v4/classic/tests/string.test.ts +95 -1
- package/node_modules/zod/src/v4/classic/tests/template-literal.test.ts +33 -1
- package/node_modules/zod/src/v4/classic/tests/to-json-schema.test.ts +234 -38
- package/node_modules/zod/src/v4/classic/tests/validate.test.ts +569 -0
- package/node_modules/zod/src/v4/core/api.ts +44 -28
- package/node_modules/zod/src/v4/core/checks.ts +62 -102
- package/node_modules/zod/src/v4/core/compile.ts +218 -93
- package/node_modules/zod/src/v4/core/core.ts +1 -3
- package/node_modules/zod/src/v4/core/doc.ts +6 -2
- package/node_modules/zod/src/v4/core/errors.ts +3 -6
- package/node_modules/zod/src/v4/core/json-schema-generator.ts +2 -2
- package/node_modules/zod/src/v4/core/json-schema-processors.ts +185 -81
- package/node_modules/zod/src/v4/core/memoizer.ts +75 -28
- package/node_modules/zod/src/v4/core/parse.ts +37 -16
- package/node_modules/zod/src/v4/core/regexes.ts +14 -4
- package/node_modules/zod/src/v4/core/schemas.ts +296 -132
- package/node_modules/zod/src/v4/core/tests/cached.test.ts +54 -0
- package/node_modules/zod/src/v4/core/tests/compile-differential.test.ts +35 -0
- package/node_modules/zod/src/v4/core/tests/compile-generative.test.ts +445 -0
- package/node_modules/zod/src/v4/core/tests/compile.test.ts +399 -2
- package/node_modules/zod/src/v4/core/tests/email-regex.test.ts +140 -0
- package/node_modules/zod/src/v4/core/tests/locales/tg.test.ts +85 -0
- package/node_modules/zod/src/v4/core/tests/polyfill-collision.test.ts +46 -0
- package/node_modules/zod/src/v4/core/tests/url-no-canparse.test.ts +118 -16
- package/node_modules/zod/src/v4/core/to-json-schema.ts +9 -7
- package/node_modules/zod/src/v4/core/util.ts +218 -147
- package/node_modules/zod/src/v4/core/versions.ts +2 -2
- package/node_modules/zod/src/v4/locales/ar.ts +2 -0
- package/node_modules/zod/src/v4/locales/az.ts +2 -0
- package/node_modules/zod/src/v4/locales/be.ts +2 -0
- package/node_modules/zod/src/v4/locales/bg.ts +2 -0
- package/node_modules/zod/src/v4/locales/bn.ts +2 -0
- package/node_modules/zod/src/v4/locales/ca.ts +2 -0
- package/node_modules/zod/src/v4/locales/ckb.ts +2 -0
- package/node_modules/zod/src/v4/locales/cs.ts +2 -0
- package/node_modules/zod/src/v4/locales/da.ts +2 -0
- package/node_modules/zod/src/v4/locales/de.ts +2 -0
- package/node_modules/zod/src/v4/locales/el.ts +2 -0
- package/node_modules/zod/src/v4/locales/en.ts +2 -0
- package/node_modules/zod/src/v4/locales/eo.ts +2 -0
- package/node_modules/zod/src/v4/locales/es.ts +2 -0
- package/node_modules/zod/src/v4/locales/fa.ts +2 -0
- package/node_modules/zod/src/v4/locales/fi.ts +2 -0
- package/node_modules/zod/src/v4/locales/fr-CA.ts +2 -0
- package/node_modules/zod/src/v4/locales/fr.ts +2 -0
- package/node_modules/zod/src/v4/locales/gu.ts +2 -0
- package/node_modules/zod/src/v4/locales/he.ts +2 -0
- package/node_modules/zod/src/v4/locales/hi.ts +2 -0
- package/node_modules/zod/src/v4/locales/hr.ts +2 -0
- package/node_modules/zod/src/v4/locales/hu.ts +2 -0
- package/node_modules/zod/src/v4/locales/hy.ts +2 -0
- package/node_modules/zod/src/v4/locales/id.ts +2 -0
- package/node_modules/zod/src/v4/locales/index.ts +1 -0
- package/node_modules/zod/src/v4/locales/is.ts +2 -0
- package/node_modules/zod/src/v4/locales/it.ts +2 -0
- package/node_modules/zod/src/v4/locales/ja.ts +2 -0
- package/node_modules/zod/src/v4/locales/ka.ts +2 -0
- package/node_modules/zod/src/v4/locales/km.ts +2 -0
- package/node_modules/zod/src/v4/locales/kn.ts +2 -0
- package/node_modules/zod/src/v4/locales/ko.ts +2 -0
- package/node_modules/zod/src/v4/locales/lt.ts +2 -0
- package/node_modules/zod/src/v4/locales/mk.ts +2 -0
- package/node_modules/zod/src/v4/locales/ms.ts +2 -0
- package/node_modules/zod/src/v4/locales/ne.ts +2 -0
- package/node_modules/zod/src/v4/locales/nl.ts +2 -0
- package/node_modules/zod/src/v4/locales/nn.ts +2 -0
- package/node_modules/zod/src/v4/locales/no.ts +2 -0
- package/node_modules/zod/src/v4/locales/ota.ts +2 -0
- package/node_modules/zod/src/v4/locales/pl.ts +2 -0
- package/node_modules/zod/src/v4/locales/ps.ts +2 -0
- package/node_modules/zod/src/v4/locales/pt-BR.ts +2 -0
- package/node_modules/zod/src/v4/locales/pt.ts +2 -0
- package/node_modules/zod/src/v4/locales/ro.ts +2 -0
- package/node_modules/zod/src/v4/locales/ru.ts +2 -0
- package/node_modules/zod/src/v4/locales/sk.ts +2 -0
- package/node_modules/zod/src/v4/locales/sl.ts +2 -0
- package/node_modules/zod/src/v4/locales/sv.ts +2 -0
- package/node_modules/zod/src/v4/locales/ta.ts +2 -0
- package/node_modules/zod/src/v4/locales/tg.ts +135 -0
- package/node_modules/zod/src/v4/locales/th.ts +2 -0
- package/node_modules/zod/src/v4/locales/tk.ts +2 -0
- package/node_modules/zod/src/v4/locales/tr.ts +2 -0
- package/node_modules/zod/src/v4/locales/uk.ts +2 -0
- package/node_modules/zod/src/v4/locales/ur.ts +2 -0
- package/node_modules/zod/src/v4/locales/uz.ts +2 -0
- package/node_modules/zod/src/v4/locales/vi.ts +2 -0
- package/node_modules/zod/src/v4/locales/yo.ts +2 -0
- package/node_modules/zod/src/v4/locales/zh-CN.ts +2 -0
- package/node_modules/zod/src/v4/locales/zh-TW.ts +2 -0
- package/node_modules/zod/src/v4/mini/external.ts +2 -0
- package/node_modules/zod/src/v4/mini/schemas.ts +32 -7
- package/node_modules/zod/src/v4/mini/tests/checks.test.ts +1 -1
- package/node_modules/zod/src/v4/mini/tests/computed.test.ts +11 -17
- package/node_modules/zod/src/v4/mini/tests/index.test.ts +86 -0
- package/node_modules/zod/src/v4/mini/tests/recursive-types.test.ts +16 -0
- package/node_modules/zod/src/v4/mini/tests/string.test.ts +23 -0
- package/node_modules/zod/v3/ZodError.cjs +19 -0
- package/node_modules/zod/v3/errors.cjs +19 -0
- package/node_modules/zod/v3/external.cjs +19 -0
- package/node_modules/zod/v3/helpers/enumUtil.cjs +19 -0
- package/node_modules/zod/v3/helpers/errorUtil.cjs +20 -1
- package/node_modules/zod/v3/helpers/errorUtil.js +1 -1
- package/node_modules/zod/v3/helpers/parseUtil.cjs +19 -0
- package/node_modules/zod/v3/helpers/partialUtil.cjs +19 -0
- package/node_modules/zod/v3/helpers/typeAliases.cjs +19 -0
- package/node_modules/zod/v3/helpers/util.cjs +19 -0
- package/node_modules/zod/v3/index.cjs +19 -0
- package/node_modules/zod/v3/standard-schema.cjs +19 -0
- package/node_modules/zod/v3/types.cjs +19 -0
- package/node_modules/zod/v4/classic/checks.cjs +19 -0
- package/node_modules/zod/v4/classic/coerce.cjs +19 -0
- package/node_modules/zod/v4/classic/compat.cjs +19 -0
- package/node_modules/zod/v4/classic/deep-partial.cjs +19 -0
- package/node_modules/zod/v4/classic/errors.cjs +19 -0
- package/node_modules/zod/v4/classic/external.cjs +22 -1
- package/node_modules/zod/v4/classic/external.d.cts +1 -1
- package/node_modules/zod/v4/classic/external.d.ts +1 -1
- package/node_modules/zod/v4/classic/external.js +1 -1
- package/node_modules/zod/v4/classic/from-json-schema.cjs +264 -24
- package/node_modules/zod/v4/classic/from-json-schema.js +245 -24
- package/node_modules/zod/v4/classic/in-out.cjs +19 -0
- package/node_modules/zod/v4/classic/index.cjs +19 -0
- package/node_modules/zod/v4/classic/iso.cjs +19 -0
- package/node_modules/zod/v4/classic/parse.cjs +19 -0
- package/node_modules/zod/v4/classic/schemas.cjs +100 -35
- package/node_modules/zod/v4/classic/schemas.d.cts +15 -1
- package/node_modules/zod/v4/classic/schemas.d.ts +15 -1
- package/node_modules/zod/v4/classic/schemas.js +77 -33
- package/node_modules/zod/v4/core/api.cjs +45 -22
- package/node_modules/zod/v4/core/api.d.cts +12 -6
- package/node_modules/zod/v4/core/api.d.ts +12 -6
- package/node_modules/zod/v4/core/api.js +25 -22
- package/node_modules/zod/v4/core/checks.cjs +51 -97
- package/node_modules/zod/v4/core/checks.d.cts +17 -1
- package/node_modules/zod/v4/core/checks.d.ts +17 -1
- package/node_modules/zod/v4/core/checks.js +31 -96
- package/node_modules/zod/v4/core/compile.cjs +173 -78
- package/node_modules/zod/v4/core/compile.d.cts +18 -4
- package/node_modules/zod/v4/core/compile.d.ts +18 -4
- package/node_modules/zod/v4/core/compile.js +154 -79
- package/node_modules/zod/v4/core/core.cjs +20 -1
- package/node_modules/zod/v4/core/core.js +1 -1
- package/node_modules/zod/v4/core/doc.cjs +26 -2
- package/node_modules/zod/v4/core/doc.js +7 -2
- package/node_modules/zod/v4/core/errors.cjs +21 -5
- package/node_modules/zod/v4/core/errors.js +2 -5
- package/node_modules/zod/v4/core/index.cjs +19 -0
- package/node_modules/zod/v4/core/json-schema-generator.cjs +20 -1
- package/node_modules/zod/v4/core/json-schema-generator.js +2 -2
- package/node_modules/zod/v4/core/json-schema-processors.cjs +188 -72
- package/node_modules/zod/v4/core/json-schema-processors.d.cts +16 -0
- package/node_modules/zod/v4/core/json-schema-processors.d.ts +16 -0
- package/node_modules/zod/v4/core/json-schema-processors.js +170 -74
- package/node_modules/zod/v4/core/json-schema.cjs +19 -0
- package/node_modules/zod/v4/core/memoizer.cjs +111 -23
- package/node_modules/zod/v4/core/memoizer.js +69 -23
- package/node_modules/zod/v4/core/parse.cjs +56 -16
- package/node_modules/zod/v4/core/parse.js +37 -16
- package/node_modules/zod/v4/core/regexes.cjs +31 -6
- package/node_modules/zod/v4/core/regexes.d.cts +3 -0
- package/node_modules/zod/v4/core/regexes.d.ts +3 -0
- package/node_modules/zod/v4/core/regexes.js +10 -4
- package/node_modules/zod/v4/core/registries.cjs +19 -0
- package/node_modules/zod/v4/core/schemas.cjs +302 -114
- package/node_modules/zod/v4/core/schemas.d.cts +28 -8
- package/node_modules/zod/v4/core/schemas.d.ts +28 -8
- package/node_modules/zod/v4/core/schemas.js +279 -113
- package/node_modules/zod/v4/core/standard-schema.cjs +19 -0
- package/node_modules/zod/v4/core/to-json-schema.cjs +28 -7
- package/node_modules/zod/v4/core/to-json-schema.d.cts +4 -3
- package/node_modules/zod/v4/core/to-json-schema.d.ts +4 -3
- package/node_modules/zod/v4/core/to-json-schema.js +7 -6
- package/node_modules/zod/v4/core/util.cjs +177 -143
- package/node_modules/zod/v4/core/util.d.cts +25 -4
- package/node_modules/zod/v4/core/util.d.ts +25 -4
- package/node_modules/zod/v4/core/util.js +156 -143
- package/node_modules/zod/v4/core/versions.cjs +21 -2
- package/node_modules/zod/v4/core/versions.d.cts +1 -1
- package/node_modules/zod/v4/core/versions.d.ts +1 -1
- package/node_modules/zod/v4/core/versions.js +2 -2
- package/node_modules/zod/v4/core/visit.cjs +19 -0
- package/node_modules/zod/v4/index.cjs +19 -0
- package/node_modules/zod/v4/locales/ar.cjs +2 -0
- package/node_modules/zod/v4/locales/ar.js +2 -0
- package/node_modules/zod/v4/locales/az.cjs +2 -0
- package/node_modules/zod/v4/locales/az.js +2 -0
- package/node_modules/zod/v4/locales/be.cjs +2 -0
- package/node_modules/zod/v4/locales/be.js +2 -0
- package/node_modules/zod/v4/locales/bg.cjs +2 -0
- package/node_modules/zod/v4/locales/bg.js +2 -0
- package/node_modules/zod/v4/locales/bn.cjs +2 -0
- package/node_modules/zod/v4/locales/bn.js +2 -0
- package/node_modules/zod/v4/locales/ca.cjs +2 -0
- package/node_modules/zod/v4/locales/ca.js +2 -0
- package/node_modules/zod/v4/locales/ckb.cjs +2 -0
- package/node_modules/zod/v4/locales/ckb.js +2 -0
- package/node_modules/zod/v4/locales/cs.cjs +2 -0
- package/node_modules/zod/v4/locales/cs.js +2 -0
- package/node_modules/zod/v4/locales/da.cjs +2 -0
- package/node_modules/zod/v4/locales/da.js +2 -0
- package/node_modules/zod/v4/locales/de.cjs +2 -0
- package/node_modules/zod/v4/locales/de.js +2 -0
- package/node_modules/zod/v4/locales/el.cjs +2 -0
- package/node_modules/zod/v4/locales/el.js +2 -0
- package/node_modules/zod/v4/locales/en.cjs +2 -0
- package/node_modules/zod/v4/locales/en.js +2 -0
- package/node_modules/zod/v4/locales/eo.cjs +2 -0
- package/node_modules/zod/v4/locales/eo.js +2 -0
- package/node_modules/zod/v4/locales/es.cjs +2 -0
- package/node_modules/zod/v4/locales/es.js +2 -0
- package/node_modules/zod/v4/locales/fa.cjs +2 -0
- package/node_modules/zod/v4/locales/fa.js +2 -0
- package/node_modules/zod/v4/locales/fi.cjs +2 -0
- package/node_modules/zod/v4/locales/fi.js +2 -0
- package/node_modules/zod/v4/locales/fr-CA.cjs +2 -0
- package/node_modules/zod/v4/locales/fr-CA.js +2 -0
- package/node_modules/zod/v4/locales/fr.cjs +2 -0
- package/node_modules/zod/v4/locales/fr.js +2 -0
- package/node_modules/zod/v4/locales/gu.cjs +2 -0
- package/node_modules/zod/v4/locales/gu.js +2 -0
- package/node_modules/zod/v4/locales/he.cjs +2 -0
- package/node_modules/zod/v4/locales/he.js +2 -0
- package/node_modules/zod/v4/locales/hi.cjs +2 -0
- package/node_modules/zod/v4/locales/hi.js +2 -0
- package/node_modules/zod/v4/locales/hr.cjs +2 -0
- package/node_modules/zod/v4/locales/hr.js +2 -0
- package/node_modules/zod/v4/locales/hu.cjs +2 -0
- package/node_modules/zod/v4/locales/hu.js +2 -0
- package/node_modules/zod/v4/locales/hy.cjs +2 -0
- package/node_modules/zod/v4/locales/hy.js +2 -0
- package/node_modules/zod/v4/locales/id.cjs +2 -0
- package/node_modules/zod/v4/locales/id.js +2 -0
- package/node_modules/zod/v4/locales/index.cjs +22 -1
- package/node_modules/zod/v4/locales/index.d.cts +1 -0
- package/node_modules/zod/v4/locales/index.d.ts +1 -0
- package/node_modules/zod/v4/locales/index.js +1 -0
- package/node_modules/zod/v4/locales/is.cjs +2 -0
- package/node_modules/zod/v4/locales/is.js +2 -0
- package/node_modules/zod/v4/locales/it.cjs +2 -0
- package/node_modules/zod/v4/locales/it.js +2 -0
- package/node_modules/zod/v4/locales/ja.cjs +2 -0
- package/node_modules/zod/v4/locales/ja.js +2 -0
- package/node_modules/zod/v4/locales/ka.cjs +2 -0
- package/node_modules/zod/v4/locales/ka.js +2 -0
- package/node_modules/zod/v4/locales/km.cjs +2 -0
- package/node_modules/zod/v4/locales/km.js +2 -0
- package/node_modules/zod/v4/locales/kn.cjs +2 -0
- package/node_modules/zod/v4/locales/kn.js +2 -0
- package/node_modules/zod/v4/locales/ko.cjs +2 -0
- package/node_modules/zod/v4/locales/ko.js +2 -0
- package/node_modules/zod/v4/locales/lt.cjs +2 -0
- package/node_modules/zod/v4/locales/lt.js +2 -0
- package/node_modules/zod/v4/locales/mk.cjs +2 -0
- package/node_modules/zod/v4/locales/mk.js +2 -0
- package/node_modules/zod/v4/locales/ms.cjs +2 -0
- package/node_modules/zod/v4/locales/ms.js +2 -0
- package/node_modules/zod/v4/locales/ne.cjs +2 -0
- package/node_modules/zod/v4/locales/ne.js +2 -0
- package/node_modules/zod/v4/locales/nl.cjs +2 -0
- package/node_modules/zod/v4/locales/nl.js +2 -0
- package/node_modules/zod/v4/locales/nn.cjs +2 -0
- package/node_modules/zod/v4/locales/nn.js +2 -0
- package/node_modules/zod/v4/locales/no.cjs +2 -0
- package/node_modules/zod/v4/locales/no.js +2 -0
- package/node_modules/zod/v4/locales/ota.cjs +2 -0
- package/node_modules/zod/v4/locales/ota.js +2 -0
- package/node_modules/zod/v4/locales/pl.cjs +2 -0
- package/node_modules/zod/v4/locales/pl.js +2 -0
- package/node_modules/zod/v4/locales/ps.cjs +2 -0
- package/node_modules/zod/v4/locales/ps.js +2 -0
- package/node_modules/zod/v4/locales/pt-BR.cjs +2 -0
- package/node_modules/zod/v4/locales/pt-BR.js +2 -0
- package/node_modules/zod/v4/locales/pt.cjs +2 -0
- package/node_modules/zod/v4/locales/pt.js +2 -0
- package/node_modules/zod/v4/locales/ro.cjs +2 -0
- package/node_modules/zod/v4/locales/ro.js +2 -0
- package/node_modules/zod/v4/locales/ru.cjs +2 -0
- package/node_modules/zod/v4/locales/ru.js +2 -0
- package/node_modules/zod/v4/locales/sk.cjs +2 -0
- package/node_modules/zod/v4/locales/sk.js +2 -0
- package/node_modules/zod/v4/locales/sl.cjs +2 -0
- package/node_modules/zod/v4/locales/sl.js +2 -0
- package/node_modules/zod/v4/locales/sv.cjs +2 -0
- package/node_modules/zod/v4/locales/sv.js +2 -0
- package/node_modules/zod/v4/locales/ta.cjs +2 -0
- package/node_modules/zod/v4/locales/ta.js +2 -0
- package/node_modules/zod/v4/locales/tg.cjs +144 -0
- package/node_modules/zod/v4/locales/tg.d.cts +5 -0
- package/node_modules/zod/v4/locales/tg.d.ts +4 -0
- package/node_modules/zod/v4/locales/tg.js +117 -0
- package/node_modules/zod/v4/locales/th.cjs +2 -0
- package/node_modules/zod/v4/locales/th.js +2 -0
- package/node_modules/zod/v4/locales/tk.cjs +2 -0
- package/node_modules/zod/v4/locales/tk.js +2 -0
- package/node_modules/zod/v4/locales/tr.cjs +2 -0
- package/node_modules/zod/v4/locales/tr.js +2 -0
- package/node_modules/zod/v4/locales/uk.cjs +2 -0
- package/node_modules/zod/v4/locales/uk.js +2 -0
- package/node_modules/zod/v4/locales/ur.cjs +2 -0
- package/node_modules/zod/v4/locales/ur.js +2 -0
- package/node_modules/zod/v4/locales/uz.cjs +2 -0
- package/node_modules/zod/v4/locales/uz.js +2 -0
- package/node_modules/zod/v4/locales/vi.cjs +2 -0
- package/node_modules/zod/v4/locales/vi.js +2 -0
- package/node_modules/zod/v4/locales/yo.cjs +2 -0
- package/node_modules/zod/v4/locales/yo.js +2 -0
- package/node_modules/zod/v4/locales/zh-CN.cjs +2 -0
- package/node_modules/zod/v4/locales/zh-CN.js +2 -0
- package/node_modules/zod/v4/locales/zh-TW.cjs +2 -0
- package/node_modules/zod/v4/locales/zh-TW.js +2 -0
- package/node_modules/zod/v4/mini/checks.cjs +19 -0
- package/node_modules/zod/v4/mini/coerce.cjs +19 -0
- package/node_modules/zod/v4/mini/deep-partial.cjs +19 -0
- package/node_modules/zod/v4/mini/external.cjs +22 -1
- package/node_modules/zod/v4/mini/external.d.cts +1 -1
- package/node_modules/zod/v4/mini/external.d.ts +1 -1
- package/node_modules/zod/v4/mini/external.js +1 -1
- package/node_modules/zod/v4/mini/in-out.cjs +19 -0
- package/node_modules/zod/v4/mini/index.cjs +19 -0
- package/node_modules/zod/v4/mini/iso.cjs +19 -0
- package/node_modules/zod/v4/mini/parse.cjs +19 -0
- package/node_modules/zod/v4/mini/schemas.cjs +44 -8
- package/node_modules/zod/v4/mini/schemas.d.cts +6 -1
- package/node_modules/zod/v4/mini/schemas.d.ts +6 -1
- package/node_modules/zod/v4/mini/schemas.js +21 -6
- package/node_modules/zod/v4-mini/index.cjs +19 -0
- package/openclaw.plugin.json +49 -3
- package/package.json +8 -8
- package/dist/.setup/accounts.runtime-BpWv-6-2.mjs +0 -2
- package/dist/.setup/action-runtime.runtime-DwH3NdpT.mjs +0 -2
- package/dist/.setup/doctor-contract-CtMUqjvk.mjs +0 -186
- package/dist/.setup/monitor-Dw5uuKWM.mjs +0 -13
- package/dist/.setup/rolldown-runtime-D7D4PA-g.mjs +0 -13
- package/dist/.setup/send.runtime-BmqRP-WG.mjs +0 -2
- package/dist/.setup/slash-commands.runtime-BpSH0b3q.mjs +0 -2
- package/dist/.setup/slash-skill-commands.runtime-Bi1JWZHY.mjs +0 -2
- package/node_modules/undici/lib/handler/unwrap-handler.js +0 -106
- package/node_modules/undici/lib/handler/wrap-handler.js +0 -105
- package/node_modules/undici/lib/llhttp/.gitkeep +0 -0
- package/node_modules/undici/lib/util/promise.js +0 -28
- /package/node_modules/typebox/build/guard/{string.d.mts → unicode/unicode_segment.d.mts} +0 -0
|
@@ -1,27 +1,29 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import { n as resolveSlackChannelConfig } from "./policy-
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
1
|
+
import { i as __reExport, n as resolveSlackStreamingMode, r as __exportAll, t as resolveSlackNativeStreaming } from "./streaming-compat-C5Wut626.mjs";
|
|
2
|
+
import { f as resolveSlackReplyToMode } from "./accounts-D_N9IqNA.mjs";
|
|
3
|
+
import { n as formatSlackTarget } from "./target-parsing-FFE26kOV.mjs";
|
|
4
|
+
import { A as countSlackTextUtf8Bytes, C as buildSlackBlocksFallbackText, E as SLACK_EDIT_TEXT_MAX_BYTES, H as SLACK_SESSION_LINK_ACTION_ID, M as truncateSlackTextByUtf8Bytes, Q as normalizeSlackOutboundText, c as qualifySlackRoutePeerId, j as truncateSlackText, k as SLACK_TEXT_LIMIT, lt as escapeSlackMrkdwn, v as hasSlackNativeDataBlock, w as buildSlackCompleteBlocksFallbackText } from "./session-status-DscajIsd.mjs";
|
|
5
|
+
import { D as normalizeSlackAllowOwnerEntry, j as resolveSlackUserAllowed, o as formatSlackError, v as readLruMapEntry, y as writeLruMapEntry } from "./probe-B2Y9qc_z.mjs";
|
|
6
|
+
import { a as prepareSlackReply, l as resolveSlackReplyRenderPlan, s as resolveSlackReplyBlocks } from "./reply-blocks-SE1kTE3I.mjs";
|
|
7
|
+
import { n as resolveSlackReplyThreadTs } from "./thread-ts-Cvt7WD6B.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-Df0CzcDl.mjs";
|
|
9
|
+
import { c as hasSlackThreadParticipationWithPersistence, i as clearSlackThreadFailureNotice, l as recordSlackThreadFailureNotice, o as hasSlackThreadFailureNotice, p as buildSlackNativeDataDeliveryPlan, s as hasSlackThreadParticipation, t as sendMessageSlack, u as recordSlackThreadParticipation } from "./send-BOVLQi3n.mjs";
|
|
10
|
+
import { n as resolveSlackChannelConfig } from "./policy-D-jfM174.mjs";
|
|
11
|
+
import { C as resolveSlackChatType, E as stripSlackMentionsForCommandDetection, S as normalizeSlackChannelType, T as readSlackAssistantThreadContext, _ as appendSlackStream, b as stopSlackStream, c as resolveSlackRoutingContext, g as SlackStreamNotDeliveredError, h as resolveSlackEffectiveAllowFrom, i as resolveSlackRoomContextHints, l as registerSlackSessionRun, m as resolveSlackCommandIngress, p as authorizeSlackBotRoomMessage, r as trackSlackDraftMessage, s as authorizeSlackDirectMessage, u as resolveSlackThreadContext, v as markSlackStreamFallbackDelivered, w as buildSlackAssistantThreadMetadata, y as startSlackStream } from "./monitor-BPVfkumU.mjs";
|
|
12
|
+
import { a as emitSlackMessageSentHooks, i as sanitizeSlackMonitorReplyPayload, n as deliverReplies, t as createSlackReplyDeliveryPlan } from "./replies-BAnUtr2f.mjs";
|
|
13
|
+
import { asOptionalRecord, normalizeLowercaseStringOrEmpty, normalizeOptionalLowercaseString, normalizeOptionalString, readNonBlankString } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
13
14
|
import { resolveInboundLastRouteSessionKey } from "openclaw/plugin-sdk/routing";
|
|
14
|
-
import { buildChannelProgressDraftLine, createChannelMessageReplyPipeline, createChannelProgressDraftCompositor, createChannelProgressWorkCounter, createDraftStreamLoop,
|
|
15
|
+
import { buildChannelProgressDraftLine, createChannelMessageReplyPipeline, createChannelProgressDraftCompositor, createChannelProgressWorkCounter, createDraftStreamLoop, createFinalizableDraftLifecycle, createLivePreviewLifecycle, createMessageReceiptFromOutboundResults, formatChannelProgressDraftDiffStat, formatPlanChecklistLines, resolveAgentOutboundIdentity, resolveChannelMessageSourceReplyDeliveryMode, resolveChannelProgressDraftConfig, resolveChannelProgressDraftMaxLineChars, resolveChannelStreamingBlockEnabled, resolveChannelStreamingPreviewToolProgress, resolveChannelStreamingSuppressDefaultToolProgressMessages } from "openclaw/plugin-sdk/channel-outbound";
|
|
15
16
|
import { createLazyRuntimeModule } from "openclaw/plugin-sdk/lazy-runtime";
|
|
16
17
|
import { danger, logVerbose, shouldLogVerbose } from "openclaw/plugin-sdk/runtime-env";
|
|
17
18
|
import { sanitizeAssistantVisibleText } from "openclaw/plugin-sdk/text-chunking";
|
|
18
19
|
import { truncateUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
|
|
20
|
+
import { normalizeStringEntriesLower } from "openclaw/plugin-sdk/string-normalization-runtime";
|
|
21
|
+
import { pruneMapToMaxSize } from "openclaw/plugin-sdk/collection-runtime";
|
|
19
22
|
import { resolveMarkdownTableMode } from "openclaw/plugin-sdk/markdown-table-runtime";
|
|
20
23
|
import { buildTtsSupplementMediaPayload, getReplyPayloadTtsSupplement, isReplyPayloadNonTerminalToolErrorWarning, resolveSendableOutboundReplyParts } from "openclaw/plugin-sdk/reply-payload";
|
|
21
|
-
import { asDateTimestampMs, asFiniteNumberInRange, parseStrictFiniteNumber, resolveExpiresAtMsFromDurationMs } from "openclaw/plugin-sdk/number-runtime";
|
|
24
|
+
import { asDateTimestampMs, asFiniteNumberInRange, parseStrictFiniteNumber, resolveExpiresAtMsFromDurationMs, resolvePromptHistoryLimit } from "openclaw/plugin-sdk/number-runtime";
|
|
22
25
|
import { hash } from "node:crypto";
|
|
23
|
-
import {
|
|
24
|
-
import { ensureConfiguredBindingRouteReady } from "openclaw/plugin-sdk/conversation-runtime";
|
|
26
|
+
import { ensureConfiguredBindingRouteReady, resolveConversationLabel } from "openclaw/plugin-sdk/conversation-runtime";
|
|
25
27
|
import { resolveChannelImplicitMentions } from "openclaw/plugin-sdk/channel-ingress-runtime";
|
|
26
28
|
import fs from "node:fs/promises";
|
|
27
29
|
import { runTasksWithConcurrency } from "openclaw/plugin-sdk/concurrency-runtime";
|
|
@@ -29,17 +31,19 @@ import { formatErrorMessage, toErrorObject } from "openclaw/plugin-sdk/error-run
|
|
|
29
31
|
import { filterSupplementalContextItems, resolvePinnedMainDmOwnerFromAllowlist, shouldIncludeSupplementalContext } from "openclaw/plugin-sdk/security-runtime";
|
|
30
32
|
import { mimeTypeFromFilePath } from "openclaw/plugin-sdk/media-mime";
|
|
31
33
|
import { mergePairLoopGuardConfig } from "openclaw/plugin-sdk/pair-loop-guard-runtime";
|
|
32
|
-
import {
|
|
34
|
+
import { getSessionEntry, readSessionUpdatedAt, resolveChannelResetConfig, resolveStorePath, updateLastRoute } from "openclaw/plugin-sdk/session-store-runtime";
|
|
33
35
|
import { resolveHumanDelayConfig } from "openclaw/plugin-sdk/agent-runtime";
|
|
34
36
|
import { enqueueRoutedSystemEvent } from "openclaw/plugin-sdk/system-event-runtime";
|
|
35
37
|
import { getGlobalHookRunner } from "openclaw/plugin-sdk/plugin-runtime";
|
|
36
|
-
import { buildChannelInboundEventContext, buildMentionRegexes, classifyChannelInboundEvent, dispatchChannelInboundTurn, formatInboundEnvelope, formatInboundMediaUnavailableText, hasVisibleInboundReplyDispatch,
|
|
38
|
+
import { buildChannelInboundEventContext, buildMentionRegexes, classifyChannelInboundEvent, dispatchChannelInboundTurn, formatInboundEnvelope, formatInboundMediaUnavailableText, hasVisibleInboundReplyDispatch, isGroupThreadRouteExclusive, matchesMentionWithExplicit, readAgentRunTerminalOutcome, resolveEnvelopeFormatOptions, resolveGroupThreadConfig, resolveGroupThreadMentionFacts, resolveInboundMentionDecision, resolveInboundReplyDispatchCounts, resolveUnmentionedGroupInboundPolicy, toInboundMediaFactsWithMetadata } from "openclaw/plugin-sdk/channel-inbound";
|
|
37
39
|
import { resolveGatewayPublicOrigin } from "openclaw/plugin-sdk/config-contracts";
|
|
38
40
|
import { buildControlUiSessionPath } from "openclaw/plugin-sdk/session-discussion";
|
|
39
41
|
import { createStatusReactionController, logAckFailure, logTypingFailure, resolveAckReaction, shouldAckReaction } from "openclaw/plugin-sdk/channel-feedback";
|
|
40
42
|
import { hasControlCommand } from "openclaw/plugin-sdk/command-detection";
|
|
41
43
|
import { isAbortRequestText } from "openclaw/plugin-sdk/command-primitives-runtime";
|
|
42
44
|
import { shouldHandleTextCommands } from "openclaw/plugin-sdk/command-surface";
|
|
45
|
+
import { resolveChannelContextVisibilityMode } from "openclaw/plugin-sdk/context-visibility-runtime";
|
|
46
|
+
import { DEFAULT_GROUP_HISTORY_LIMIT, buildHistoryContextFromEntries, buildInboundHistoryFromEntries } from "openclaw/plugin-sdk/reply-history";
|
|
43
47
|
import { createChannelPreflightAudio, formatAudioTranscriptForAgent } from "openclaw/plugin-sdk/media-understanding-runtime";
|
|
44
48
|
//#region extensions/slack/src/monitor/message-handler/timestamp.ts
|
|
45
49
|
const SLACK_TIMESTAMP_RE = /^\d+(?:\.\d+)?$/;
|
|
@@ -55,9 +59,6 @@ function resolveSlackTimestampMs(ts) {
|
|
|
55
59
|
}
|
|
56
60
|
//#endregion
|
|
57
61
|
//#region extensions/slack/src/monitor/message-handler/dispatch-helpers.ts
|
|
58
|
-
function resolveSlackMessageTimestampMs(message) {
|
|
59
|
-
return resolveSlackTimestampMs(message.event_ts ?? message.ts);
|
|
60
|
-
}
|
|
61
62
|
function resolveSlackBotLoopProtection(prepared) {
|
|
62
63
|
const senderBotId = prepared.message.bot_id;
|
|
63
64
|
if (!senderBotId) return;
|
|
@@ -71,7 +72,7 @@ function resolveSlackBotLoopProtection(prepared) {
|
|
|
71
72
|
config: mergePairLoopGuardConfig(prepared.account.config.botLoopProtection, prepared.channelConfig?.botLoopProtection),
|
|
72
73
|
defaultsConfig: prepared.ctx.cfg.channels?.defaults?.botLoopProtection,
|
|
73
74
|
defaultEnabled: true,
|
|
74
|
-
nowMs:
|
|
75
|
+
nowMs: resolveSlackTimestampMs(prepared.message.event_ts ?? prepared.message.ts)
|
|
75
76
|
};
|
|
76
77
|
}
|
|
77
78
|
function isSlackStreamingEnabled(params) {
|
|
@@ -89,26 +90,14 @@ function resolveExplicitSlackProgressTitle(entry) {
|
|
|
89
90
|
const trimmed = label.trim();
|
|
90
91
|
return trimmed && trimmed.toLowerCase() !== "auto" ? trimmed : void 0;
|
|
91
92
|
}
|
|
92
|
-
function resolveSlackProgressStyle(entry) {
|
|
93
|
+
function resolveSlackProgressStyle(entry, hasReplyThread) {
|
|
93
94
|
const progress = entry?.streaming?.progress;
|
|
95
|
+
if (!hasReplyThread && !Object.entries(progress ?? {}).some(([key, value]) => key !== "nativeTaskCards" || value !== true)) return "none";
|
|
94
96
|
return progress?.style ?? (progress?.toolProgress === false ? "compact" : "card");
|
|
95
97
|
}
|
|
96
|
-
function resolveSlackNativeProgressTaskCards(entry) {
|
|
97
|
-
if (
|
|
98
|
-
|
|
99
|
-
if (!streaming || typeof streaming !== "object" || Array.isArray(streaming)) return true;
|
|
100
|
-
const progressConfig = streaming.progress;
|
|
101
|
-
if (!progressConfig || typeof progressConfig !== "object" || Array.isArray(progressConfig)) return true;
|
|
102
|
-
return progressConfig.nativeTaskCards !== false;
|
|
103
|
-
}
|
|
104
|
-
function resolveSlackStreamingThreadHint(params) {
|
|
105
|
-
return resolveSlackThreadTs({
|
|
106
|
-
replyToMode: params.replyToMode,
|
|
107
|
-
incomingThreadTs: params.incomingThreadTs,
|
|
108
|
-
messageTs: params.messageTs,
|
|
109
|
-
hasReplied: false,
|
|
110
|
-
isThreadReply: params.isThreadReply
|
|
111
|
-
});
|
|
98
|
+
function resolveSlackNativeProgressTaskCards(entry, style) {
|
|
99
|
+
if (style !== "card") return false;
|
|
100
|
+
return entry?.streaming?.progress?.nativeTaskCards !== false;
|
|
112
101
|
}
|
|
113
102
|
const SLACK_STREAM_RECIPIENT_TEAM_CACHE_MAX = 2e3;
|
|
114
103
|
const slackStreamRecipientTeamCaches = /* @__PURE__ */ new WeakMap();
|
|
@@ -123,7 +112,7 @@ function buildSlackEventDeliveryKey(params, preparedReply = prepareSlackReply(pa
|
|
|
123
112
|
const reply = resolveSendableOutboundReplyParts(params.payload, { text: params.textOverride });
|
|
124
113
|
const renderPlan = preparedReply.resolvePreview(params.textOverride);
|
|
125
114
|
const plannedBlocks = renderPlan.mode === "single" ? renderPlan.blocks : renderPlan.blockPart?.blocks;
|
|
126
|
-
const slackBlocks =
|
|
115
|
+
const slackBlocks = resolveSlackReplyBlocks(params.payload) ?? plannedBlocks;
|
|
127
116
|
const renderedText = renderPlan.mode === "single" ? renderPlan.text : renderPlan.fallbackText;
|
|
128
117
|
if (!reply.hasContent && !slackBlocks?.length && !renderedText.trim()) return null;
|
|
129
118
|
return JSON.stringify({
|
|
@@ -135,27 +124,6 @@ function buildSlackEventDeliveryKey(params, preparedReply = prepareSlackReply(pa
|
|
|
135
124
|
blocks: slackBlocks ?? null
|
|
136
125
|
});
|
|
137
126
|
}
|
|
138
|
-
function readSlackStreamRecipientTeamCache(params) {
|
|
139
|
-
if (!params.fallbackTeamId || !params.userId) return;
|
|
140
|
-
const cacheKey = `${params.fallbackTeamId}:${params.userId}`;
|
|
141
|
-
const cache = getSlackStreamRecipientTeamCache(params.client);
|
|
142
|
-
const cached = cache.get(cacheKey);
|
|
143
|
-
if (!cached) return;
|
|
144
|
-
cache.delete(cacheKey);
|
|
145
|
-
cache.set(cacheKey, cached);
|
|
146
|
-
return cached;
|
|
147
|
-
}
|
|
148
|
-
function rememberSlackStreamRecipientTeam(params) {
|
|
149
|
-
if (!params.fallbackTeamId || !params.userId) return;
|
|
150
|
-
const cacheKey = `${params.fallbackTeamId}:${params.userId}`;
|
|
151
|
-
const cache = getSlackStreamRecipientTeamCache(params.client);
|
|
152
|
-
if (cache.has(cacheKey)) cache.delete(cacheKey);
|
|
153
|
-
cache.set(cacheKey, params.teamId);
|
|
154
|
-
if (cache.size > SLACK_STREAM_RECIPIENT_TEAM_CACHE_MAX) {
|
|
155
|
-
const oldest = cache.keys().next().value;
|
|
156
|
-
if (oldest) cache.delete(oldest);
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
127
|
function createSlackEventDeliveryTracker() {
|
|
160
128
|
const deliveredKeys = /* @__PURE__ */ new Set();
|
|
161
129
|
return {
|
|
@@ -176,7 +144,9 @@ function shouldUseStreaming(params) {
|
|
|
176
144
|
return true;
|
|
177
145
|
}
|
|
178
146
|
async function resolveSlackStreamRecipientTeamId(params) {
|
|
179
|
-
const
|
|
147
|
+
const cacheKey = params.fallbackTeamId && params.userId ? `${params.fallbackTeamId}:${params.userId}` : void 0;
|
|
148
|
+
const cache = cacheKey ? getSlackStreamRecipientTeamCache(params.client) : void 0;
|
|
149
|
+
const cachedTeamId = cache && cacheKey ? readLruMapEntry(cache, cacheKey) : void 0;
|
|
180
150
|
if (cachedTeamId) return cachedTeamId;
|
|
181
151
|
if (params.userId) try {
|
|
182
152
|
const info = await params.client.users.info({
|
|
@@ -185,10 +155,7 @@ async function resolveSlackStreamRecipientTeamId(params) {
|
|
|
185
155
|
});
|
|
186
156
|
const teamId = info.user?.team_id ?? info.user?.profile?.team;
|
|
187
157
|
if (teamId) {
|
|
188
|
-
|
|
189
|
-
...params,
|
|
190
|
-
teamId
|
|
191
|
-
});
|
|
158
|
+
if (cache && cacheKey) writeLruMapEntry(cache, cacheKey, teamId, SLACK_STREAM_RECIPIENT_TEAM_CACHE_MAX);
|
|
192
159
|
return teamId;
|
|
193
160
|
}
|
|
194
161
|
} catch (err) {
|
|
@@ -206,17 +173,22 @@ function createSlackDraftStream(params) {
|
|
|
206
173
|
const edit = params.edit ?? editSlackMessage;
|
|
207
174
|
const remove = params.remove ?? deleteSlackMessage;
|
|
208
175
|
let streamMessage;
|
|
176
|
+
let streamGeneration = 0;
|
|
177
|
+
let cleanupGeneration = -1;
|
|
209
178
|
let untrackConversationBoundary;
|
|
210
179
|
let lastVisibleUpdate;
|
|
211
180
|
let lastSentKey = "";
|
|
212
|
-
|
|
213
|
-
let cleanupTail = Promise.resolve();
|
|
214
|
-
const finalizedMessageIds = /* @__PURE__ */ new Set();
|
|
181
|
+
let preserveHumanReplies = false;
|
|
215
182
|
const streamState = {
|
|
216
183
|
stopped: false,
|
|
217
184
|
final: false
|
|
218
185
|
};
|
|
219
186
|
const normalizeUpdate = (update) => typeof update === "string" ? { text: update } : update;
|
|
187
|
+
const clearMessageId = () => {
|
|
188
|
+
streamMessage = void 0;
|
|
189
|
+
lastVisibleUpdate = void 0;
|
|
190
|
+
lastSentKey = "";
|
|
191
|
+
};
|
|
220
192
|
const sendOrEditStreamMessage = async (pending) => {
|
|
221
193
|
if (streamState.stopped) return;
|
|
222
194
|
const update = normalizeUpdate(pending);
|
|
@@ -232,8 +204,10 @@ function createSlackDraftStream(params) {
|
|
|
232
204
|
const sentKey = `${trimmed}\n${blocks ? JSON.stringify(blocks) : ""}`;
|
|
233
205
|
if (sentKey === lastSentKey) return;
|
|
234
206
|
lastSentKey = sentKey;
|
|
207
|
+
const generation = streamGeneration;
|
|
235
208
|
try {
|
|
236
209
|
if (streamMessage) {
|
|
210
|
+
const message = streamMessage;
|
|
237
211
|
await edit(streamMessage.channelId, streamMessage.messageId, trimmed, {
|
|
238
212
|
cfg: params.cfg,
|
|
239
213
|
token: params.token,
|
|
@@ -241,7 +215,7 @@ function createSlackDraftStream(params) {
|
|
|
241
215
|
...params.eventScope ? { client: params.eventScope.client } : {},
|
|
242
216
|
...blocks ? { blocks } : {}
|
|
243
217
|
});
|
|
244
|
-
lastVisibleUpdate = {
|
|
218
|
+
if (streamMessage === message) lastVisibleUpdate = {
|
|
245
219
|
text: trimmed,
|
|
246
220
|
...blocks ? { blocks } : {}
|
|
247
221
|
};
|
|
@@ -266,16 +240,22 @@ function createSlackDraftStream(params) {
|
|
|
266
240
|
...params.metadata ? { metadata: params.metadata } : {},
|
|
267
241
|
...blocks ? { blocks } : {}
|
|
268
242
|
});
|
|
243
|
+
const sentMessage = {
|
|
244
|
+
channelId: sent.channelId,
|
|
245
|
+
messageId: sent.messageId,
|
|
246
|
+
generation
|
|
247
|
+
};
|
|
248
|
+
if (generation !== streamGeneration) {
|
|
249
|
+
if (sent.channelId && sent.messageId) lifecycle.retire(sentMessage, { defer: true });
|
|
250
|
+
return;
|
|
251
|
+
}
|
|
269
252
|
if (!sent.channelId || !sent.messageId) {
|
|
270
253
|
stopTrackingConversationBoundary();
|
|
271
254
|
streamState.stopped = true;
|
|
272
255
|
params.warn?.("slack stream preview stopped (missing identifiers from sendMessage)");
|
|
273
256
|
return;
|
|
274
257
|
}
|
|
275
|
-
streamMessage =
|
|
276
|
-
channelId: sent.channelId,
|
|
277
|
-
messageId: sent.messageId
|
|
278
|
-
};
|
|
258
|
+
streamMessage = sentMessage;
|
|
279
259
|
lastVisibleUpdate = {
|
|
280
260
|
text: trimmed,
|
|
281
261
|
...blocks ? { blocks } : {}
|
|
@@ -293,72 +273,84 @@ function createSlackDraftStream(params) {
|
|
|
293
273
|
}).stop;
|
|
294
274
|
}
|
|
295
275
|
} catch (err) {
|
|
296
|
-
|
|
297
|
-
|
|
276
|
+
if (generation === streamGeneration) {
|
|
277
|
+
stopTrackingConversationBoundary();
|
|
278
|
+
streamState.stopped = true;
|
|
279
|
+
}
|
|
298
280
|
params.warn?.(`slack stream preview failed: ${formatSlackError(err)}`);
|
|
299
281
|
}
|
|
300
282
|
};
|
|
301
|
-
const
|
|
283
|
+
const lifecycle = createFinalizableDraftLifecycle({
|
|
302
284
|
throttleMs,
|
|
303
285
|
coalesceInFlight: true,
|
|
304
286
|
state: streamState,
|
|
305
287
|
sendOrEditStreamMessage,
|
|
306
288
|
emptyValue: "",
|
|
307
|
-
isEmpty: (value) => !normalizeUpdate(value).text.trim()
|
|
289
|
+
isEmpty: (value) => !normalizeUpdate(value).text.trim(),
|
|
290
|
+
readMessageId: () => streamMessage,
|
|
291
|
+
clearMessageId,
|
|
292
|
+
isValidMessageId: (value) => typeof value === "object" && value !== null,
|
|
293
|
+
deleteMessage: async (message) => {
|
|
294
|
+
if (message.generation > cleanupGeneration) return false;
|
|
295
|
+
if (!message.retained && !(preserveHumanReplies && message.detachedByHuman)) await remove(message.channelId, message.messageId, {
|
|
296
|
+
token: params.token,
|
|
297
|
+
accountId: params.accountId,
|
|
298
|
+
...params.eventScope ? { client: params.eventScope.client } : {}
|
|
299
|
+
});
|
|
300
|
+
return true;
|
|
301
|
+
},
|
|
302
|
+
warn: params.warn,
|
|
303
|
+
warnPrefix: "slack stream preview cleanup failed"
|
|
308
304
|
});
|
|
305
|
+
const { loop, update, discardPending, seal } = lifecycle;
|
|
309
306
|
const stopTrackingConversationBoundary = () => {
|
|
310
307
|
untrackConversationBoundary?.();
|
|
311
308
|
untrackConversationBoundary = void 0;
|
|
312
309
|
};
|
|
313
|
-
const dropDetachedMessages = (
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
if (preserveHumanReplies && message.detachedByHuman) {
|
|
319
|
-
pendingCleanupMessages.splice(index, 1);
|
|
320
|
-
continue;
|
|
321
|
-
}
|
|
322
|
-
try {
|
|
323
|
-
await remove(message.channelId, message.messageId, {
|
|
324
|
-
token: params.token,
|
|
325
|
-
accountId: params.accountId,
|
|
326
|
-
...params.eventScope ? { client: params.eventScope.client } : {}
|
|
327
|
-
});
|
|
328
|
-
pendingCleanupMessages.splice(index, 1);
|
|
329
|
-
} catch (err) {
|
|
330
|
-
params.warn?.(`slack stream preview cleanup failed: ${formatSlackError(err)}`);
|
|
331
|
-
index += 1;
|
|
332
|
-
}
|
|
333
|
-
}
|
|
310
|
+
const dropDetachedMessages = () => {
|
|
311
|
+
const generation = streamGeneration;
|
|
312
|
+
return lifecycle.cleanupPending(() => {
|
|
313
|
+
preserveHumanReplies = false;
|
|
314
|
+
cleanupGeneration = generation;
|
|
334
315
|
});
|
|
335
|
-
return cleanupTail;
|
|
336
316
|
};
|
|
337
317
|
const discardPendingAndStopTracking = async () => {
|
|
318
|
+
const generation = streamGeneration;
|
|
338
319
|
await discardPending();
|
|
339
|
-
stopTrackingConversationBoundary();
|
|
320
|
+
if (generation === streamGeneration) stopTrackingConversationBoundary();
|
|
340
321
|
};
|
|
341
322
|
const clear = async (options) => {
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
323
|
+
const generation = streamGeneration;
|
|
324
|
+
let clearingMessage = streamMessage;
|
|
325
|
+
await lifecycle.clearWithStop(async () => {
|
|
326
|
+
if (generation === streamGeneration) {
|
|
327
|
+
await discardPendingAndStopTracking();
|
|
328
|
+
if (generation === streamGeneration) {
|
|
329
|
+
clearingMessage = streamMessage;
|
|
330
|
+
clearMessageId();
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
cleanupGeneration = generation;
|
|
334
|
+
preserveHumanReplies = options?.preserveHumanReplies === true;
|
|
335
|
+
}, {
|
|
336
|
+
readMessageId: () => clearingMessage,
|
|
337
|
+
clearMessageId: () => {
|
|
338
|
+
clearingMessage = void 0;
|
|
339
|
+
}
|
|
340
|
+
});
|
|
350
341
|
};
|
|
351
342
|
const forceNewMessage = (reason = "turn") => {
|
|
352
343
|
stopTrackingConversationBoundary();
|
|
353
|
-
if (reason === "turn")
|
|
344
|
+
if (reason === "turn") {
|
|
345
|
+
streamState.stopped = false;
|
|
346
|
+
streamGeneration += 1;
|
|
347
|
+
}
|
|
354
348
|
streamState.final = false;
|
|
355
|
-
if (streamMessage && !
|
|
349
|
+
if (streamMessage && !streamMessage.retained) {
|
|
356
350
|
streamMessage.detachedByHuman = reason === "human";
|
|
357
|
-
|
|
351
|
+
lifecycle.retire(streamMessage, { defer: true });
|
|
358
352
|
}
|
|
359
|
-
|
|
360
|
-
lastVisibleUpdate = void 0;
|
|
361
|
-
lastSentKey = "";
|
|
353
|
+
clearMessageId();
|
|
362
354
|
loop.resetPending();
|
|
363
355
|
};
|
|
364
356
|
const finalizeMessage = async (messageId, editFinal) => {
|
|
@@ -368,7 +360,7 @@ function createSlackDraftStream(params) {
|
|
|
368
360
|
const { channelId } = currentMessage;
|
|
369
361
|
await editFinal();
|
|
370
362
|
if (streamMessage?.channelId === channelId && streamMessage.messageId === messageId) {
|
|
371
|
-
|
|
363
|
+
currentMessage.retained = true;
|
|
372
364
|
stopTrackingConversationBoundary();
|
|
373
365
|
return true;
|
|
374
366
|
}
|
|
@@ -459,12 +451,11 @@ const SLACK_PROGRESS_TASK_TITLE_MAX = 120;
|
|
|
459
451
|
const SLACK_PROGRESS_PLAN_FALLBACK_TITLE = "Thinking";
|
|
460
452
|
const SLACK_PROGRESS_LINE_DELTA_RE = /(?:^|\s)\+(\d+)\s+[−-](\d+)(?=\s|$)/u;
|
|
461
453
|
const SLACK_ATTENTION_TASK_PREFIX = "openclaw-attention-";
|
|
462
|
-
function buildSessionSources(
|
|
463
|
-
return
|
|
454
|
+
function buildSessionSources(links) {
|
|
455
|
+
return links.map((link) => ({
|
|
464
456
|
type: "url_source",
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
}];
|
|
457
|
+
...link
|
|
458
|
+
}));
|
|
468
459
|
}
|
|
469
460
|
function field(text) {
|
|
470
461
|
return {
|
|
@@ -620,12 +611,13 @@ function buildSlackProgressStreamChunks(params) {
|
|
|
620
611
|
});
|
|
621
612
|
}
|
|
622
613
|
const headline = params.title?.trim() || params.label?.trim();
|
|
614
|
+
const summaryTitle = params.finalInProgressStatus === "error" ? "Failed" : params.finalInProgressStatus === "complete" || !params.summaryRow ? "Completed" : "Working";
|
|
623
615
|
const newest = tasks.at(-1);
|
|
624
|
-
const title = compactChunkText(headline || (newest?.details ? `${newest.title} — ${newest.details}` : newest?.title) || (params.summaryRow ?
|
|
616
|
+
const title = compactChunkText(headline || (newest?.details ? `${newest.title} — ${newest.details}` : newest?.title) || (params.summaryRow ? summaryTitle : attention.at(-1)?.title) || SLACK_PROGRESS_PLAN_FALLBACK_TITLE);
|
|
625
617
|
const diffOutput = formatTaskDiffOutput(params.diffStat);
|
|
626
|
-
if (tasks.length === 0 && (params.summaryRow || params.
|
|
618
|
+
if (tasks.length === 0 && (params.summaryRow || params.sessionLinks?.length || diffOutput)) tasks.push({
|
|
627
619
|
id: "openclaw_summary",
|
|
628
|
-
title: params.summaryRow ? compactTitle(title) :
|
|
620
|
+
title: params.summaryRow ? compactTitle(title) : summaryTitle,
|
|
629
621
|
status: params.finalInProgressStatus ?? (params.summaryRow ? "in_progress" : "complete")
|
|
630
622
|
});
|
|
631
623
|
tasks.push(...attention);
|
|
@@ -647,7 +639,7 @@ function buildSlackProgressStreamChunks(params) {
|
|
|
647
639
|
if (task.details) chunk.details = task.details;
|
|
648
640
|
if (task.output) chunk.output = task.output;
|
|
649
641
|
if (index === finalTaskIndex && diffOutput) chunk.output = [task.output, diffOutput].filter(Boolean).join(" · ");
|
|
650
|
-
if (index === finalTaskIndex && params.
|
|
642
|
+
if (index === finalTaskIndex && params.sessionLinks?.length) chunk.sources = buildSessionSources(params.sessionLinks);
|
|
651
643
|
return chunk;
|
|
652
644
|
});
|
|
653
645
|
return [{
|
|
@@ -699,7 +691,7 @@ function buildSlackProgressCardBlocks(params) {
|
|
|
699
691
|
buildActivityText(params.lines.filter((line) => line.kind !== "approval" && lineTaskStatus(line) !== "error"), maxLineChars),
|
|
700
692
|
joinRecentProgressRows(attention)
|
|
701
693
|
];
|
|
702
|
-
const title = params.title
|
|
694
|
+
const title = params.title?.trim() || (params.state === "working" ? "Working" : params.state === "success" ? "Done" : "Failed");
|
|
703
695
|
const blocks = [
|
|
704
696
|
params.titleFormat === "plain" ? progressTextSection({
|
|
705
697
|
text: `${icon} ${title}`,
|
|
@@ -718,17 +710,17 @@ function buildSlackProgressCardBlocks(params) {
|
|
|
718
710
|
type: "context",
|
|
719
711
|
elements: [field(footer)]
|
|
720
712
|
});
|
|
721
|
-
if (params.state !== "working" && params.
|
|
713
|
+
if (params.state !== "working" && params.sessionLinks?.length) blocks.push({
|
|
722
714
|
type: "actions",
|
|
723
|
-
elements:
|
|
715
|
+
elements: params.sessionLinks.map((link, index) => ({
|
|
724
716
|
type: "button",
|
|
725
|
-
action_id: SLACK_SESSION_LINK_ACTION_ID
|
|
717
|
+
action_id: index === 0 ? SLACK_SESSION_LINK_ACTION_ID : `${SLACK_SESSION_LINK_ACTION_ID}:${index}`,
|
|
726
718
|
text: {
|
|
727
719
|
type: "plain_text",
|
|
728
|
-
text:
|
|
720
|
+
text: link.text
|
|
729
721
|
},
|
|
730
|
-
url:
|
|
731
|
-
}
|
|
722
|
+
url: link.url
|
|
723
|
+
}))
|
|
732
724
|
});
|
|
733
725
|
return blocks.slice(0, 50);
|
|
734
726
|
}
|
|
@@ -913,25 +905,20 @@ function blocksMatch(expected, actual) {
|
|
|
913
905
|
}
|
|
914
906
|
}
|
|
915
907
|
async function readSlackMessageAfterEditError(params) {
|
|
916
|
-
|
|
917
|
-
token: params.token,
|
|
918
|
-
channel: params.channelId,
|
|
919
|
-
ts: params.threadTs,
|
|
920
|
-
latest: params.messageId,
|
|
921
|
-
oldest: params.messageId,
|
|
922
|
-
inclusive: true,
|
|
923
|
-
limit: 1
|
|
924
|
-
})).messages ?? []).find((message) => message?.ts === params.messageId) ?? null;
|
|
925
|
-
const message = (await params.client.conversations.history({
|
|
908
|
+
const query = {
|
|
926
909
|
token: params.token,
|
|
927
910
|
channel: params.channelId,
|
|
928
911
|
latest: params.messageId,
|
|
929
912
|
oldest: params.messageId,
|
|
930
913
|
inclusive: true,
|
|
931
914
|
limit: 1
|
|
932
|
-
}
|
|
933
|
-
|
|
934
|
-
|
|
915
|
+
};
|
|
916
|
+
const result = params.threadTs ? await params.client.conversations.replies({
|
|
917
|
+
...query,
|
|
918
|
+
ts: params.threadTs
|
|
919
|
+
}) : await params.client.conversations.history(query);
|
|
920
|
+
const message = params.threadTs ? result.messages?.find((entry) => entry?.ts === params.messageId) : result.messages?.[0];
|
|
921
|
+
return message?.ts && message.ts === params.messageId ? message : null;
|
|
935
922
|
}
|
|
936
923
|
async function didSlackPreviewEditApplyAfterError(params) {
|
|
937
924
|
const readback = await readSlackMessageAfterEditError(params);
|
|
@@ -958,15 +945,7 @@ async function finalizeSlackPreviewEdit(params) {
|
|
|
958
945
|
});
|
|
959
946
|
} catch (err) {
|
|
960
947
|
try {
|
|
961
|
-
if (await didSlackPreviewEditApplyAfterError({
|
|
962
|
-
client: params.client,
|
|
963
|
-
token: params.token,
|
|
964
|
-
channelId: params.channelId,
|
|
965
|
-
messageId: params.messageId,
|
|
966
|
-
text: params.text,
|
|
967
|
-
blocks: params.blocks,
|
|
968
|
-
threadTs: params.threadTs
|
|
969
|
-
})) {
|
|
948
|
+
if (await didSlackPreviewEditApplyAfterError(params)) {
|
|
970
949
|
logVerbose(`slack: preview final edit response failed but readback matched message ${params.channelId}/${params.messageId}; suppressing duplicate fallback send`);
|
|
971
950
|
return;
|
|
972
951
|
}
|
|
@@ -978,37 +957,39 @@ async function finalizeSlackPreviewEdit(params) {
|
|
|
978
957
|
}
|
|
979
958
|
//#endregion
|
|
980
959
|
//#region extensions/slack/src/monitor/message-handler/dispatch-progress-card.ts
|
|
960
|
+
const MAX_VISIBLE_WORK_LINKS = 5;
|
|
981
961
|
function createSlackDraftProgressCardRuntime(params) {
|
|
982
962
|
const { account, cfg, ctx, prepared, slackClient } = params.setup;
|
|
983
|
-
let latestFallbackText = "";
|
|
984
963
|
let finalStatus;
|
|
985
|
-
const
|
|
986
|
-
|
|
964
|
+
const visibleWorkSessions = /* @__PURE__ */ new Map();
|
|
965
|
+
const resolveSessionLinks = () => {
|
|
966
|
+
if (visibleWorkSessions.size > 0) return [...visibleWorkSessions.values()].slice(0, MAX_VISIBLE_WORK_LINKS).map((session, index) => {
|
|
967
|
+
const label = session.label?.replace(/\s+/g, " ").trim();
|
|
968
|
+
return {
|
|
969
|
+
url: session.url,
|
|
970
|
+
text: visibleWorkSessions.size === 1 ? "Open work session" : truncateSlackText(label ? `Open ${label}` : `Open work session ${index + 1}`, 75)
|
|
971
|
+
};
|
|
972
|
+
});
|
|
973
|
+
if (cfg.gateway?.controlUi?.enabled === false) return [];
|
|
987
974
|
const publicOrigin = resolveGatewayPublicOrigin(cfg);
|
|
988
|
-
if (!publicOrigin) return;
|
|
975
|
+
if (!publicOrigin) return [];
|
|
989
976
|
const url = new URL(publicOrigin);
|
|
990
977
|
const path = buildControlUiSessionPath({
|
|
991
978
|
namespace: "chat",
|
|
992
|
-
sessionKey: prepared.route.sessionKey,
|
|
979
|
+
sessionKey: prepared.ctxPayload.SessionKey ?? prepared.route.sessionKey,
|
|
993
980
|
fallbackAgentId: prepared.route.agentId,
|
|
981
|
+
mainKey: cfg.session?.mainKey,
|
|
994
982
|
basePath: cfg.gateway?.controlUi?.basePath
|
|
995
983
|
});
|
|
996
|
-
if (!path) return;
|
|
984
|
+
if (!path) return [];
|
|
997
985
|
url.pathname = path;
|
|
998
|
-
return
|
|
986
|
+
return [{
|
|
987
|
+
url: url.toString(),
|
|
988
|
+
text: "Open in OpenClaw"
|
|
989
|
+
}];
|
|
999
990
|
};
|
|
1000
|
-
const resolveText = (snapshot) => latestFallbackText || formatChannelProgressDraftText({
|
|
1001
|
-
entry: account.config,
|
|
1002
|
-
lines: [...snapshot.lines],
|
|
1003
|
-
seed: params.progressSeed,
|
|
1004
|
-
formatLine: formatSlackProgressDraftLine,
|
|
1005
|
-
narration: snapshot.statusHeadline,
|
|
1006
|
-
narrationFormat: snapshot.statusHeadlineFormat,
|
|
1007
|
-
plan: snapshot.plan,
|
|
1008
|
-
diffStat: snapshot.diffStat
|
|
1009
|
-
});
|
|
1010
991
|
const resolvePresentation = (snapshot, state) => {
|
|
1011
|
-
const title = params.explicitTitle ?? snapshot.statusHeadline
|
|
992
|
+
const title = params.explicitTitle ?? snapshot.statusHeadline;
|
|
1012
993
|
const titleFormat = params.explicitTitle ? void 0 : snapshot.statusHeadlineFormat;
|
|
1013
994
|
const narration = params.explicitTitle ? snapshot.statusHeadlineFormat === "plain" || snapshot.planExplanationFormat === "plain" ? [...snapshot.statusHeadline && (snapshot.statusHeadline !== snapshot.planExplanation || snapshot.statusHeadlineFormat !== snapshot.planExplanationFormat) ? [{
|
|
1014
995
|
text: snapshot.statusHeadline,
|
|
@@ -1021,7 +1002,7 @@ function createSlackDraftProgressCardRuntime(params) {
|
|
|
1021
1002
|
format: snapshot.planExplanationFormat
|
|
1022
1003
|
}] : void 0;
|
|
1023
1004
|
const workCounter = state === "working" ? params.progressWorkCounter : void 0;
|
|
1024
|
-
const
|
|
1005
|
+
const sessionLinks = state === "working" ? [] : resolveSessionLinks();
|
|
1025
1006
|
return buildSlackProgressCardBlocks({
|
|
1026
1007
|
state,
|
|
1027
1008
|
title,
|
|
@@ -1033,10 +1014,10 @@ function createSlackDraftProgressCardRuntime(params) {
|
|
|
1033
1014
|
diffStat: snapshot.diffStat,
|
|
1034
1015
|
toolCalls: workCounter?.toolCalls,
|
|
1035
1016
|
elapsedSeconds: workCounter?.elapsedSeconds,
|
|
1036
|
-
|
|
1017
|
+
sessionLinks
|
|
1037
1018
|
});
|
|
1038
1019
|
};
|
|
1039
|
-
const finalize = async (status, snapshot = params.getSnapshot()
|
|
1020
|
+
const finalize = async (status, snapshot = params.getSnapshot()) => {
|
|
1040
1021
|
if (!params.draftStream || !params.enabled) return false;
|
|
1041
1022
|
await params.draftStream.dropDetachedMessages();
|
|
1042
1023
|
const terminalStatus = finalStatus === "error" || status === "error" ? "error" : "success";
|
|
@@ -1048,14 +1029,15 @@ function createSlackDraftProgressCardRuntime(params) {
|
|
|
1048
1029
|
await params.draftStream.seal();
|
|
1049
1030
|
try {
|
|
1050
1031
|
const finalized = await params.draftStream.finalizeMessage(messageId, async () => {
|
|
1032
|
+
const blocks = resolvePresentation(snapshot, terminalStatus);
|
|
1051
1033
|
await finalizeSlackPreviewEdit({
|
|
1052
1034
|
client: slackClient,
|
|
1053
1035
|
token: ctx.botToken,
|
|
1054
1036
|
accountId: account.accountId,
|
|
1055
1037
|
channelId,
|
|
1056
1038
|
messageId,
|
|
1057
|
-
text:
|
|
1058
|
-
blocks
|
|
1039
|
+
text: buildSlackCompleteBlocksFallbackText(blocks),
|
|
1040
|
+
blocks,
|
|
1059
1041
|
threadTs: params.getThreadTs()
|
|
1060
1042
|
});
|
|
1061
1043
|
});
|
|
@@ -1067,19 +1049,18 @@ function createSlackDraftProgressCardRuntime(params) {
|
|
|
1067
1049
|
}
|
|
1068
1050
|
};
|
|
1069
1051
|
return {
|
|
1070
|
-
|
|
1071
|
-
|
|
1052
|
+
resolveSessionLinks,
|
|
1053
|
+
onVisibleWorkSessions: (sessions) => {
|
|
1054
|
+
for (const session of sessions) if (!visibleWorkSessions.has(session.sessionKey)) visibleWorkSessions.set(session.sessionKey, session);
|
|
1055
|
+
},
|
|
1072
1056
|
resolvePresentation,
|
|
1073
1057
|
finalize,
|
|
1074
1058
|
get hasTerminalized() {
|
|
1075
1059
|
return finalStatus !== void 0;
|
|
1076
1060
|
},
|
|
1077
|
-
setFallbackText(text) {
|
|
1078
|
-
latestFallbackText = text;
|
|
1079
|
-
},
|
|
1080
1061
|
reset() {
|
|
1081
|
-
latestFallbackText = "";
|
|
1082
1062
|
finalStatus = void 0;
|
|
1063
|
+
visibleWorkSessions.clear();
|
|
1083
1064
|
}
|
|
1084
1065
|
};
|
|
1085
1066
|
}
|
|
@@ -1095,15 +1076,12 @@ function formatSlackProgressDraftLine(line) {
|
|
|
1095
1076
|
//#endregion
|
|
1096
1077
|
//#region extensions/slack/src/monitor/message-handler/dispatch-progress-native.ts
|
|
1097
1078
|
function createSlackNativeProgressTransport(params) {
|
|
1098
|
-
const {
|
|
1079
|
+
const { replyPlan } = params.setup;
|
|
1099
1080
|
const { delivery } = params;
|
|
1100
1081
|
const markDelivered = (threadTs) => {
|
|
1101
1082
|
if (!delivery.streamSession?.delivered) return false;
|
|
1102
1083
|
delivery.observedReplyDelivery = true;
|
|
1103
|
-
if (threadTs)
|
|
1104
|
-
delivery.usedReplyThreadTs ??= threadTs;
|
|
1105
|
-
delivery.rememberDeliveredThreadTs("block", threadTs);
|
|
1106
|
-
}
|
|
1084
|
+
if (threadTs) delivery.rememberDeliveredThreadTs("block", threadTs);
|
|
1107
1085
|
return true;
|
|
1108
1086
|
};
|
|
1109
1087
|
const waitForStart = async () => {
|
|
@@ -1124,30 +1102,15 @@ function createSlackNativeProgressTransport(params) {
|
|
|
1124
1102
|
return false;
|
|
1125
1103
|
}
|
|
1126
1104
|
delivery.nativeProgressStreamThreadTs = streamThreadTs;
|
|
1127
|
-
const startPromise = (
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
...update.text ? { text: update.text } : {},
|
|
1134
|
-
...update.chunks?.length ? { chunks: update.chunks } : {},
|
|
1135
|
-
taskDisplayMode: "plan",
|
|
1136
|
-
...slackIdentity ? { identity: slackIdentity } : {},
|
|
1137
|
-
teamId: await resolveSlackStreamRecipientTeamId({
|
|
1138
|
-
client: slackClient,
|
|
1139
|
-
token: ctx.botToken,
|
|
1140
|
-
userId: message.user,
|
|
1141
|
-
fallbackTeamId: slackStreamFallbackTeamId
|
|
1142
|
-
}),
|
|
1143
|
-
userId: message.user
|
|
1144
|
-
});
|
|
1145
|
-
delivery.streamSession = session;
|
|
1146
|
-
return session;
|
|
1147
|
-
})();
|
|
1105
|
+
const startPromise = delivery.startStream({
|
|
1106
|
+
threadTs: streamThreadTs,
|
|
1107
|
+
...update.text ? { text: update.text } : {},
|
|
1108
|
+
...update.chunks?.length ? { chunks: update.chunks } : {},
|
|
1109
|
+
taskDisplayMode: "plan"
|
|
1110
|
+
});
|
|
1148
1111
|
delivery.nativeProgressStreamStartPromise = startPromise;
|
|
1149
1112
|
try {
|
|
1150
|
-
|
|
1113
|
+
await startPromise;
|
|
1151
1114
|
const delivered = markDelivered(streamThreadTs);
|
|
1152
1115
|
return update.chunks?.length ? delivered : true;
|
|
1153
1116
|
} finally {
|
|
@@ -1174,8 +1137,8 @@ function createSlackNativeProgressTransport(params) {
|
|
|
1174
1137
|
//#endregion
|
|
1175
1138
|
//#region extensions/slack/src/monitor/message-handler/dispatch-progress.ts
|
|
1176
1139
|
function createSlackProgressRuntime(runtimeParams) {
|
|
1177
|
-
const { setup, delivery
|
|
1178
|
-
const { account, cfg, ctx, hasSlackCustomIdentity, message, prepared, replyPlan, runtime, slackClient, slackIdentity, slackMessageMetadata, slackStreaming, shouldUseDraftStream, useStreaming, previewStreamingEnabled } = setup;
|
|
1140
|
+
const { setup, delivery } = runtimeParams;
|
|
1141
|
+
const { account, cfg, ctx, hasSlackCustomIdentity, message, prepared, replyPlan, runtime, slackClient, slackIdentity, slackMessageMetadata, slackStreaming, slackProgressStyle, quietProgress, shouldUseDraftStream, useStreaming, previewStreamingEnabled } = setup;
|
|
1179
1142
|
const draftStream = shouldUseDraftStream ? createSlackDraftStream({
|
|
1180
1143
|
target: prepared.replyTarget,
|
|
1181
1144
|
cfg,
|
|
@@ -1199,7 +1162,7 @@ function createSlackProgressRuntime(runtimeParams) {
|
|
|
1199
1162
|
const progressDraftActive = Boolean(draftStream) || useNativeProgressStreaming;
|
|
1200
1163
|
const previewToolProgressEnabled = progressDraftActive && resolveChannelStreamingPreviewToolProgress(account.config, slackStreaming.mode !== "progress", slackStreaming.mode);
|
|
1201
1164
|
let shouldYieldDraftProgress = () => false;
|
|
1202
|
-
const suppressDefaultToolProgressMessages = resolveChannelStreamingSuppressDefaultToolProgressMessages(account.config, {
|
|
1165
|
+
const suppressDefaultToolProgressMessages = quietProgress || resolveChannelStreamingSuppressDefaultToolProgressMessages(account.config, {
|
|
1203
1166
|
draftStreamActive: Boolean(draftStream) || useNativeProgressStreaming,
|
|
1204
1167
|
mode: slackStreaming.mode,
|
|
1205
1168
|
previewToolProgressEnabled,
|
|
@@ -1220,7 +1183,6 @@ function createSlackProgressRuntime(runtimeParams) {
|
|
|
1220
1183
|
};
|
|
1221
1184
|
const progressWorkCounter = createChannelProgressWorkCounter();
|
|
1222
1185
|
const progressSeed = `${account.accountId}:${message.channel}`;
|
|
1223
|
-
const slackProgressStyle = resolveSlackProgressStyle(account.config);
|
|
1224
1186
|
const preambleOnlyProgress = isProgressMode && slackProgressStyle === "compact" && !previewToolProgressEnabled;
|
|
1225
1187
|
const useDraftProgressCard = Boolean(draftStream) && isProgressMode && slackProgressStyle === "card";
|
|
1226
1188
|
const explicitProgressTitle = resolveExplicitSlackProgressTitle(account.config);
|
|
@@ -1236,7 +1198,6 @@ function createSlackProgressRuntime(runtimeParams) {
|
|
|
1236
1198
|
draftStream,
|
|
1237
1199
|
enabled: useDraftProgressCard,
|
|
1238
1200
|
progressWorkCounter: previewToolProgressEnabled ? progressWorkCounter : void 0,
|
|
1239
|
-
progressSeed,
|
|
1240
1201
|
explicitTitle: explicitProgressTitle,
|
|
1241
1202
|
maxLineChars: progressDraftMaxLineChars,
|
|
1242
1203
|
getSnapshot: () => progressDraft.getSnapshot(),
|
|
@@ -1345,30 +1306,30 @@ function createSlackProgressRuntime(runtimeParams) {
|
|
|
1345
1306
|
nativeUpdates.stop();
|
|
1346
1307
|
await nativeUpdates.waitForInFlight();
|
|
1347
1308
|
};
|
|
1348
|
-
const appendNativeNarration = (payload, kind) => withNativeStreamOrder(() =>
|
|
1349
|
-
|
|
1350
|
-
if (isRenderedAsProgressTitle(payload.text)) return false;
|
|
1309
|
+
const appendNativeNarration = (payload, kind) => withNativeStreamOrder(async () => {
|
|
1310
|
+
if (isRenderedAsProgressTitle(payload.text)) return { visibleReplySent: false };
|
|
1351
1311
|
const narrationUpdate = resolveNarrationUpdate(payload.text?.trimEnd());
|
|
1352
|
-
if (!narrationUpdate.delta) return false;
|
|
1353
|
-
await delivery.deliverWithStreaming({
|
|
1312
|
+
if (!narrationUpdate.delta) return { visibleReplySent: false };
|
|
1313
|
+
const result = await delivery.deliverWithStreaming({
|
|
1354
1314
|
payload,
|
|
1355
1315
|
kind,
|
|
1356
1316
|
streamText: narrationUpdate.delta,
|
|
1357
1317
|
appendSeparator: false,
|
|
1358
1318
|
taskDisplayMode: "plan"
|
|
1359
1319
|
});
|
|
1360
|
-
if (!delivery.streamFailed) {
|
|
1320
|
+
if (result.visibleReplySent && !delivery.streamFailed) {
|
|
1361
1321
|
nativeNarrationRenderedText = narrationUpdate.next.rendered;
|
|
1362
1322
|
nativeNarrationSourceText = narrationUpdate.next.source;
|
|
1363
1323
|
}
|
|
1364
|
-
return
|
|
1365
|
-
};
|
|
1324
|
+
return result;
|
|
1325
|
+
});
|
|
1366
1326
|
const resetProgressTurnState = () => {
|
|
1367
1327
|
progressWorkCounter.reset();
|
|
1368
1328
|
nativeNarrationRenderedText = "";
|
|
1369
1329
|
nativeNarrationSourceText = "";
|
|
1370
1330
|
};
|
|
1371
1331
|
const progressDraft = createChannelProgressDraftCompositor({
|
|
1332
|
+
preparedItems: true,
|
|
1372
1333
|
entry: account.config,
|
|
1373
1334
|
mode: slackStreaming.mode,
|
|
1374
1335
|
active: progressDraftActive,
|
|
@@ -1390,7 +1351,6 @@ function createSlackProgressRuntime(runtimeParams) {
|
|
|
1390
1351
|
const snapshot = options.snapshot;
|
|
1391
1352
|
const latestLine = snapshot.lines.at(-1);
|
|
1392
1353
|
if (preambleOnlyProgress && typeof latestLine === "object" && latestLine.complete === false) return false;
|
|
1393
|
-
progressCard.setFallbackText(previewText);
|
|
1394
1354
|
draftStream.update(preambleOnlyProgress ? {
|
|
1395
1355
|
text: previewText,
|
|
1396
1356
|
allowNewMessage: typeof latestLine !== "object" || latestLine.complete !== false,
|
|
@@ -1415,51 +1375,70 @@ function createSlackProgressRuntime(runtimeParams) {
|
|
|
1415
1375
|
}
|
|
1416
1376
|
}
|
|
1417
1377
|
});
|
|
1378
|
+
const previewLifecycle = createLivePreviewLifecycle({
|
|
1379
|
+
draft: draftStream && !useDraftProgressCard ? {
|
|
1380
|
+
flush: draftStream.flush,
|
|
1381
|
+
discardPending: draftStream.discardPending,
|
|
1382
|
+
seal: draftStream.seal,
|
|
1383
|
+
id: () => {
|
|
1384
|
+
const channelId = draftStream.channelId();
|
|
1385
|
+
const messageId = draftStream.messageId();
|
|
1386
|
+
return channelId && messageId ? {
|
|
1387
|
+
channelId,
|
|
1388
|
+
messageId
|
|
1389
|
+
} : void 0;
|
|
1390
|
+
},
|
|
1391
|
+
clear: async () => {
|
|
1392
|
+
await draftStream.clear({ preserveHumanReplies: !isProgressMode && previewLifecycle.finalDelivered });
|
|
1393
|
+
}
|
|
1394
|
+
} : void 0,
|
|
1395
|
+
cleanupUndelivered: true,
|
|
1396
|
+
onFinalStarted: () => progressDraft.markFinalReplyStarted(),
|
|
1397
|
+
onFinalDelivered: () => progressDraft.markFinalReplyDelivered(),
|
|
1398
|
+
onCleanupFailure: (error) => logVerbose(`slack: progress preview cleanup failed (${formatSlackError(error)})`)
|
|
1399
|
+
});
|
|
1418
1400
|
const commentaryProgressEnabled = progressDraft.commentaryProgressEnabled;
|
|
1419
1401
|
const deliverNativeFinal = async (payload, kind) => {
|
|
1420
|
-
progressDraft.markFinalReplyStarted();
|
|
1421
1402
|
await cancelNativeUpdates();
|
|
1422
|
-
await withNativeStreamOrder(() => deliverNativeFinalNow(payload, kind));
|
|
1403
|
+
return await withNativeStreamOrder(() => deliverNativeFinalNow(payload, kind));
|
|
1423
1404
|
};
|
|
1424
1405
|
const deliverNativeFinalNow = async (payload, kind) => {
|
|
1425
|
-
progressDraft.markFinalReplyStarted();
|
|
1426
1406
|
const streamReady = await nativeTransport.waitForStart();
|
|
1427
1407
|
const finalThreadTs = delivery.streamSession?.threadTs ?? delivery.nativeProgressStreamThreadTs;
|
|
1428
1408
|
if (payload.isError !== true && streamReady && Boolean(delivery.streamSession) && delivery.isStreamingEligible(payload, { maxTextBytes: 4e3 })) {
|
|
1429
1409
|
await appendNativeProgressCompletion(false);
|
|
1430
|
-
await delivery.deliverWithStreaming({
|
|
1410
|
+
return await delivery.deliverWithStreaming({
|
|
1431
1411
|
payload,
|
|
1432
1412
|
kind
|
|
1433
1413
|
});
|
|
1434
|
-
} else {
|
|
1435
|
-
await delivery.deliverNormally({
|
|
1436
|
-
payload,
|
|
1437
|
-
kind,
|
|
1438
|
-
forcedThreadTs: finalThreadTs
|
|
1439
|
-
});
|
|
1440
|
-
await appendNativeProgressCompletion(payload.isError === true);
|
|
1441
1414
|
}
|
|
1442
|
-
|
|
1415
|
+
const result = await delivery.deliverNormally({
|
|
1416
|
+
payload,
|
|
1417
|
+
kind,
|
|
1418
|
+
forcedThreadTs: finalThreadTs
|
|
1419
|
+
});
|
|
1420
|
+
await appendNativeProgressCompletion(payload.isError === true);
|
|
1421
|
+
return result;
|
|
1443
1422
|
};
|
|
1444
1423
|
const buildNativeProgressCompletionChunks = (finalInProgressStatus) => {
|
|
1445
1424
|
const snapshot = progressDraft.getSnapshot();
|
|
1446
1425
|
const lines = resolveNativeProgressLines(snapshot);
|
|
1447
|
-
const
|
|
1426
|
+
const sessionLinks = progressCard.resolveSessionLinks();
|
|
1448
1427
|
const narrationUpdate = resolveNarrationUpdate(resolveNativeProgressNarration(snapshot));
|
|
1449
1428
|
const hasRetirableNativeTasks = [...nativeStreamSnapshot.tasks.values()].some((task) => task.status !== "complete" && task.status !== "error");
|
|
1450
|
-
if (lines.length === 0 && !snapshot.plan?.length && !hasRetirableNativeTasks && !snapshot.diffStat && !narrationUpdate.delta &&
|
|
1429
|
+
if (lines.length === 0 && !snapshot.plan?.length && !hasRetirableNativeTasks && !snapshot.diffStat && !narrationUpdate.delta && sessionLinks.length === 0) return;
|
|
1451
1430
|
const completion = reconcileSlackNativeTaskChunks({
|
|
1452
1431
|
previous: nativeStreamSnapshot,
|
|
1453
1432
|
finalStatus: finalInProgressStatus,
|
|
1454
1433
|
chunks: buildSlackProgressStreamChunks({
|
|
1455
|
-
title: resolveNativeProgressTitle(snapshot)
|
|
1434
|
+
title: resolveNativeProgressTitle(snapshot),
|
|
1456
1435
|
lines,
|
|
1457
1436
|
plan: snapshot.plan,
|
|
1458
1437
|
maxLineChars: progressDraftMaxLineChars,
|
|
1459
1438
|
summaryRow: !previewToolProgressEnabled,
|
|
1460
1439
|
finalInProgressStatus,
|
|
1461
1440
|
diffStat: snapshot.diffStat,
|
|
1462
|
-
|
|
1441
|
+
sessionLinks
|
|
1463
1442
|
})
|
|
1464
1443
|
}).chunks;
|
|
1465
1444
|
return narrationUpdate.delta ? [{
|
|
@@ -1530,12 +1509,12 @@ function createSlackProgressRuntime(runtimeParams) {
|
|
|
1530
1509
|
await cancelNativeUpdates();
|
|
1531
1510
|
}
|
|
1532
1511
|
const priorSnapshot = progressDraft.getSnapshot();
|
|
1533
|
-
const priorFallbackText = progressCard.resolveText(priorSnapshot);
|
|
1534
1512
|
const completionChunks = useNativeProgressStreaming && !nativeProgressCompletionSent ? buildNativeProgressCompletionChunks(nativeProgressTerminalStatus) : void 0;
|
|
1535
1513
|
if (!progressDraft.beginNewTurn(options)) return false;
|
|
1536
1514
|
if (useNativeProgressStreaming) await finishNativeProgressTurn(completionChunks);
|
|
1537
1515
|
else {
|
|
1538
|
-
await progressCard.finalize("success", priorSnapshot
|
|
1516
|
+
await progressCard.finalize("success", priorSnapshot);
|
|
1517
|
+
await previewLifecycle.cleanup();
|
|
1539
1518
|
draftStream?.forceNewMessage();
|
|
1540
1519
|
await dropDetachedProgressCards();
|
|
1541
1520
|
}
|
|
@@ -1546,7 +1525,7 @@ function createSlackProgressRuntime(runtimeParams) {
|
|
|
1546
1525
|
nativeUpdatesStopped = false;
|
|
1547
1526
|
nativeUpdates.resetThrottleWindow();
|
|
1548
1527
|
progressCard.reset();
|
|
1549
|
-
|
|
1528
|
+
previewLifecycle.reset();
|
|
1550
1529
|
delivery.resetDeliveryTracker();
|
|
1551
1530
|
return true;
|
|
1552
1531
|
};
|
|
@@ -1561,26 +1540,26 @@ function createSlackProgressRuntime(runtimeParams) {
|
|
|
1561
1540
|
};
|
|
1562
1541
|
const onQueuedFollowupAdmitted = !shouldUseDraftStream && !useNativeProgressStreaming ? void 0 : async () => {
|
|
1563
1542
|
await draftStream?.flush();
|
|
1564
|
-
resetPreviewDeliveryState();
|
|
1565
1543
|
if (isProgressMode) await beginNewProgressTurn({ force: true });
|
|
1566
|
-
else
|
|
1544
|
+
else {
|
|
1545
|
+
await previewLifecycle.cleanup();
|
|
1546
|
+
previewLifecycle.reset();
|
|
1547
|
+
draftStream?.forceNewMessage();
|
|
1548
|
+
}
|
|
1567
1549
|
delivery.resetDeliveryTracker();
|
|
1568
1550
|
resetDraftDeliveryState();
|
|
1569
1551
|
progressDraft.reset();
|
|
1570
1552
|
};
|
|
1571
|
-
const onQueuedFollowupSettled = !
|
|
1553
|
+
const onQueuedFollowupSettled = !draftStream && !useNativeProgressStreaming ? void 0 : async () => {
|
|
1572
1554
|
if (useNativeProgressStreaming) {
|
|
1573
1555
|
progressDraft.markFinalReplyStarted();
|
|
1574
1556
|
await cancelNativeUpdates();
|
|
1575
1557
|
await finishNativeProgressTurn(nativeProgressCompletionSent ? void 0 : buildNativeProgressCompletionChunks(nativeProgressTerminalStatus));
|
|
1576
|
-
progressDraft.markFinalReplyDelivered();
|
|
1577
1558
|
return;
|
|
1578
1559
|
}
|
|
1579
|
-
if (
|
|
1560
|
+
if (!useDraftProgressCard) {
|
|
1580
1561
|
progressDraft.markFinalReplyStarted();
|
|
1581
|
-
await
|
|
1582
|
-
await draftStream?.dropDetachedMessages();
|
|
1583
|
-
progressDraft.markFinalReplyDelivered();
|
|
1562
|
+
await previewLifecycle.cleanup();
|
|
1584
1563
|
return;
|
|
1585
1564
|
}
|
|
1586
1565
|
if (!progressCard.hasTerminalized) await draftStream?.clear();
|
|
@@ -1588,6 +1567,7 @@ function createSlackProgressRuntime(runtimeParams) {
|
|
|
1588
1567
|
};
|
|
1589
1568
|
return {
|
|
1590
1569
|
draftStream,
|
|
1570
|
+
previewLifecycle,
|
|
1591
1571
|
isProgressMode,
|
|
1592
1572
|
useDraftProgressCard,
|
|
1593
1573
|
useNativeProgressStreaming,
|
|
@@ -1616,6 +1596,7 @@ function createSlackProgressRuntime(runtimeParams) {
|
|
|
1616
1596
|
deliverNativeFinal,
|
|
1617
1597
|
dropDetachedProgressCards,
|
|
1618
1598
|
finalizeDraftProgressCard: progressCard.finalize,
|
|
1599
|
+
onVisibleWorkSessions: progressCard.onVisibleWorkSessions,
|
|
1619
1600
|
onDraftBoundary,
|
|
1620
1601
|
onQueuedFollowupAdmitted,
|
|
1621
1602
|
onQueuedFollowupSettled,
|
|
@@ -1672,14 +1653,14 @@ async function createSlackDispatchSetup(prepared) {
|
|
|
1672
1653
|
ctx: prepared.ctxPayload
|
|
1673
1654
|
});
|
|
1674
1655
|
}
|
|
1675
|
-
const
|
|
1656
|
+
const threadContext = resolveSlackThreadContext({
|
|
1676
1657
|
message,
|
|
1677
1658
|
replyToMode: prepared.replyToMode
|
|
1678
1659
|
});
|
|
1679
1660
|
const forcedReplyThreadTs = prepared.forcedReplyThreadTs;
|
|
1680
1661
|
const slackMessageMetadata = prepared.slackMessageMetadata;
|
|
1681
|
-
const statusThreadTs = forcedReplyThreadTs ??
|
|
1682
|
-
const isThreadReply =
|
|
1662
|
+
const statusThreadTs = forcedReplyThreadTs ?? threadContext.messageThreadId;
|
|
1663
|
+
const isThreadReply = threadContext.isThreadReply;
|
|
1683
1664
|
const replyDeliveryMode = forcedReplyThreadTs ? "off" : prepared.replyToMode;
|
|
1684
1665
|
const sourceReplyDeliveryMode = resolveChannelMessageSourceReplyDeliveryMode({
|
|
1685
1666
|
cfg,
|
|
@@ -1701,6 +1682,7 @@ async function createSlackDispatchSetup(prepared) {
|
|
|
1701
1682
|
const messageTs = message.ts ?? message.event_ts;
|
|
1702
1683
|
const incomingThreadTs = message.thread_ts;
|
|
1703
1684
|
let didSetStatus = false;
|
|
1685
|
+
let statusWasSet = false;
|
|
1704
1686
|
let didAddTypingReaction = false;
|
|
1705
1687
|
const statusReactionsEnabled = prepared.ctxPayload.InboundEventKind !== "room_event" && Boolean(prepared.ackReactionPromise) && Boolean(reactionMessageTs) && cfg.messages?.statusReactions?.enabled === true;
|
|
1706
1688
|
const statusReactions = createStatusReactionController({
|
|
@@ -1739,8 +1721,12 @@ async function createSlackDispatchSetup(prepared) {
|
|
|
1739
1721
|
hasRepliedRef,
|
|
1740
1722
|
isThreadReply: Boolean(forcedReplyThreadTs) || isThreadReply
|
|
1741
1723
|
});
|
|
1724
|
+
const slackStreaming = resolveSlackStreamingConfig({ streaming: account.config.streaming });
|
|
1725
|
+
const streamThreadHint = forcedReplyThreadTs ?? replyPlan.peekThreadTs();
|
|
1726
|
+
const slackProgressStyle = resolveSlackProgressStyle(account.config, Boolean(streamThreadHint));
|
|
1727
|
+
const quietProgress = slackStreaming.mode === "progress" && slackProgressStyle === "none";
|
|
1742
1728
|
const typingTarget = statusThreadTs ? `${message.channel}/${statusThreadTs}` : message.channel;
|
|
1743
|
-
const typingReaction = ctx.typingReaction;
|
|
1729
|
+
const typingReaction = quietProgress && account.config.typingReaction === void 0 ? "hourglass_flowing_sand" : ctx.typingReaction;
|
|
1744
1730
|
const threadStatusGate = { hasVisibleOutput: () => false };
|
|
1745
1731
|
const { onModelSelected, ...replyPipeline } = createChannelMessageReplyPipeline({
|
|
1746
1732
|
cfg,
|
|
@@ -1752,7 +1738,7 @@ async function createSlackDispatchSetup(prepared) {
|
|
|
1752
1738
|
start: async () => {
|
|
1753
1739
|
if (!didSetStatus && !threadStatusGate.hasVisibleOutput()) {
|
|
1754
1740
|
didSetStatus = true;
|
|
1755
|
-
await ctx.setSlackSessionStatus({
|
|
1741
|
+
statusWasSet = await ctx.setSlackSessionStatus({
|
|
1756
1742
|
channelId: message.channel,
|
|
1757
1743
|
threadTs: statusThreadTs,
|
|
1758
1744
|
status: "processing",
|
|
@@ -1773,12 +1759,17 @@ async function createSlackDispatchSetup(prepared) {
|
|
|
1773
1759
|
stop: async () => {
|
|
1774
1760
|
if (didSetStatus) {
|
|
1775
1761
|
didSetStatus = false;
|
|
1776
|
-
|
|
1762
|
+
const reportFailure = statusWasSet;
|
|
1763
|
+
statusWasSet = false;
|
|
1764
|
+
const restored = await ctx.setSlackSessionStatus({
|
|
1777
1765
|
channelId: message.channel,
|
|
1778
1766
|
threadTs: statusThreadTs,
|
|
1779
1767
|
status: "active",
|
|
1780
1768
|
eventScope: prepared.eventScope
|
|
1781
1769
|
});
|
|
1770
|
+
if (reportFailure && !restored) try {
|
|
1771
|
+
runtime.error?.("Slack session status could not return to active after processing. Enable verbose logging to inspect the Slack API failure.");
|
|
1772
|
+
} catch {}
|
|
1782
1773
|
}
|
|
1783
1774
|
if (didAddTypingReaction && typingReaction && message.ts) {
|
|
1784
1775
|
didAddTypingReaction = false;
|
|
@@ -1810,23 +1801,16 @@ async function createSlackDispatchSetup(prepared) {
|
|
|
1810
1801
|
}
|
|
1811
1802
|
}
|
|
1812
1803
|
});
|
|
1813
|
-
const slackStreaming = resolveSlackStreamingConfig({ streaming: account.config.streaming });
|
|
1814
|
-
const streamThreadHint = forcedReplyThreadTs ?? resolveSlackStreamingThreadHint({
|
|
1815
|
-
replyToMode: replyDeliveryMode,
|
|
1816
|
-
incomingThreadTs,
|
|
1817
|
-
messageTs,
|
|
1818
|
-
isThreadReply
|
|
1819
|
-
});
|
|
1820
1804
|
const hookRunner = getGlobalHookRunner();
|
|
1821
1805
|
const modifyingHooksRegistered = (hookRunner?.hasHooks("reply_payload_sending") ?? false) || (hookRunner?.hasHooks("message_sending") ?? false);
|
|
1822
1806
|
const allowPreHookProviderStreaming = !prepared.ctxPayload.GroupThread && !modifyingHooksRegistered;
|
|
1823
|
-
const previewStreamingEnabled = allowPreHookProviderStreaming && !sourceRepliesAreToolOnly && slackStreaming.mode !== "off";
|
|
1807
|
+
const previewStreamingEnabled = allowPreHookProviderStreaming && !sourceRepliesAreToolOnly && !quietProgress && slackStreaming.mode !== "off";
|
|
1824
1808
|
const hasSlackCustomIdentity = Boolean(slackIdentity?.username || slackIdentity?.iconUrl || slackIdentity?.iconEmoji);
|
|
1825
1809
|
const useStreaming = shouldUseStreaming({
|
|
1826
1810
|
streamingEnabled: !prepared.ctxPayload.GroupThread && !sourceRepliesAreToolOnly && (allowPreHookProviderStreaming || slackStreaming.mode !== "progress") && isSlackStreamingEnabled({
|
|
1827
1811
|
mode: slackStreaming.mode,
|
|
1828
1812
|
nativeStreaming: slackStreaming.nativeStreaming,
|
|
1829
|
-
nativeProgressTaskCards: resolveSlackNativeProgressTaskCards(account.config)
|
|
1813
|
+
nativeProgressTaskCards: resolveSlackNativeProgressTaskCards(account.config, slackProgressStyle)
|
|
1830
1814
|
}),
|
|
1831
1815
|
threadTs: streamThreadHint
|
|
1832
1816
|
});
|
|
@@ -1850,13 +1834,10 @@ async function createSlackDispatchSetup(prepared) {
|
|
|
1850
1834
|
isThreadReply,
|
|
1851
1835
|
replyDeliveryMode,
|
|
1852
1836
|
sourceReplyDeliveryMode,
|
|
1853
|
-
sourceRepliesAreToolOnly,
|
|
1854
1837
|
suppressRoomEventTyping,
|
|
1855
1838
|
messageSentHookTarget,
|
|
1856
1839
|
messageSentHookContext,
|
|
1857
1840
|
messageSentDeliveryHookContext,
|
|
1858
|
-
incomingThreadTs,
|
|
1859
|
-
messageTs,
|
|
1860
1841
|
statusReactionsEnabled,
|
|
1861
1842
|
statusReactions,
|
|
1862
1843
|
hasRepliedRef,
|
|
@@ -1865,11 +1846,13 @@ async function createSlackDispatchSetup(prepared) {
|
|
|
1865
1846
|
onModelSelected,
|
|
1866
1847
|
replyPipeline,
|
|
1867
1848
|
slackStreaming,
|
|
1849
|
+
slackProgressStyle,
|
|
1850
|
+
quietProgress,
|
|
1868
1851
|
streamThreadHint,
|
|
1869
1852
|
previewStreamingEnabled,
|
|
1870
1853
|
hasSlackCustomIdentity,
|
|
1871
1854
|
shouldUseDraftStream,
|
|
1872
|
-
disableBlockStreaming: sourceRepliesAreToolOnly ? true : resolveSlackDisableBlockStreaming({
|
|
1855
|
+
disableBlockStreaming: sourceRepliesAreToolOnly || quietProgress ? true : resolveSlackDisableBlockStreaming({
|
|
1873
1856
|
useStreaming,
|
|
1874
1857
|
shouldUseDraftStream,
|
|
1875
1858
|
blockStreamingEnabled
|
|
@@ -1888,9 +1871,43 @@ function createSlackStreamingDeliveryRuntime(setup) {
|
|
|
1888
1871
|
streamFailed: false,
|
|
1889
1872
|
usedReplyThreadTs: void 0,
|
|
1890
1873
|
usedBlockReplyThreadTs: void 0,
|
|
1891
|
-
observedReplyDelivery: false
|
|
1892
|
-
observedFinalReplyDelivery: false
|
|
1874
|
+
observedReplyDelivery: false
|
|
1893
1875
|
};
|
|
1876
|
+
const startStream = async (params) => {
|
|
1877
|
+
const session = await startSlackStream({
|
|
1878
|
+
client: slackClient,
|
|
1879
|
+
clientOptions: slackClientOptions,
|
|
1880
|
+
channel: message.channel,
|
|
1881
|
+
...params,
|
|
1882
|
+
...slackIdentity ? { identity: slackIdentity } : {},
|
|
1883
|
+
teamId: await resolveSlackStreamRecipientTeamId({
|
|
1884
|
+
client: slackClient,
|
|
1885
|
+
token: ctx.botToken,
|
|
1886
|
+
userId: message.user,
|
|
1887
|
+
fallbackTeamId: slackStreamFallbackTeamId
|
|
1888
|
+
}),
|
|
1889
|
+
userId: message.user
|
|
1890
|
+
});
|
|
1891
|
+
state.streamSession = session;
|
|
1892
|
+
return session;
|
|
1893
|
+
};
|
|
1894
|
+
const deliverPreparedReply = (reply, replyThreadTs, deferMessageSentHooks = false) => deliverReplies({
|
|
1895
|
+
cfg: ctx.cfg,
|
|
1896
|
+
replies: [reply],
|
|
1897
|
+
target: prepared.replyTarget,
|
|
1898
|
+
token: ctx.botToken,
|
|
1899
|
+
accountId: account.accountId,
|
|
1900
|
+
runtime,
|
|
1901
|
+
textLimit: ctx.textLimit,
|
|
1902
|
+
mediaMaxBytes: ctx.mediaMaxBytes,
|
|
1903
|
+
replyThreadTs,
|
|
1904
|
+
replyToMode: replyDeliveryMode,
|
|
1905
|
+
...slackIdentity ? { identity: slackIdentity } : {},
|
|
1906
|
+
...slackMessageMetadata ? { metadata: slackMessageMetadata } : {},
|
|
1907
|
+
...messageSentDeliveryHookContext,
|
|
1908
|
+
...deferMessageSentHooks ? { deferMessageSentHooks: true } : {},
|
|
1909
|
+
eventScope: prepared.eventScope
|
|
1910
|
+
});
|
|
1894
1911
|
const emitStreamedDelivery = (content, result) => {
|
|
1895
1912
|
emitSlackMessageSentHooks({
|
|
1896
1913
|
...messageSentHookContext,
|
|
@@ -1930,30 +1947,19 @@ function createSlackStreamingDeliveryRuntime(setup) {
|
|
|
1930
1947
|
if (session.stoppedBySlack) return;
|
|
1931
1948
|
state.observedReplyDelivery = true;
|
|
1932
1949
|
state.usedReplyThreadTs ??= session.threadTs;
|
|
1933
|
-
return
|
|
1950
|
+
return {
|
|
1951
|
+
visibleReplySent: session.delivered,
|
|
1952
|
+
...stopResult.messageId ? { messageIds: [stopResult.messageId] } : {},
|
|
1953
|
+
threadId: session.threadTs
|
|
1954
|
+
};
|
|
1934
1955
|
} catch (stopErr) {
|
|
1935
1956
|
if (stopErr instanceof SlackStreamNotDeliveredError) fallbackError = stopErr;
|
|
1936
1957
|
else throw stopErr;
|
|
1937
1958
|
}
|
|
1938
1959
|
const fallbackText = fallbackError.pendingText.trim();
|
|
1939
1960
|
if (!fallbackText) return;
|
|
1940
|
-
await
|
|
1941
|
-
|
|
1942
|
-
replies: [prepareSlackReply({ text: fallbackText })],
|
|
1943
|
-
target: prepared.replyTarget,
|
|
1944
|
-
token: ctx.botToken,
|
|
1945
|
-
accountId: account.accountId,
|
|
1946
|
-
runtime,
|
|
1947
|
-
textLimit: ctx.textLimit,
|
|
1948
|
-
mediaMaxBytes: ctx.mediaMaxBytes,
|
|
1949
|
-
replyThreadTs: session.threadTs,
|
|
1950
|
-
replyToMode: replyDeliveryMode,
|
|
1951
|
-
...slackIdentity ? { identity: slackIdentity } : {},
|
|
1952
|
-
...slackMessageMetadata ? { metadata: slackMessageMetadata } : {},
|
|
1953
|
-
...messageSentDeliveryHookContext,
|
|
1954
|
-
deferMessageSentHooks: true,
|
|
1955
|
-
eventScope: prepared.eventScope
|
|
1956
|
-
});
|
|
1961
|
+
const sent = await deliverPreparedReply(prepareSlackReply({ text: fallbackText }), session.threadTs, true);
|
|
1962
|
+
if (!sent?.receipt.platformMessageIds.length) return;
|
|
1957
1963
|
markSlackStreamFallbackDelivered(session);
|
|
1958
1964
|
if (!session.stopped) try {
|
|
1959
1965
|
await stopSlackStream({
|
|
@@ -1966,7 +1972,12 @@ function createSlackStreamingDeliveryRuntime(setup) {
|
|
|
1966
1972
|
state.observedReplyDelivery = true;
|
|
1967
1973
|
state.usedReplyThreadTs ??= session.threadTs;
|
|
1968
1974
|
logVerbose(`slack-stream: streamed delivery failed (${fallbackError.slackCode}); delivered ${fallbackText.length} chars via deliverReplies fallback`);
|
|
1969
|
-
return {
|
|
1975
|
+
return {
|
|
1976
|
+
visibleReplySent: true,
|
|
1977
|
+
messageIds: sent.receipt.platformMessageIds,
|
|
1978
|
+
receipt: sent.receipt,
|
|
1979
|
+
threadId: sent.threadTs ?? session.threadTs
|
|
1980
|
+
};
|
|
1970
1981
|
};
|
|
1971
1982
|
const finishStream = async (chunks) => {
|
|
1972
1983
|
const session = state.streamSession;
|
|
@@ -1988,7 +1999,7 @@ function createSlackStreamingDeliveryRuntime(setup) {
|
|
|
1988
1999
|
}
|
|
1989
2000
|
};
|
|
1990
2001
|
const deliverNormally = async (params) => {
|
|
1991
|
-
if (state.streamSession?.stoppedBySlack) return;
|
|
2002
|
+
if (state.streamSession?.stoppedBySlack) return { visibleReplySent: false };
|
|
1992
2003
|
const replyThreadTs = resolveDeliveryThreadTs(params);
|
|
1993
2004
|
const deliveryReplyThreadTs = replyDeliveryMode === "off" && !forcedReplyThreadTs && !isThreadReply ? void 0 : replyThreadTs;
|
|
1994
2005
|
const preparedReply = prepareSlackReply(params.payload);
|
|
@@ -1999,26 +2010,11 @@ function createSlackStreamingDeliveryRuntime(setup) {
|
|
|
1999
2010
|
}, preparedReply);
|
|
2000
2011
|
if (deliveryTracker.hasDelivered(deliveryKey)) {
|
|
2001
2012
|
logVerbose("slack: suppressed duplicate normal delivery within the same turn");
|
|
2002
|
-
return
|
|
2013
|
+
return { visibleReplySent: false };
|
|
2003
2014
|
}
|
|
2004
|
-
await
|
|
2005
|
-
|
|
2006
|
-
replies: [preparedReply],
|
|
2007
|
-
target: prepared.replyTarget,
|
|
2008
|
-
token: ctx.botToken,
|
|
2009
|
-
accountId: account.accountId,
|
|
2010
|
-
runtime,
|
|
2011
|
-
textLimit: ctx.textLimit,
|
|
2012
|
-
mediaMaxBytes: ctx.mediaMaxBytes,
|
|
2013
|
-
replyThreadTs: deliveryReplyThreadTs,
|
|
2014
|
-
replyToMode: replyDeliveryMode,
|
|
2015
|
-
...slackIdentity ? { identity: slackIdentity } : {},
|
|
2016
|
-
...slackMessageMetadata ? { metadata: slackMessageMetadata } : {},
|
|
2017
|
-
...messageSentDeliveryHookContext,
|
|
2018
|
-
eventScope: prepared.eventScope
|
|
2019
|
-
});
|
|
2015
|
+
const sent = await deliverPreparedReply(preparedReply, deliveryReplyThreadTs);
|
|
2016
|
+
if (!sent?.receipt.platformMessageIds.length) return { visibleReplySent: false };
|
|
2020
2017
|
state.observedReplyDelivery = true;
|
|
2021
|
-
if (params.kind === "final") state.observedFinalReplyDelivery = true;
|
|
2022
2018
|
const deliveredThreadTs = resolveSlackReplyThreadTs({
|
|
2023
2019
|
replyToMode: replyDeliveryMode,
|
|
2024
2020
|
replyToId: params.payload.replyToId,
|
|
@@ -2028,36 +2024,37 @@ function createSlackStreamingDeliveryRuntime(setup) {
|
|
|
2028
2024
|
rememberDeliveredThreadTs(params.kind, deliveredThreadTs);
|
|
2029
2025
|
replyPlan.markSent();
|
|
2030
2026
|
deliveryTracker.markDelivered(deliveryKey);
|
|
2031
|
-
return
|
|
2027
|
+
return {
|
|
2028
|
+
visibleReplySent: true,
|
|
2029
|
+
messageIds: sent.receipt.platformMessageIds,
|
|
2030
|
+
receipt: sent.receipt,
|
|
2031
|
+
threadId: sent.threadTs ?? deliveredThreadTs
|
|
2032
|
+
};
|
|
2032
2033
|
};
|
|
2033
2034
|
const isStreamingEligible = (payload, options) => {
|
|
2034
2035
|
const reply = resolveSendableOutboundReplyParts(payload);
|
|
2035
2036
|
const renderPlan = resolveSlackReplyRenderPlan(payload);
|
|
2036
2037
|
const plannedBlocks = renderPlan.mode === "single" ? renderPlan.blocks : renderPlan.blockPart?.blocks;
|
|
2037
|
-
return !state.streamFailed && !reply.hasMedia && renderPlan.mode !== "split" && !renderPlan.textIsSlackPlainText && !plannedBlocks?.length && !
|
|
2038
|
+
return !state.streamFailed && !reply.hasMedia && renderPlan.mode !== "split" && !renderPlan.textIsSlackPlainText && !plannedBlocks?.length && !resolveSlackReplyBlocks(payload)?.length && reply.hasText && (!options?.maxTextBytes || countSlackTextUtf8Bytes(reply.trimmedText) <= options.maxTextBytes);
|
|
2038
2039
|
};
|
|
2039
2040
|
const deliverWithStreaming = async (params) => {
|
|
2040
|
-
if (state.streamSession?.stoppedBySlack) return;
|
|
2041
|
-
if (!isStreamingEligible(params.payload)) {
|
|
2042
|
-
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
});
|
|
2047
|
-
return;
|
|
2048
|
-
}
|
|
2041
|
+
if (state.streamSession?.stoppedBySlack) return { visibleReplySent: false };
|
|
2042
|
+
if (!isStreamingEligible(params.payload)) return await deliverNormally({
|
|
2043
|
+
payload: params.payload,
|
|
2044
|
+
kind: params.kind,
|
|
2045
|
+
forcedThreadTs: state.streamSession?.threadTs ?? state.nativeProgressStreamThreadTs
|
|
2046
|
+
});
|
|
2049
2047
|
if (!state.streamSession && state.nativeProgressStreamStartPromise) await state.nativeProgressStreamStartPromise;
|
|
2050
|
-
if (state.streamSession?.stoppedBySlack) return;
|
|
2048
|
+
if (state.streamSession?.stoppedBySlack) return { visibleReplySent: false };
|
|
2051
2049
|
let session = state.streamSession;
|
|
2052
2050
|
const threadTs = session?.threadTs ?? replyPlan.nextThreadTs();
|
|
2053
2051
|
if (state.streamFailed || !threadTs) {
|
|
2054
2052
|
state.streamFailed = true;
|
|
2055
|
-
await deliverNormally({
|
|
2053
|
+
return await deliverNormally({
|
|
2056
2054
|
payload: params.payload,
|
|
2057
2055
|
kind: params.kind,
|
|
2058
2056
|
forcedThreadTs: threadTs ?? state.nativeProgressStreamThreadTs
|
|
2059
2057
|
});
|
|
2060
|
-
return;
|
|
2061
2058
|
}
|
|
2062
2059
|
const hookContent = resolveSendableOutboundReplyParts(params.payload).trimmedText;
|
|
2063
2060
|
const text = params.streamText ?? hookContent;
|
|
@@ -2068,35 +2065,22 @@ function createSlackStreamingDeliveryRuntime(setup) {
|
|
|
2068
2065
|
});
|
|
2069
2066
|
if (deliveryTracker.hasDelivered(deliveryKey)) {
|
|
2070
2067
|
logVerbose("slack-stream: suppressed duplicate reply payload");
|
|
2071
|
-
return;
|
|
2068
|
+
return { visibleReplySent: false };
|
|
2072
2069
|
}
|
|
2073
2070
|
let messageId;
|
|
2071
|
+
let fallbackDelivery;
|
|
2074
2072
|
try {
|
|
2075
2073
|
if (session) await appendSlackStream({
|
|
2076
2074
|
session,
|
|
2077
2075
|
text: `${params.appendSeparator === false ? "" : "\n"}${text}`,
|
|
2078
2076
|
chunks: []
|
|
2079
2077
|
});
|
|
2080
|
-
else {
|
|
2081
|
-
|
|
2082
|
-
|
|
2083
|
-
|
|
2084
|
-
|
|
2085
|
-
|
|
2086
|
-
text,
|
|
2087
|
-
chunks: [],
|
|
2088
|
-
...params.taskDisplayMode ? { taskDisplayMode: params.taskDisplayMode } : {},
|
|
2089
|
-
...slackIdentity ? { identity: slackIdentity } : {},
|
|
2090
|
-
teamId: await resolveSlackStreamRecipientTeamId({
|
|
2091
|
-
client: slackClient,
|
|
2092
|
-
token: ctx.botToken,
|
|
2093
|
-
userId: message.user,
|
|
2094
|
-
fallbackTeamId: slackStreamFallbackTeamId
|
|
2095
|
-
}),
|
|
2096
|
-
userId: message.user
|
|
2097
|
-
});
|
|
2098
|
-
state.streamSession = session;
|
|
2099
|
-
}
|
|
2078
|
+
else session = await startStream({
|
|
2079
|
+
threadTs,
|
|
2080
|
+
text,
|
|
2081
|
+
chunks: [],
|
|
2082
|
+
...params.taskDisplayMode ? { taskDisplayMode: params.taskDisplayMode } : {}
|
|
2083
|
+
});
|
|
2100
2084
|
messageId = session.streamer.ts;
|
|
2101
2085
|
} catch (error) {
|
|
2102
2086
|
state.streamFailed = true;
|
|
@@ -2107,18 +2091,16 @@ function createSlackStreamingDeliveryRuntime(setup) {
|
|
|
2107
2091
|
});
|
|
2108
2092
|
throw error;
|
|
2109
2093
|
}
|
|
2110
|
-
if (!session) {
|
|
2111
|
-
|
|
2112
|
-
|
|
2113
|
-
|
|
2114
|
-
|
|
2115
|
-
});
|
|
2116
|
-
return;
|
|
2117
|
-
}
|
|
2094
|
+
if (!session) return await deliverNormally({
|
|
2095
|
+
payload: params.payload,
|
|
2096
|
+
kind: params.kind,
|
|
2097
|
+
forcedThreadTs: threadTs
|
|
2098
|
+
});
|
|
2118
2099
|
try {
|
|
2119
2100
|
const fallback = await deliverPendingStreamFallback(session, error);
|
|
2120
2101
|
if (!fallback && !session.stoppedBySlack) throw error;
|
|
2121
|
-
|
|
2102
|
+
fallbackDelivery = fallback;
|
|
2103
|
+
messageId = fallback?.receipt ? void 0 : fallback?.messageIds?.[0];
|
|
2122
2104
|
} catch (fallbackError) {
|
|
2123
2105
|
emitStreamedDelivery(hookContent, {
|
|
2124
2106
|
success: false,
|
|
@@ -2132,10 +2114,10 @@ function createSlackStreamingDeliveryRuntime(setup) {
|
|
|
2132
2114
|
success: false,
|
|
2133
2115
|
error: "Stopped by Slack user"
|
|
2134
2116
|
});
|
|
2135
|
-
return;
|
|
2117
|
+
return { visibleReplySent: false };
|
|
2136
2118
|
}
|
|
2119
|
+
if (!fallbackDelivery?.visibleReplySent && (!session.delivered || session.pendingText)) return { visibleReplySent: false };
|
|
2137
2120
|
state.observedReplyDelivery = true;
|
|
2138
|
-
if (params.kind === "final") state.observedFinalReplyDelivery = true;
|
|
2139
2121
|
rememberDeliveredThreadTs(params.kind, threadTs);
|
|
2140
2122
|
replyPlan.markSent();
|
|
2141
2123
|
deliveryTracker.markDelivered(deliveryKey);
|
|
@@ -2143,15 +2125,20 @@ function createSlackStreamingDeliveryRuntime(setup) {
|
|
|
2143
2125
|
success: true,
|
|
2144
2126
|
...messageId ? { messageId } : {}
|
|
2145
2127
|
});
|
|
2128
|
+
return fallbackDelivery ?? {
|
|
2129
|
+
visibleReplySent: true,
|
|
2130
|
+
...messageId ? { messageIds: [messageId] } : {},
|
|
2131
|
+
threadId: threadTs
|
|
2132
|
+
};
|
|
2146
2133
|
};
|
|
2147
2134
|
return Object.assign(state, {
|
|
2148
2135
|
deliverNormally,
|
|
2149
2136
|
deliverWithStreaming,
|
|
2150
2137
|
finishStream,
|
|
2151
|
-
hasDelivered: (params) => deliveryTracker.hasDelivered(buildSlackEventDeliveryKey(params)),
|
|
2152
2138
|
isStreamingEligible,
|
|
2153
2139
|
markPreviewPayloadDelivered,
|
|
2154
2140
|
rememberDeliveredThreadTs,
|
|
2141
|
+
startStream,
|
|
2155
2142
|
resetDeliveryTracker: () => {
|
|
2156
2143
|
deliveryTracker = createSlackEventDeliveryTracker();
|
|
2157
2144
|
}
|
|
@@ -2194,17 +2181,12 @@ async function dispatchSlackMessageWithSetup(setup, beginSessionRun, turnAdoptio
|
|
|
2194
2181
|
const { account, cfg, ctx, disableBlockStreaming, hasSlackCustomIdentity, hasRepliedRef, message, messageSentHookContext, messageSentHookTarget, onModelSelected, previewStreamingEnabled, replyPipeline, replyPlan, route, runtime, slackClient, slackStreaming, sourceReplyDeliveryMode, statusReactions, statusReactionsEnabled, statusThreadTs, suppressRoomEventTyping, useStreaming } = setup;
|
|
2195
2182
|
let dispatchError;
|
|
2196
2183
|
const delivery = createSlackStreamingDeliveryRuntime(setup);
|
|
2197
|
-
const draftPreviewCommitted = { value: false };
|
|
2198
2184
|
const progress = createSlackProgressRuntime({
|
|
2199
2185
|
setup,
|
|
2200
|
-
delivery
|
|
2201
|
-
resetPreviewDeliveryState: () => {
|
|
2202
|
-
draftPreviewCommitted.value = false;
|
|
2203
|
-
delivery.observedFinalReplyDelivery = false;
|
|
2204
|
-
}
|
|
2186
|
+
delivery
|
|
2205
2187
|
});
|
|
2206
|
-
const draftStream = progress
|
|
2207
|
-
setup.threadStatusGate.hasVisibleOutput = () => delivery.observedReplyDelivery ||
|
|
2188
|
+
const { draftStream, previewLifecycle } = progress;
|
|
2189
|
+
setup.threadStatusGate.hasVisibleOutput = () => delivery.observedReplyDelivery || previewLifecycle.previewFinalized || Boolean(draftStream?.messageId());
|
|
2208
2190
|
const failureNoticeThreadTs = message.thread_ts;
|
|
2209
2191
|
const failureNoticeTeamId = prepared.eventScope?.teamId;
|
|
2210
2192
|
let sawTerminalFailurePayload = false;
|
|
@@ -2212,7 +2194,7 @@ async function dispatchSlackMessageWithSetup(setup, beginSessionRun, turnAdoptio
|
|
|
2212
2194
|
const filterPassiveThreadFailure = (payload) => {
|
|
2213
2195
|
if (payload.isError !== true || prepared.ctxPayload.ChatType !== "channel" || isReplyPayloadNonTerminalToolErrorWarning(payload)) return payload;
|
|
2214
2196
|
sawTerminalFailurePayload = true;
|
|
2215
|
-
if (delivery.observedReplyDelivery ||
|
|
2197
|
+
if (delivery.observedReplyDelivery || previewLifecycle.previewFinalized) return payload;
|
|
2216
2198
|
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;
|
|
2217
2199
|
const noticeThreadTs = failureNoticeThreadTs ?? (explicitlyAddressed ? statusThreadTs : void 0);
|
|
2218
2200
|
const notice = {
|
|
@@ -2233,14 +2215,6 @@ async function dispatchSlackMessageWithSetup(setup, beginSessionRun, turnAdoptio
|
|
|
2233
2215
|
pendingFailureNotice = notice;
|
|
2234
2216
|
return payload;
|
|
2235
2217
|
};
|
|
2236
|
-
let compactFinalDeliveryStarted = false;
|
|
2237
|
-
const clearCompactProgress = async () => {
|
|
2238
|
-
try {
|
|
2239
|
-
await draftStream?.clear();
|
|
2240
|
-
} catch (err) {
|
|
2241
|
-
logVerbose(`slack: progress preview cleanup failed (${formatSlackError(err)})`);
|
|
2242
|
-
}
|
|
2243
|
-
};
|
|
2244
2218
|
const deliverSlackPayload = async (incomingPayload, info) => {
|
|
2245
2219
|
let payload = incomingPayload;
|
|
2246
2220
|
if (info.participant && (payload.text || payload.mediaUrl || payload.mediaUrls?.length)) payload = {
|
|
@@ -2248,66 +2222,42 @@ async function dispatchSlackMessageWithSetup(setup, beginSessionRun, turnAdoptio
|
|
|
2248
2222
|
text: formatSlackGroupThreadReply(payload.text ?? "", info.participant)
|
|
2249
2223
|
};
|
|
2250
2224
|
if (info.kind === "final" && slackStreaming.mode === "progress" && progress.isProgressMode) {
|
|
2251
|
-
|
|
2252
|
-
|
|
2253
|
-
|
|
2254
|
-
|
|
2255
|
-
|
|
2256
|
-
|
|
2257
|
-
|
|
2258
|
-
|
|
2259
|
-
|
|
2260
|
-
|
|
2261
|
-
payload:
|
|
2262
|
-
...payload,
|
|
2263
|
-
text: supplement.spokenText
|
|
2264
|
-
} : payload,
|
|
2265
|
-
kind: info.kind,
|
|
2266
|
-
forcedThreadTs: delivery.usedReplyThreadTs
|
|
2267
|
-
});
|
|
2268
|
-
if (delivery.observedFinalReplyDelivery) {
|
|
2269
|
-
progress.progressDraft.markFinalReplyDelivered();
|
|
2270
|
-
await clearCompactProgress();
|
|
2271
|
-
}
|
|
2272
|
-
return;
|
|
2273
|
-
}
|
|
2274
|
-
if (progress.useDraftProgressCard) {
|
|
2275
|
-
await delivery.deliverNormally({
|
|
2276
|
-
payload,
|
|
2225
|
+
const supplement = getReplyPayloadTtsSupplement(payload);
|
|
2226
|
+
const finalPayload = !progress.useDraftProgressCard && !progress.useNativeProgressStreaming && supplement && !supplement.visibleTextAlreadyDelivered && !payload.text?.trim() ? {
|
|
2227
|
+
...payload,
|
|
2228
|
+
text: supplement.spokenText
|
|
2229
|
+
} : payload;
|
|
2230
|
+
return (await previewLifecycle.deliver({
|
|
2231
|
+
kind: info.kind,
|
|
2232
|
+
payload: finalPayload,
|
|
2233
|
+
isError: payload.isError === true,
|
|
2234
|
+
deliverNormally: (reply) => progress.useNativeProgressStreaming ? progress.deliverNativeFinal(reply, info.kind) : delivery.deliverNormally({
|
|
2235
|
+
payload: reply,
|
|
2277
2236
|
kind: info.kind,
|
|
2278
2237
|
forcedThreadTs: delivery.usedReplyThreadTs
|
|
2279
|
-
})
|
|
2280
|
-
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
}
|
|
2238
|
+
}),
|
|
2239
|
+
onNormalDelivered: progress.useDraftProgressCard ? async () => {
|
|
2240
|
+
if (!await progress.finalizeDraftProgressCard(payload.isError === true ? "error" : "success")) await draftStream?.clear();
|
|
2241
|
+
} : void 0
|
|
2242
|
+
})).deliveryResult ?? { visibleReplySent: false };
|
|
2284
2243
|
}
|
|
2285
2244
|
if (progress.useNativeProgressStreaming) {
|
|
2286
|
-
if (info.kind !== "final" && payload.isError !== true)
|
|
2287
|
-
|
|
2288
|
-
await delivery.deliverNormally({
|
|
2289
|
-
payload,
|
|
2290
|
-
kind: info.kind,
|
|
2291
|
-
forcedThreadTs: delivery.streamSession?.threadTs ?? delivery.nativeProgressStreamThreadTs
|
|
2292
|
-
});
|
|
2293
|
-
return;
|
|
2294
|
-
}
|
|
2295
|
-
return await progress.appendNativeNarration(payload, info.kind) ? void 0 : { visibleReplySent: false };
|
|
2296
|
-
}
|
|
2297
|
-
await delivery.deliverNormally({
|
|
2245
|
+
if (info.kind !== "final" && payload.isError !== true && delivery.isStreamingEligible(payload)) return await progress.appendNativeNarration(payload, info.kind);
|
|
2246
|
+
return await delivery.deliverNormally({
|
|
2298
2247
|
payload,
|
|
2299
2248
|
kind: info.kind,
|
|
2300
2249
|
forcedThreadTs: delivery.streamSession?.threadTs ?? delivery.nativeProgressStreamThreadTs
|
|
2301
2250
|
});
|
|
2302
|
-
return;
|
|
2303
2251
|
}
|
|
2304
|
-
if (useStreaming) {
|
|
2305
|
-
|
|
2306
|
-
|
|
2252
|
+
if (useStreaming) return (await previewLifecycle.deliver({
|
|
2253
|
+
kind: info.kind,
|
|
2254
|
+
payload,
|
|
2255
|
+
isError: payload.isError === true,
|
|
2256
|
+
deliverNormally: (reply) => delivery.deliverWithStreaming({
|
|
2257
|
+
payload: reply,
|
|
2307
2258
|
kind: info.kind
|
|
2308
|
-
})
|
|
2309
|
-
|
|
2310
|
-
}
|
|
2259
|
+
})
|
|
2260
|
+
})).deliveryResult ?? { visibleReplySent: false };
|
|
2311
2261
|
const reply = resolveSendableOutboundReplyParts(payload);
|
|
2312
2262
|
const ttsSupplement = getReplyPayloadTtsSupplement(payload);
|
|
2313
2263
|
const replySourceText = payload.text ?? ttsSupplement?.spokenText;
|
|
@@ -2321,26 +2271,13 @@ async function dispatchSlackMessageWithSetup(setup, beginSessionRun, turnAdoptio
|
|
|
2321
2271
|
accountId: account.accountId
|
|
2322
2272
|
}) });
|
|
2323
2273
|
const previewFinalTextFitsEdit = countSlackTextUtf8Bytes(previewFinalText) <= SLACK_EDIT_TEXT_MAX_BYTES;
|
|
2324
|
-
const shouldRestoreTtsSupplementTextForPreviewFallback = Boolean(ttsSupplement) && ttsSupplement?.visibleTextAlreadyDelivered !== true && Boolean(draftStream) && !
|
|
2274
|
+
const shouldRestoreTtsSupplementTextForPreviewFallback = Boolean(ttsSupplement) && ttsSupplement?.visibleTextAlreadyDelivered !== true && Boolean(draftStream) && !previewLifecycle.previewFinalized && !previewLifecycle.finalDelivered && previewStreamingEnabled && !payload.text?.trim();
|
|
2325
2275
|
let ttsPreviewFinalization;
|
|
2326
|
-
await
|
|
2276
|
+
return (await previewLifecycle.deliver({
|
|
2327
2277
|
kind: info.kind,
|
|
2328
2278
|
payload,
|
|
2329
|
-
|
|
2330
|
-
|
|
2331
|
-
flush: draftStream.flush,
|
|
2332
|
-
clear: () => draftStream.clear({ preserveHumanReplies: true }),
|
|
2333
|
-
discardPending: draftStream.discardPending,
|
|
2334
|
-
seal: draftStream.seal,
|
|
2335
|
-
id: () => {
|
|
2336
|
-
const channelId = draftStream.channelId();
|
|
2337
|
-
const messageId = draftStream.messageId();
|
|
2338
|
-
return channelId && messageId ? {
|
|
2339
|
-
channelId,
|
|
2340
|
-
messageId
|
|
2341
|
-
} : void 0;
|
|
2342
|
-
}
|
|
2343
|
-
} : void 0,
|
|
2279
|
+
isError: payload.isError === true,
|
|
2280
|
+
adapter: {
|
|
2344
2281
|
buildFinalEdit: () => {
|
|
2345
2282
|
if (hasSlackCustomIdentity || !previewStreamingEnabled || reply.hasMedia && !ttsSupplement || payload.isError || requiresSeparateFallbackDelivery || !previewFinalTextFitsEdit || trimmedFinalText.length === 0 && !slackBlocks?.length) return;
|
|
2346
2283
|
return {
|
|
@@ -2350,11 +2287,6 @@ async function dispatchSlackMessageWithSetup(setup, beginSessionRun, turnAdoptio
|
|
|
2350
2287
|
};
|
|
2351
2288
|
},
|
|
2352
2289
|
editFinal: async (preview, edit) => {
|
|
2353
|
-
if (delivery.hasDelivered({
|
|
2354
|
-
kind: info.kind,
|
|
2355
|
-
payload,
|
|
2356
|
-
threadTs: edit.threadTs
|
|
2357
|
-
})) return;
|
|
2358
2290
|
if (ttsSupplement) ttsPreviewFinalization = { threadTs: edit.threadTs };
|
|
2359
2291
|
if (!await draftStream?.finalizeMessage(preview.messageId, async () => {
|
|
2360
2292
|
await finalizeSlackPreviewEdit({
|
|
@@ -2368,59 +2300,66 @@ async function dispatchSlackMessageWithSetup(setup, beginSessionRun, turnAdoptio
|
|
|
2368
2300
|
threadTs: edit.threadTs
|
|
2369
2301
|
});
|
|
2370
2302
|
})) throw new Error("Slack preview moved below a newer conversation message");
|
|
2371
|
-
if (!ttsSupplement) emitSlackMessageSentHooks({
|
|
2372
|
-
...messageSentHookContext,
|
|
2373
|
-
to: messageSentHookTarget,
|
|
2374
|
-
accountId: account.accountId,
|
|
2375
|
-
content: trimmedFinalText,
|
|
2376
|
-
success: true,
|
|
2377
|
-
messageId: preview.messageId
|
|
2378
|
-
});
|
|
2379
|
-
draftPreviewCommitted.value = true;
|
|
2380
|
-
delivery.observedFinalReplyDelivery = true;
|
|
2381
2303
|
},
|
|
2382
|
-
|
|
2383
|
-
|
|
2384
|
-
|
|
2304
|
+
createPreviewReceipt: (preview, edit) => createMessageReceiptFromOutboundResults({
|
|
2305
|
+
results: [{
|
|
2306
|
+
channel: "slack",
|
|
2307
|
+
channelId: preview.channelId,
|
|
2308
|
+
messageId: preview.messageId
|
|
2309
|
+
}],
|
|
2310
|
+
threadId: edit.threadTs,
|
|
2311
|
+
kind: "text"
|
|
2312
|
+
}),
|
|
2313
|
+
onPreviewFinalized: (preview) => {
|
|
2385
2314
|
const finalThreadTs = delivery.usedReplyThreadTs ?? statusThreadTs;
|
|
2386
2315
|
delivery.observedReplyDelivery = true;
|
|
2387
2316
|
replyPlan.markSent();
|
|
2388
|
-
if (!ttsSupplement)
|
|
2389
|
-
|
|
2390
|
-
|
|
2391
|
-
|
|
2392
|
-
|
|
2317
|
+
if (!ttsSupplement) {
|
|
2318
|
+
delivery.markPreviewPayloadDelivered({
|
|
2319
|
+
kind: info.kind,
|
|
2320
|
+
payload,
|
|
2321
|
+
threadTs: finalThreadTs
|
|
2322
|
+
});
|
|
2323
|
+
emitSlackMessageSentHooks({
|
|
2324
|
+
...messageSentHookContext,
|
|
2325
|
+
to: messageSentHookTarget,
|
|
2326
|
+
accountId: account.accountId,
|
|
2327
|
+
content: trimmedFinalText,
|
|
2328
|
+
success: true,
|
|
2329
|
+
messageId: preview.messageId
|
|
2330
|
+
});
|
|
2331
|
+
}
|
|
2393
2332
|
},
|
|
2394
2333
|
buildSupplementalPayload: () => ttsSupplement ? buildTtsSupplementMediaPayload(payload) : void 0,
|
|
2395
2334
|
deliverSupplemental: async (supplementalPayload) => {
|
|
2396
2335
|
const previewThreadTs = delivery.usedReplyThreadTs ?? statusThreadTs;
|
|
2397
|
-
const
|
|
2336
|
+
const supplementalResult = await delivery.deliverNormally({
|
|
2398
2337
|
payload: supplementalPayload,
|
|
2399
2338
|
kind: info.kind,
|
|
2400
2339
|
forcedThreadTs: previewThreadTs
|
|
2401
2340
|
});
|
|
2402
|
-
delivery.markPreviewPayloadDelivered({
|
|
2341
|
+
if (supplementalResult.visibleReplySent) delivery.markPreviewPayloadDelivered({
|
|
2403
2342
|
kind: info.kind,
|
|
2404
2343
|
payload,
|
|
2405
|
-
threadTs:
|
|
2344
|
+
threadTs: supplementalResult.threadId
|
|
2406
2345
|
});
|
|
2346
|
+
return supplementalResult;
|
|
2407
2347
|
},
|
|
2408
2348
|
logPreviewEditFailure: (err) => {
|
|
2409
2349
|
logVerbose(`slack: preview final edit failed; falling back to standard send (${formatSlackError(err)})`);
|
|
2410
2350
|
}
|
|
2411
|
-
}
|
|
2412
|
-
deliverNormally: async () => {
|
|
2413
|
-
await delivery.deliverNormally({
|
|
2414
|
-
payload: shouldRestoreTtsSupplementTextForPreviewFallback || ttsPreviewFinalization && !payload.text?.trim() ? {
|
|
2415
|
-
...
|
|
2351
|
+
},
|
|
2352
|
+
deliverNormally: async (normalPayload) => {
|
|
2353
|
+
return await delivery.deliverNormally({
|
|
2354
|
+
payload: normalPayload === payload && (shouldRestoreTtsSupplementTextForPreviewFallback || ttsPreviewFinalization && !payload.text?.trim()) ? {
|
|
2355
|
+
...normalPayload,
|
|
2416
2356
|
text: ttsSupplement?.spokenText
|
|
2417
|
-
} :
|
|
2357
|
+
} : normalPayload,
|
|
2418
2358
|
kind: info.kind,
|
|
2419
2359
|
...ttsPreviewFinalization?.threadTs ? { forcedThreadTs: ttsPreviewFinalization.threadTs } : {}
|
|
2420
2360
|
});
|
|
2421
2361
|
}
|
|
2422
|
-
});
|
|
2423
|
-
if (info.kind === "final") progress.progressDraft.markFinalReplyDelivered();
|
|
2362
|
+
})).deliveryResult ?? { visibleReplySent: false };
|
|
2424
2363
|
};
|
|
2425
2364
|
let agentRunFailed = false;
|
|
2426
2365
|
let settledDispatchResult;
|
|
@@ -2452,9 +2391,9 @@ async function dispatchSlackMessageWithSetup(setup, beginSessionRun, turnAdoptio
|
|
|
2452
2391
|
}
|
|
2453
2392
|
},
|
|
2454
2393
|
record: prepared.turn.record,
|
|
2455
|
-
history: prepared.turn.history,
|
|
2456
2394
|
botLoopProtection: resolveSlackBotLoopProtection(prepared),
|
|
2457
2395
|
replyOptions: {
|
|
2396
|
+
onVisibleWorkSessions: progress.onVisibleWorkSessions,
|
|
2458
2397
|
groupThreadReplyFormatter: formatSlackGroupThreadReply,
|
|
2459
2398
|
queuedDeliveryCorrelations: [{ begin: beginSessionRun }],
|
|
2460
2399
|
...turnAdoptionLifecycle ? { turnAdoptionLifecycle } : {},
|
|
@@ -2474,9 +2413,7 @@ async function dispatchSlackMessageWithSetup(setup, beginSessionRun, turnAdoptio
|
|
|
2474
2413
|
} : void 0,
|
|
2475
2414
|
allowProgressCallbacksWhenSourceDeliverySuppressed: sourceReplyDeliveryMode === "message_tool_only" && statusReactionsEnabled ? true : void 0,
|
|
2476
2415
|
allowToolLifecycleWhenProgressHidden: statusReactionsEnabled ? true : void 0,
|
|
2477
|
-
onPartialReply: useStreaming
|
|
2478
|
-
return progress.updateDraftFromPartial(payload.text);
|
|
2479
|
-
},
|
|
2416
|
+
onPartialReply: !useStreaming && previewStreamingEnabled ? async (payload) => progress.updateDraftFromPartial(payload.text) : void 0,
|
|
2480
2417
|
onAssistantMessageStart: progress.onDraftBoundary ? async () => {
|
|
2481
2418
|
await progress.onDraftBoundary?.();
|
|
2482
2419
|
return false;
|
|
@@ -2494,30 +2431,19 @@ async function dispatchSlackMessageWithSetup(setup, beginSessionRun, turnAdoptio
|
|
|
2494
2431
|
},
|
|
2495
2432
|
onToolStart: async (payload) => {
|
|
2496
2433
|
if (statusReactionsEnabled) await statusReactions.setTool(payload.name);
|
|
2497
|
-
if (payload.phase === "start") progress.progressWorkCounter.noteToolCall(payload.name);
|
|
2498
|
-
if (progress.preambleOnlyProgress) return isChannelProgressDraftWorkToolName(payload.name) ? await progress.progressDraft.noteActivity() : false;
|
|
2499
2434
|
return await progress.progressDraft.pushToolEvent(payload);
|
|
2500
2435
|
},
|
|
2501
2436
|
onItemEvent: async (payload) => {
|
|
2502
|
-
if (payload.
|
|
2503
|
-
if (
|
|
2504
|
-
|
|
2505
|
-
|
|
2506
|
-
if (progress.commentaryProgressEnabled) return await progress.progressDraft.pushCommentaryProgress(payload.progressText, {
|
|
2507
|
-
itemId: payload.itemId,
|
|
2508
|
-
...progress.preambleOnlyProgress ? { complete: payload.phase !== "start" && payload.phase !== "update" } : {}
|
|
2509
|
-
}) || headlineVisible;
|
|
2510
|
-
return headlineVisible;
|
|
2511
|
-
}
|
|
2512
|
-
return progress.preambleOnlyProgress ? await progress.progressDraft.noteActivity() : await progress.progressDraft.pushItemEvent(payload);
|
|
2437
|
+
if (payload.hideFromChannelProgress || payload.suppressChannelProgress) return progress.preambleOnlyProgress ? false : progress.progressDraft.pushItemEvent(payload);
|
|
2438
|
+
if (payload.kind === "preamble" && progress.shouldYieldDraftProgress()) return false;
|
|
2439
|
+
progress.progressWorkCounter.noteItem(payload);
|
|
2440
|
+
return progress.preambleOnlyProgress && payload.kind !== "preamble" ? await progress.progressDraft.noteActivity() : await progress.progressDraft.pushItemEvent(payload);
|
|
2513
2441
|
},
|
|
2514
2442
|
onPlanUpdate: async (payload) => {
|
|
2515
2443
|
if (payload.phase !== "update") return false;
|
|
2516
2444
|
return await progress.pushPlanProgress(payload.steps, payload.explanation, payload.explanationFormat);
|
|
2517
2445
|
},
|
|
2518
|
-
onApprovalEvent: (payload) => progress.progressDraft.pushApprovalEvent(payload)
|
|
2519
|
-
onCommandOutput: async (payload) => progress.preambleOnlyProgress ? await progress.progressDraft.noteActivity() : await progress.progressDraft.pushCommandOutputEvent(payload),
|
|
2520
|
-
onPatchSummary: async (payload) => progress.preambleOnlyProgress ? await progress.progressDraft.noteActivity() : await progress.progressDraft.pushPatchEvent(payload)
|
|
2446
|
+
onApprovalEvent: (payload) => progress.progressDraft.pushApprovalEvent(payload)
|
|
2521
2447
|
}
|
|
2522
2448
|
});
|
|
2523
2449
|
if (turnResult.dispatched) {
|
|
@@ -2541,9 +2467,11 @@ async function dispatchSlackMessageWithSetup(setup, beginSessionRun, turnAdoptio
|
|
|
2541
2467
|
const completionChunks = progress.useNativeProgressStreaming && !progress.nativeProgressCompletionSent ? progress.buildNativeProgressCompletionChunks(dispatchError || agentRunFailed ? "error" : progress.nativeProgressTerminalStatus) : void 0;
|
|
2542
2468
|
if (completionChunks?.length) progress.nativeProgressCompletionSent = true;
|
|
2543
2469
|
await delivery.finishStream(completionChunks);
|
|
2544
|
-
const anyReplyDelivered = hasVisibleInboundReplyDispatch(settledDispatchResult, { observedReplyDelivery: delivery.observedReplyDelivery });
|
|
2545
|
-
if (
|
|
2546
|
-
|
|
2470
|
+
const anyReplyDelivered = hasVisibleInboundReplyDispatch(settledDispatchResult, { observedReplyDelivery: delivery.observedReplyDelivery || previewLifecycle.finalDelivered });
|
|
2471
|
+
if (anyReplyDelivered && !previewLifecycle.finalStarted && !dispatchError && !agentRunFailed) {
|
|
2472
|
+
if (hasVisibleInboundReplyDispatch(settledDispatchResult)) await previewLifecycle.observeDelivery({ visibleReplySent: true });
|
|
2473
|
+
}
|
|
2474
|
+
await previewLifecycle.cleanup({ failed: Boolean(dispatchError || agentRunFailed) });
|
|
2547
2475
|
if (pendingFailureNotice && anyReplyDelivered) recordSlackThreadFailureNotice(pendingFailureNotice);
|
|
2548
2476
|
if (dispatchError || agentRunFailed) await progress.finalizeDraftProgressCard("error");
|
|
2549
2477
|
await progress.dropDetachedProgressCards();
|
|
@@ -2562,14 +2490,13 @@ async function dispatchSlackMessageWithSetup(setup, beginSessionRun, turnAdoptio
|
|
|
2562
2490
|
teamId: prepared.eventScope?.teamId
|
|
2563
2491
|
});
|
|
2564
2492
|
if (dispatchError) throw toErrorObject(dispatchError, "Slack dispatch failed");
|
|
2565
|
-
if (!anyReplyDelivered && !
|
|
2566
|
-
await draftStream?.clear();
|
|
2567
|
-
await draftStream?.dropDetachedMessages();
|
|
2493
|
+
if (!anyReplyDelivered && !previewLifecycle.previewFinalized && !(agentRunFailed && progress.useDraftProgressCard)) {
|
|
2494
|
+
if (progress.useDraftProgressCard) await draftStream?.clear();
|
|
2568
2495
|
return;
|
|
2569
2496
|
}
|
|
2570
2497
|
if (shouldLogVerbose()) {
|
|
2571
2498
|
const finalCount = resolveInboundReplyDispatchCounts(settledDispatchResult).final;
|
|
2572
|
-
logVerbose(`slack: delivered ${finalCount}
|
|
2499
|
+
logVerbose(`slack: delivered ${finalCount} repl${finalCount === 1 ? "y" : "ies"} to ${prepared.replyTarget}`);
|
|
2573
2500
|
}
|
|
2574
2501
|
}
|
|
2575
2502
|
//#endregion
|
|
@@ -2629,12 +2556,9 @@ function formatSlackFilePlaceholder(files) {
|
|
|
2629
2556
|
return `[attached: ${formatSlackFileReferenceList(files)}]`;
|
|
2630
2557
|
}
|
|
2631
2558
|
function pushUniqueText(parts, value, options = {}) {
|
|
2632
|
-
const text = options.preserveWhitespace ?
|
|
2559
|
+
const text = options.preserveWhitespace ? readNonBlankString(value) : normalizeOptionalString(value);
|
|
2633
2560
|
if (text && !parts.includes(text)) parts.push(text);
|
|
2634
2561
|
}
|
|
2635
|
-
function resolveSlackBlocksFallbackText(blocks) {
|
|
2636
|
-
return resolveSlackBlocksText(blocks)?.text;
|
|
2637
|
-
}
|
|
2638
2562
|
function resolveSlackAttachmentFallbackText(attachments) {
|
|
2639
2563
|
if (!Array.isArray(attachments) || attachments.length === 0) return;
|
|
2640
2564
|
const parts = [];
|
|
@@ -2649,13 +2573,13 @@ function resolveSlackAttachmentFallbackText(attachments) {
|
|
|
2649
2573
|
pushUniqueText(parts, field.title);
|
|
2650
2574
|
pushUniqueText(parts, field.value);
|
|
2651
2575
|
}
|
|
2652
|
-
pushUniqueText(parts,
|
|
2653
|
-
pushUniqueText(parts,
|
|
2576
|
+
pushUniqueText(parts, resolveSlackBlocksText(fallbackBlocks(attachment.blocks))?.text, { preserveWhitespace: true });
|
|
2577
|
+
pushUniqueText(parts, resolveSlackBlocksText(fallbackBlocks(attachment.message_blocks))?.text, { preserveWhitespace: true });
|
|
2654
2578
|
}
|
|
2655
2579
|
return parts.length > 0 ? parts.join("\n") : void 0;
|
|
2656
2580
|
}
|
|
2657
2581
|
function resolveSlackMessageText(message) {
|
|
2658
|
-
const messageText = normalizeOptionalString(message.text) ?? resolveSlackAttachmentFallbackText(message.attachments);
|
|
2582
|
+
const messageText = normalizeOptionalString(message.text) ?? resolveSlackAttachmentFallbackText(message.attachments) ?? (message.attachments?.some((attachment) => attachment.is_share === true && (normalizeOptionalString(attachment.image_url) || attachment.files?.length)) ? "[Slack media attachment]" : void 0);
|
|
2659
2583
|
return resolveSlackMessageText$1({
|
|
2660
2584
|
...message,
|
|
2661
2585
|
text: messageText
|
|
@@ -2670,11 +2594,12 @@ async function resolveSlackThreadStarter(params) {
|
|
|
2670
2594
|
params.threadTs
|
|
2671
2595
|
]);
|
|
2672
2596
|
const cached = THREAD_STARTER_CACHE.get(cacheKey);
|
|
2673
|
-
if (cached) {
|
|
2597
|
+
if (cached && !params.refresh) {
|
|
2674
2598
|
const now = asDateTimestampMs(Date.now());
|
|
2675
2599
|
if (now !== void 0 && cached.expiresAt > now) return cached.value;
|
|
2676
2600
|
THREAD_STARTER_CACHE.delete(cacheKey);
|
|
2677
2601
|
}
|
|
2602
|
+
if (params.refresh) THREAD_STARTER_CACHE.delete(cacheKey);
|
|
2678
2603
|
try {
|
|
2679
2604
|
const message = (await params.client.conversations.replies({
|
|
2680
2605
|
channel: params.channelId,
|
|
@@ -2703,7 +2628,7 @@ async function resolveSlackThreadStarter(params) {
|
|
|
2703
2628
|
}
|
|
2704
2629
|
return starter;
|
|
2705
2630
|
} catch (err) {
|
|
2706
|
-
logVerbose
|
|
2631
|
+
logVerbose(`slack thread starter fetch failed channel=${params.channelId} ts=${params.threadTs}: ${formatErrorMessage(err)}`);
|
|
2707
2632
|
return null;
|
|
2708
2633
|
}
|
|
2709
2634
|
}
|
|
@@ -2725,25 +2650,36 @@ async function resolveSlackThreadHistory(params) {
|
|
|
2725
2650
|
try {
|
|
2726
2651
|
do {
|
|
2727
2652
|
pagesFetched += 1;
|
|
2653
|
+
params.assertCurrent?.();
|
|
2728
2654
|
const response = await params.client.conversations.replies({
|
|
2729
2655
|
channel: params.channelId,
|
|
2730
2656
|
ts: params.threadTs,
|
|
2731
2657
|
limit: fetchLimit,
|
|
2732
|
-
inclusive:
|
|
2658
|
+
inclusive: false,
|
|
2659
|
+
...params.currentMessageTs ? { latest: params.currentMessageTs } : {},
|
|
2660
|
+
...params.oldest ? { oldest: params.oldest } : {},
|
|
2733
2661
|
...cursor ? { cursor } : {}
|
|
2734
2662
|
});
|
|
2663
|
+
params.assertCurrent?.();
|
|
2735
2664
|
for (const msg of response.messages ?? []) {
|
|
2665
|
+
const timestamp = resolveSlackTimestampMs(msg.ts);
|
|
2736
2666
|
const text = resolveSlackMessageText(msg);
|
|
2737
2667
|
if (!text && !msg.files?.length) continue;
|
|
2738
|
-
if (params.currentMessageTs && msg.ts
|
|
2668
|
+
if (!msg.ts || msg.ts === params.currentMessageTs || params.currentMessageTs && timestamp !== void 0 && Number(msg.ts) >= Number(params.currentMessageTs) || params.oldest && (timestamp === void 0 || Number(msg.ts) <= Number(params.oldest)) || params.excludedMessageIds?.has(msg.ts)) continue;
|
|
2669
|
+
if (retained.some(([entry]) => entry.ts === msg.ts)) continue;
|
|
2739
2670
|
retained.push([msg, text]);
|
|
2740
2671
|
}
|
|
2741
2672
|
if (retained.length > maxMessages) retained.splice(0, retained.length - maxMessages);
|
|
2742
2673
|
const next = response.response_metadata?.next_cursor;
|
|
2743
2674
|
cursor = typeof next === "string" && next.trim().length > 0 ? next.trim() : void 0;
|
|
2675
|
+
if (response.has_more && !cursor) {
|
|
2676
|
+
params.onOmission?.("Slack returned an incomplete thread page without a cursor");
|
|
2677
|
+
return [];
|
|
2678
|
+
}
|
|
2744
2679
|
} while (cursor && pagesFetched < SLACK_THREAD_HISTORY_MAX_PAGES);
|
|
2745
2680
|
if (cursor) {
|
|
2746
|
-
logVerbose
|
|
2681
|
+
logVerbose(`slack thread history capped channel=${params.channelId} ts=${params.threadTs} pages=${SLACK_THREAD_HISTORY_MAX_PAGES}`);
|
|
2682
|
+
params.onOmission?.("Slack thread exceeds the three-page automatic history budget");
|
|
2747
2683
|
return [];
|
|
2748
2684
|
}
|
|
2749
2685
|
return retained.map(([message, text]) => ({
|
|
@@ -2751,13 +2687,55 @@ async function resolveSlackThreadHistory(params) {
|
|
|
2751
2687
|
userId: message.user,
|
|
2752
2688
|
botId: message.bot_id,
|
|
2753
2689
|
ts: message.ts,
|
|
2754
|
-
files: message.files
|
|
2690
|
+
files: message.files,
|
|
2691
|
+
attachments: message.attachments
|
|
2755
2692
|
}));
|
|
2756
2693
|
} catch (err) {
|
|
2757
|
-
|
|
2694
|
+
params.assertCurrent?.();
|
|
2695
|
+
params.onOmission?.(formatErrorMessage(err));
|
|
2696
|
+
logVerbose(`slack thread history fetch failed channel=${params.channelId} ts=${params.threadTs}: ${formatErrorMessage(err)}`);
|
|
2758
2697
|
return [];
|
|
2759
2698
|
}
|
|
2760
2699
|
}
|
|
2700
|
+
/** Slack channel history is newest first, unlike chronological thread replies. */
|
|
2701
|
+
async function resolveSlackChannelHistory(params) {
|
|
2702
|
+
if (!Number.isFinite(params.limit) || params.limit <= 0) return [];
|
|
2703
|
+
const messages = [];
|
|
2704
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2705
|
+
let cursor;
|
|
2706
|
+
let scanned = 0;
|
|
2707
|
+
const maxPages = Math.ceil(params.limit / 200);
|
|
2708
|
+
for (let page = 0; page < maxPages; page += 1) {
|
|
2709
|
+
params.assertCurrent?.();
|
|
2710
|
+
const response = await params.client.conversations.history({
|
|
2711
|
+
channel: params.channelId,
|
|
2712
|
+
latest: params.currentMessageTs,
|
|
2713
|
+
...params.oldest ? { oldest: params.oldest } : {},
|
|
2714
|
+
inclusive: false,
|
|
2715
|
+
limit: Math.min(200, params.limit - scanned),
|
|
2716
|
+
...cursor ? { cursor } : {}
|
|
2717
|
+
});
|
|
2718
|
+
params.assertCurrent?.();
|
|
2719
|
+
for (const message of response.messages ?? []) {
|
|
2720
|
+
scanned += 1;
|
|
2721
|
+
if (!message.ts || Number(message.ts) >= Number(params.currentMessageTs) || params.oldest && Number(message.ts) <= Number(params.oldest) || params.excludedMessageIds.has(message.ts) || seen.has(message.ts)) continue;
|
|
2722
|
+
seen.add(message.ts);
|
|
2723
|
+
const text = resolveSlackMessageText(message);
|
|
2724
|
+
if (!text && !message.files?.length) continue;
|
|
2725
|
+
messages.push({
|
|
2726
|
+
text: text ?? formatSlackFilePlaceholder(message.files),
|
|
2727
|
+
userId: message.user,
|
|
2728
|
+
botId: message.bot_id,
|
|
2729
|
+
ts: message.ts,
|
|
2730
|
+
files: message.files,
|
|
2731
|
+
attachments: message.attachments
|
|
2732
|
+
});
|
|
2733
|
+
}
|
|
2734
|
+
cursor = response.response_metadata?.next_cursor?.trim() || void 0;
|
|
2735
|
+
if (!cursor || scanned >= params.limit) break;
|
|
2736
|
+
}
|
|
2737
|
+
return messages.slice(0, params.limit).toReversed();
|
|
2738
|
+
}
|
|
2761
2739
|
//#endregion
|
|
2762
2740
|
//#region extensions/slack/src/monitor/message-handler/preflight-audio.ts
|
|
2763
2741
|
function isSlackAudioFile(file) {
|
|
@@ -2798,9 +2776,7 @@ async function resolveSlackPreflightAudioTranscript(params) {
|
|
|
2798
2776
|
mediaIndex
|
|
2799
2777
|
} : null;
|
|
2800
2778
|
}
|
|
2801
|
-
|
|
2802
|
-
await slackPreflightAudio.send(params);
|
|
2803
|
-
}
|
|
2779
|
+
const sendSlackPreflightAudioTranscriptEcho = slackPreflightAudio.send.bind(slackPreflightAudio);
|
|
2804
2780
|
async function discardSlackPreflightMedia(media) {
|
|
2805
2781
|
await Promise.allSettled((media ?? []).map((entry) => fs.rm(entry.path, { force: true })));
|
|
2806
2782
|
}
|
|
@@ -2810,7 +2786,7 @@ const SLACK_MENTION_RESOLUTION_CONCURRENCY = 4;
|
|
|
2810
2786
|
const SLACK_MENTION_RESOLUTION_MAX_LOOKUPS_PER_MESSAGE = 20;
|
|
2811
2787
|
const SLACK_USER_MENTION_RE$1 = /<@([A-Z0-9]+)(?:\|[^>]+)?>/gi;
|
|
2812
2788
|
const MAX_SLACK_UNAVAILABLE_FILE_TEXT_CHARS = 2e3;
|
|
2813
|
-
const loadSlackMediaModule$1 = createLazyRuntimeModule(() => import("./actions-
|
|
2789
|
+
const loadSlackMediaModule$1 = createLazyRuntimeModule(() => import("./actions-Df0CzcDl.mjs").then((n) => n._));
|
|
2814
2790
|
function formatSlackUnavailableMedia(params) {
|
|
2815
2791
|
let fileReferences = params.files?.map((file) => `${formatSlackFileReference(file)} unavailable (${file.reason})`).join(", ");
|
|
2816
2792
|
if (fileReferences && fileReferences.length > MAX_SLACK_UNAVAILABLE_FILE_TEXT_CHARS) fileReferences = `${truncateUtf16Safe(fileReferences, MAX_SLACK_UNAVAILABLE_FILE_TEXT_CHARS)}; … (file references truncated)`;
|
|
@@ -2829,18 +2805,15 @@ function formatSlackUnavailableMedia(params) {
|
|
|
2829
2805
|
}
|
|
2830
2806
|
function collectUniqueSlackMentionIds$1(texts) {
|
|
2831
2807
|
const seen = /* @__PURE__ */ new Set();
|
|
2832
|
-
const mentionIds = [];
|
|
2833
2808
|
for (const text of texts) {
|
|
2834
2809
|
if (!text) continue;
|
|
2835
2810
|
SLACK_USER_MENTION_RE$1.lastIndex = 0;
|
|
2836
2811
|
for (const match of text.matchAll(SLACK_USER_MENTION_RE$1)) {
|
|
2837
2812
|
const userId = match[1];
|
|
2838
|
-
if (
|
|
2839
|
-
seen.add(userId);
|
|
2840
|
-
mentionIds.push(userId);
|
|
2813
|
+
if (userId) seen.add(userId);
|
|
2841
2814
|
}
|
|
2842
2815
|
}
|
|
2843
|
-
return
|
|
2816
|
+
return [...seen];
|
|
2844
2817
|
}
|
|
2845
2818
|
function renderSlackUserMentions(text, renderedMentions) {
|
|
2846
2819
|
if (!text || renderedMentions.size === 0) return text;
|
|
@@ -2851,8 +2824,7 @@ function renderSlackUserMentions(text, renderedMentions) {
|
|
|
2851
2824
|
}
|
|
2852
2825
|
function filterInheritedParentFiles(params) {
|
|
2853
2826
|
const { files, isThreadReply, threadStarter } = params;
|
|
2854
|
-
if (!isThreadReply || !files?.length) return files;
|
|
2855
|
-
if (!threadStarter?.files?.length) return files;
|
|
2827
|
+
if (!isThreadReply || !files?.length || !threadStarter?.files?.length) return files;
|
|
2856
2828
|
const starterFileIds = new Set(threadStarter.files.map((file) => file.id));
|
|
2857
2829
|
const filtered = files.filter((file) => !file.id || !starterFileIds.has(file.id));
|
|
2858
2830
|
if (filtered.length < files.length) logVerbose(`slack: filtered ${files.length - filtered.length} inherited parent file(s) from thread reply`);
|
|
@@ -2873,19 +2845,13 @@ async function resolveSlackMessageContent(params) {
|
|
|
2873
2845
|
readIdleTimeoutMs: params.mediaReadIdleTimeoutMs,
|
|
2874
2846
|
totalTimeoutMs: params.mediaTotalTimeoutMs,
|
|
2875
2847
|
abortSignal: params.abortSignal,
|
|
2848
|
+
assertCurrent: params.assertCurrent,
|
|
2876
2849
|
preloadedMedia: params.preloadedMedia
|
|
2877
2850
|
})) : null;
|
|
2878
2851
|
const effectiveDirectMedia = attachmentContent?.media.length ? attachmentContent.media : null;
|
|
2879
2852
|
const mediaPlaceholder = effectiveDirectMedia?.map((item) => item.placeholder).join(" ");
|
|
2880
2853
|
let botAttachmentText;
|
|
2881
|
-
if (params.isBotMessage && !attachmentContent?.text)
|
|
2882
|
-
const botAttachmentTextParts = [];
|
|
2883
|
-
for (const attachment of params.message.attachments ?? []) {
|
|
2884
|
-
const text = normalizeOptionalString(attachment.text) ?? normalizeOptionalString(attachment.fallback);
|
|
2885
|
-
if (text) botAttachmentTextParts.push(text);
|
|
2886
|
-
}
|
|
2887
|
-
botAttachmentText = botAttachmentTextParts.length > 0 ? botAttachmentTextParts.join("\n") : void 0;
|
|
2888
|
-
}
|
|
2854
|
+
if (params.isBotMessage && !attachmentContent?.text) botAttachmentText = (params.message.attachments ?? []).map((attachment) => normalizeOptionalString(attachment.text) ?? normalizeOptionalString(attachment.fallback)).filter(Boolean).join("\n") || void 0;
|
|
2889
2855
|
const textParts = [
|
|
2890
2856
|
resolveSlackMessageText$1(params.message),
|
|
2891
2857
|
attachmentContent?.text,
|
|
@@ -2914,17 +2880,9 @@ async function resolveSlackMessageContent(params) {
|
|
|
2914
2880
|
renderedMentions.set(result.userId, result.rendered);
|
|
2915
2881
|
}
|
|
2916
2882
|
}
|
|
2917
|
-
const renderedMessageText = renderSlackUserMentions(textParts[0], renderedMentions);
|
|
2918
|
-
const renderedAttachmentText = renderSlackUserMentions(textParts[1], renderedMentions);
|
|
2919
|
-
const renderedBotAttachmentText = renderSlackUserMentions(textParts[2], renderedMentions);
|
|
2920
2883
|
const commandSourceText = renderSlackUserMentions(normalizeOptionalString(params.message.text), renderedMentions) ?? "";
|
|
2921
2884
|
const rawBody = formatSlackUnavailableMedia({
|
|
2922
|
-
body: [
|
|
2923
|
-
renderedMessageText,
|
|
2924
|
-
renderedAttachmentText,
|
|
2925
|
-
renderedBotAttachmentText,
|
|
2926
|
-
mediaPlaceholder
|
|
2927
|
-
].filter(Boolean).join("\n") || "",
|
|
2885
|
+
body: [...textParts.map((text) => renderSlackUserMentions(text, renderedMentions)), mediaPlaceholder].filter(Boolean).join("\n"),
|
|
2928
2886
|
files: attachmentContent?.files,
|
|
2929
2887
|
unavailableMediaCount: attachmentContent?.unavailableMediaCount ?? 0
|
|
2930
2888
|
});
|
|
@@ -2939,8 +2897,8 @@ async function resolveSlackMessageContent(params) {
|
|
|
2939
2897
|
//#endregion
|
|
2940
2898
|
//#region extensions/slack/src/monitor/message-handler/prepare-dm-history.ts
|
|
2941
2899
|
function resolveSlackDmHistoryLimit(params) {
|
|
2942
|
-
const override = params.userId
|
|
2943
|
-
return
|
|
2900
|
+
const override = params.userId ? params.account.config.dms?.[params.userId]?.historyLimit : void 0;
|
|
2901
|
+
return resolvePromptHistoryLimit(override ?? params.defaultLimit, 0);
|
|
2944
2902
|
}
|
|
2945
2903
|
async function resolveSlackDmHistoryContext(params) {
|
|
2946
2904
|
const maxMessages = Math.max(0, Math.floor(params.limit));
|
|
@@ -3016,56 +2974,177 @@ function isSlackThreadAuthorCurrentBot(params) {
|
|
|
3016
2974
|
if (identity.botId && author.botId && author.botId === identity.botId) return true;
|
|
3017
2975
|
return false;
|
|
3018
2976
|
}
|
|
3019
|
-
|
|
3020
|
-
|
|
3021
|
-
|
|
3022
|
-
|
|
3023
|
-
|
|
3024
|
-
|
|
2977
|
+
//#endregion
|
|
2978
|
+
//#region extensions/slack/src/monitor/message-handler/prepare-room-history.ts
|
|
2979
|
+
const SLACK_HISTORY_MEDIA_MAX_ATTACHMENTS = 4;
|
|
2980
|
+
const SLACK_HISTORY_MEDIA_MAX_BYTES = 10485760;
|
|
2981
|
+
const SLACK_HISTORY_MEDIA_IDLE_TIMEOUT_MS = 1e3;
|
|
2982
|
+
const SLACK_HISTORY_MEDIA_TOTAL_TIMEOUT_MS = 3e3;
|
|
2983
|
+
async function resolveSlackRoomHistory(params) {
|
|
2984
|
+
if (params.ctx.historyLimit <= 0 || !params.message.ts) return [];
|
|
2985
|
+
const warnOmission = (reason) => {
|
|
2986
|
+
params.ctx.logger.warn({
|
|
2987
|
+
accountId: params.ctx.accountId,
|
|
2988
|
+
teamId: params.eventScope?.teamId ?? params.ctx.teamId,
|
|
2989
|
+
channelId: params.message.channel,
|
|
2990
|
+
threadTs: params.threadTs,
|
|
2991
|
+
reason
|
|
2992
|
+
}, "Slack automatic history omitted");
|
|
3025
2993
|
};
|
|
3026
|
-
|
|
3027
|
-
|
|
3028
|
-
|
|
3029
|
-
|
|
3030
|
-
|
|
3031
|
-
|
|
3032
|
-
|
|
3033
|
-
|
|
3034
|
-
|
|
3035
|
-
|
|
3036
|
-
|
|
2994
|
+
try {
|
|
2995
|
+
params.assertCurrent();
|
|
2996
|
+
const request = {
|
|
2997
|
+
channelId: params.message.channel,
|
|
2998
|
+
client: params.eventScope?.client ?? params.ctx.app.client,
|
|
2999
|
+
currentMessageTs: params.message.ts,
|
|
3000
|
+
oldest: params.oldest,
|
|
3001
|
+
excludedMessageIds: params.excludedMessageIds,
|
|
3002
|
+
limit: Math.max(DEFAULT_GROUP_HISTORY_LIMIT, params.ctx.historyLimit),
|
|
3003
|
+
assertCurrent: params.assertCurrent
|
|
3004
|
+
};
|
|
3005
|
+
const messages = params.threadTs ? await resolveSlackThreadHistory({
|
|
3006
|
+
...request,
|
|
3007
|
+
threadTs: params.threadTs,
|
|
3008
|
+
onOmission: warnOmission
|
|
3009
|
+
}) : await resolveSlackChannelHistory(request);
|
|
3010
|
+
params.assertCurrent();
|
|
3011
|
+
const permitted = [];
|
|
3012
|
+
for (const message of messages) {
|
|
3013
|
+
if (isSlackThreadAuthorCurrentBot({
|
|
3014
|
+
identity: params.ctx,
|
|
3015
|
+
author: message
|
|
3016
|
+
})) continue;
|
|
3017
|
+
const user = message.userId ? await params.ctx.resolveUserName(message.userId, params.eventScope) : void 0;
|
|
3018
|
+
params.assertCurrent();
|
|
3019
|
+
const senderAllowed = resolveSlackUserAllowed({
|
|
3020
|
+
allowList: params.allowFromLower,
|
|
3021
|
+
teamId: params.eventScope?.teamId ?? params.ctx.teamId,
|
|
3022
|
+
userId: message.userId ?? message.botId,
|
|
3023
|
+
userName: user?.name,
|
|
3024
|
+
allowNameMatching: params.ctx.allowNameMatching
|
|
3025
|
+
});
|
|
3026
|
+
if (!shouldIncludeSupplementalContext({
|
|
3027
|
+
mode: params.contextVisibilityMode,
|
|
3028
|
+
kind: "history",
|
|
3029
|
+
senderAllowed
|
|
3030
|
+
})) continue;
|
|
3031
|
+
permitted.push({
|
|
3032
|
+
message,
|
|
3033
|
+
sender: user?.name ?? message.userId ?? `Bot (${message.botId ?? "unknown"})`
|
|
3034
|
+
});
|
|
3037
3035
|
}
|
|
3038
|
-
|
|
3039
|
-
|
|
3036
|
+
const entries = [];
|
|
3037
|
+
let mediaRemaining = SLACK_HISTORY_MEDIA_MAX_ATTACHMENTS;
|
|
3038
|
+
for (const { message, sender } of permitted.slice(-params.ctx.historyLimit)) {
|
|
3039
|
+
const { media, attempted } = mediaRemaining > 0 && (message.files?.length || message.attachments?.length) ? await resolveSlackHistoryMedia({
|
|
3040
|
+
ctx: params.ctx,
|
|
3041
|
+
eventScope: params.eventScope,
|
|
3042
|
+
maxAttachments: mediaRemaining,
|
|
3043
|
+
assertCurrent: params.assertCurrent,
|
|
3044
|
+
abortSignal: params.abortSignal,
|
|
3045
|
+
message: {
|
|
3046
|
+
type: "message",
|
|
3047
|
+
channel: params.message.channel,
|
|
3048
|
+
ts: message.ts,
|
|
3049
|
+
user: message.userId,
|
|
3050
|
+
bot_id: message.botId,
|
|
3051
|
+
text: message.text,
|
|
3052
|
+
files: message.files,
|
|
3053
|
+
attachments: message.attachments
|
|
3054
|
+
}
|
|
3055
|
+
}) : {
|
|
3056
|
+
media: [],
|
|
3057
|
+
attempted: 0
|
|
3058
|
+
};
|
|
3059
|
+
params.assertCurrent();
|
|
3060
|
+
mediaRemaining -= attempted;
|
|
3061
|
+
entries.push({
|
|
3062
|
+
sender,
|
|
3063
|
+
body: message.text,
|
|
3064
|
+
timestamp: resolveSlackTimestampMs(message.ts),
|
|
3065
|
+
messageId: message.ts,
|
|
3066
|
+
...media.length > 0 ? { media } : {}
|
|
3067
|
+
});
|
|
3068
|
+
}
|
|
3069
|
+
return entries;
|
|
3070
|
+
} catch (error) {
|
|
3071
|
+
warnOmission(formatErrorMessage(error));
|
|
3072
|
+
return [];
|
|
3040
3073
|
}
|
|
3041
|
-
return {
|
|
3042
|
-
kept,
|
|
3043
|
-
omittedCurrentBot
|
|
3044
|
-
};
|
|
3045
3074
|
}
|
|
3046
|
-
function
|
|
3047
|
-
if (
|
|
3048
|
-
return
|
|
3075
|
+
function isSlackImageFileCandidate(file) {
|
|
3076
|
+
if ((file.mimetype?.split(";")[0]?.trim().toLowerCase())?.startsWith("image/")) return true;
|
|
3077
|
+
return Boolean(mimeTypeFromFilePath(file.name)?.startsWith("image/"));
|
|
3049
3078
|
}
|
|
3050
|
-
function
|
|
3051
|
-
if (
|
|
3052
|
-
|
|
3053
|
-
return [params.threadStarter, ...params.history];
|
|
3079
|
+
function sliceSlackImageFileCandidates(files, limit) {
|
|
3080
|
+
if (limit <= 0 || !files?.length) return [];
|
|
3081
|
+
return files.filter(isSlackImageFileCandidate).slice(0, limit);
|
|
3054
3082
|
}
|
|
3055
|
-
function
|
|
3056
|
-
|
|
3057
|
-
|
|
3058
|
-
|
|
3059
|
-
|
|
3060
|
-
|
|
3083
|
+
function sliceSlackHistoryAttachmentCandidates(attachments, limit) {
|
|
3084
|
+
if (limit <= 0 || !attachments?.length) return [];
|
|
3085
|
+
const out = [];
|
|
3086
|
+
let remaining = limit;
|
|
3087
|
+
for (const attachment of attachments) {
|
|
3088
|
+
if (attachment.is_share !== true) continue;
|
|
3089
|
+
const hasImageUrl = Boolean(normalizeOptionalString(attachment.image_url));
|
|
3090
|
+
const files = sliceSlackImageFileCandidates(attachment.files, remaining - (hasImageUrl ? 1 : 0));
|
|
3091
|
+
if (!hasImageUrl && files.length === 0) continue;
|
|
3092
|
+
out.push({
|
|
3093
|
+
...attachment,
|
|
3094
|
+
files
|
|
3095
|
+
});
|
|
3096
|
+
remaining -= (hasImageUrl ? 1 : 0) + files.length;
|
|
3097
|
+
if (remaining <= 0) break;
|
|
3098
|
+
}
|
|
3099
|
+
return out;
|
|
3061
3100
|
}
|
|
3062
|
-
function
|
|
3063
|
-
|
|
3101
|
+
function buildSlackHistoryMediaCandidateMessage(message, maxAttachments) {
|
|
3102
|
+
const files = sliceSlackImageFileCandidates(message.files, maxAttachments);
|
|
3103
|
+
const attachments = sliceSlackHistoryAttachmentCandidates(message.attachments, Math.max(0, maxAttachments - files.length));
|
|
3104
|
+
if (files.length === 0 && attachments.length === 0) return null;
|
|
3105
|
+
return {
|
|
3106
|
+
message: {
|
|
3107
|
+
...message,
|
|
3108
|
+
files,
|
|
3109
|
+
attachments
|
|
3110
|
+
},
|
|
3111
|
+
attempted: files.length + attachments.reduce((count, attachment) => count + (normalizeOptionalString(attachment.image_url) ? 1 : 0) + (attachment.files?.length ?? 0), 0)
|
|
3112
|
+
};
|
|
3113
|
+
}
|
|
3114
|
+
async function resolveSlackHistoryMedia(params) {
|
|
3115
|
+
const candidate = buildSlackHistoryMediaCandidateMessage(params.message, params.maxAttachments);
|
|
3116
|
+
if (!candidate) return {
|
|
3117
|
+
media: [],
|
|
3118
|
+
attempted: 0
|
|
3119
|
+
};
|
|
3120
|
+
const content = await resolveSlackMessageContent({
|
|
3121
|
+
message: candidate.message,
|
|
3122
|
+
isThreadReply: false,
|
|
3123
|
+
threadStarter: null,
|
|
3124
|
+
isBotMessage: Boolean(params.message.bot_id),
|
|
3125
|
+
client: params.eventScope?.client ?? params.ctx.app.client,
|
|
3126
|
+
botToken: params.ctx.botToken,
|
|
3127
|
+
mediaMaxBytes: Math.min(params.ctx.mediaMaxBytes, SLACK_HISTORY_MEDIA_MAX_BYTES),
|
|
3128
|
+
mediaReadIdleTimeoutMs: SLACK_HISTORY_MEDIA_IDLE_TIMEOUT_MS,
|
|
3129
|
+
mediaTotalTimeoutMs: SLACK_HISTORY_MEDIA_TOTAL_TIMEOUT_MS,
|
|
3130
|
+
assertCurrent: params.assertCurrent,
|
|
3131
|
+
abortSignal: params.abortSignal
|
|
3132
|
+
});
|
|
3133
|
+
return {
|
|
3134
|
+
media: await toInboundMediaFactsWithMetadata(content?.effectiveDirectMedia, {
|
|
3135
|
+
kind: "image",
|
|
3136
|
+
messageId: params.message.ts
|
|
3137
|
+
}),
|
|
3138
|
+
attempted: candidate.attempted
|
|
3139
|
+
};
|
|
3064
3140
|
}
|
|
3065
3141
|
//#endregion
|
|
3066
3142
|
//#region extensions/slack/src/monitor/message-handler/prepare-thread-context.ts
|
|
3067
|
-
const loadSlackMediaModule = createLazyRuntimeModule(() => import("./actions-
|
|
3143
|
+
const loadSlackMediaModule = createLazyRuntimeModule(() => import("./actions-Df0CzcDl.mjs").then((n) => n._));
|
|
3068
3144
|
const SLACK_THREAD_CONTEXT_USER_LOOKUP_CONCURRENCY = 4;
|
|
3145
|
+
function formatSlackThreadLabelSnippet(text) {
|
|
3146
|
+
return truncateUtf16Safe(text.replace(/\s+/g, " "), 80);
|
|
3147
|
+
}
|
|
3069
3148
|
function resolveSlackThreadSessionFreshness(params) {
|
|
3070
3149
|
return params.ctx.channelRuntime?.session?.resolveEntryResetFreshness?.({
|
|
3071
3150
|
agentId: params.agentId,
|
|
@@ -3079,45 +3158,16 @@ function resolveSlackThreadSessionFreshness(params) {
|
|
|
3079
3158
|
})
|
|
3080
3159
|
});
|
|
3081
3160
|
}
|
|
3082
|
-
function isSlackThreadContextSenderAllowed(params) {
|
|
3083
|
-
return resolveInboundSupplementalSenderAllowed({
|
|
3084
|
-
isGroup: true,
|
|
3085
|
-
groupPolicy: params.allowFromLower.length === 0 ? "open" : "allowlist",
|
|
3086
|
-
allowFrom: params.allowFromLower,
|
|
3087
|
-
isSenderAllowed: (allowFrom) => {
|
|
3088
|
-
if (params.botId) return true;
|
|
3089
|
-
if (!params.userId) return false;
|
|
3090
|
-
return resolveSlackAllowListMatch({
|
|
3091
|
-
allowList: allowFrom,
|
|
3092
|
-
id: params.userId,
|
|
3093
|
-
name: params.userName,
|
|
3094
|
-
allowNameMatching: params.allowNameMatching
|
|
3095
|
-
}).allowed;
|
|
3096
|
-
}
|
|
3097
|
-
});
|
|
3098
|
-
}
|
|
3099
3161
|
async function resolveSlackThreadUserMap(params) {
|
|
3100
|
-
const uniqueUserIds = [];
|
|
3101
|
-
const seen = /* @__PURE__ */ new Set();
|
|
3102
|
-
for (const item of params.messages) {
|
|
3103
|
-
if (!item.userId || seen.has(item.userId)) continue;
|
|
3104
|
-
seen.add(item.userId);
|
|
3105
|
-
uniqueUserIds.push(item.userId);
|
|
3106
|
-
}
|
|
3107
|
-
const userMap = /* @__PURE__ */ new Map();
|
|
3108
|
-
if (uniqueUserIds.length === 0) return userMap;
|
|
3162
|
+
const uniqueUserIds = [...new Set(params.messages.map((item) => item.userId).filter((id) => Boolean(id)))];
|
|
3109
3163
|
const { results } = await runTasksWithConcurrency({
|
|
3110
3164
|
tasks: uniqueUserIds.map((id) => async () => {
|
|
3111
3165
|
const user = await params.ctx.resolveUserName(id, params.eventScope);
|
|
3112
|
-
return user ?
|
|
3113
|
-
id,
|
|
3114
|
-
user
|
|
3115
|
-
} : null;
|
|
3166
|
+
return user ? [id, user] : null;
|
|
3116
3167
|
}),
|
|
3117
3168
|
limit: SLACK_THREAD_CONTEXT_USER_LOOKUP_CONCURRENCY
|
|
3118
3169
|
});
|
|
3119
|
-
|
|
3120
|
-
return userMap;
|
|
3170
|
+
return new Map(results.flatMap((result) => result ? [result] : []));
|
|
3121
3171
|
}
|
|
3122
3172
|
async function resolveSlackThreadContextData(params) {
|
|
3123
3173
|
const botIdentity = {
|
|
@@ -3155,16 +3205,14 @@ async function resolveSlackThreadContextData(params) {
|
|
|
3155
3205
|
};
|
|
3156
3206
|
const starter = params.threadStarter;
|
|
3157
3207
|
const starterSenderName = params.allowNameMatching && params.allowFromLower.length > 0 && starter?.userId ? (await params.ctx.resolveUserName(starter.userId, params.eventScope))?.name : void 0;
|
|
3158
|
-
|
|
3159
|
-
|
|
3160
|
-
|
|
3161
|
-
|
|
3162
|
-
|
|
3163
|
-
allowFromLower: params.allowFromLower,
|
|
3208
|
+
params.assertHistoryCurrent?.();
|
|
3209
|
+
const starterIsCurrentBot = Boolean(starter && isCurrentBotAuthor(starter));
|
|
3210
|
+
const starterAllowed = !starter || !starterIsCurrentBot && resolveSlackUserAllowed({
|
|
3211
|
+
allowList: params.allowFromLower,
|
|
3212
|
+
teamId: params.eventScope?.teamId ?? params.ctx.teamId,
|
|
3164
3213
|
allowNameMatching: params.allowNameMatching,
|
|
3165
|
-
userId: starter.userId,
|
|
3166
|
-
userName: starterSenderName
|
|
3167
|
-
botId: starter.botId
|
|
3214
|
+
userId: starter.userId ?? starter.botId,
|
|
3215
|
+
userName: starterSenderName
|
|
3168
3216
|
});
|
|
3169
3217
|
const includeStarterContext = !starter || !starterIsCurrentBot && shouldIncludeSupplementalContext({
|
|
3170
3218
|
mode: params.contextVisibilityMode,
|
|
@@ -3177,12 +3225,16 @@ async function resolveSlackThreadContextData(params) {
|
|
|
3177
3225
|
threadLabel = `Slack thread ${params.roomLabel}${snippet ? `: ${snippet}` : ""}`;
|
|
3178
3226
|
if (shouldSeedInitialThreadContext && !params.effectiveDirectMedia && starter.files && starter.files.length > 0) {
|
|
3179
3227
|
const { resolveSlackAttachmentContent } = await loadSlackMediaModule();
|
|
3228
|
+
params.assertHistoryCurrent?.();
|
|
3180
3229
|
const attachmentContent = await resolveSlackAttachmentContent({
|
|
3181
3230
|
files: starter.files,
|
|
3182
3231
|
client: params.eventScope?.client ?? params.ctx.app.client,
|
|
3183
3232
|
token: params.ctx.botToken,
|
|
3184
|
-
maxBytes: params.ctx.mediaMaxBytes
|
|
3233
|
+
maxBytes: params.ctx.mediaMaxBytes,
|
|
3234
|
+
assertCurrent: params.assertHistoryCurrent,
|
|
3235
|
+
abortSignal: params.abortSignal
|
|
3185
3236
|
});
|
|
3237
|
+
params.assertHistoryCurrent?.();
|
|
3186
3238
|
threadStarterMedia = attachmentContent?.media.length ? attachmentContent.media : null;
|
|
3187
3239
|
if (attachmentContent) threadStarterBody = formatSlackUnavailableMedia({
|
|
3188
3240
|
body: threadStarterBody,
|
|
@@ -3196,58 +3248,64 @@ async function resolveSlackThreadContextData(params) {
|
|
|
3196
3248
|
}
|
|
3197
3249
|
}
|
|
3198
3250
|
} else threadLabel = `Slack thread ${params.roomLabel}`;
|
|
3199
|
-
const includeBotStarterAsRootContext =
|
|
3200
|
-
starterIsCurrentBot,
|
|
3201
|
-
isNewThreadSession: shouldSeedInitialThreadContext,
|
|
3202
|
-
hasStarterText: Boolean(starter?.text)
|
|
3203
|
-
});
|
|
3251
|
+
const includeBotStarterAsRootContext = Boolean(starter?.text && starterIsCurrentBot && shouldSeedInitialThreadContext);
|
|
3204
3252
|
if (starter?.text && starterIsCurrentBot && !includeBotStarterAsRootContext) logVerbose("slack: omitted current-bot thread starter from context");
|
|
3205
3253
|
else if (starter?.text && !includeStarterContext && !starterIsCurrentBot) logVerbose(`slack: omitted thread starter from context (mode=${params.contextVisibilityMode}, sender_allowed=${starterAllowed ? "yes" : "no"})`);
|
|
3206
3254
|
else if (includeBotStarterAsRootContext) {
|
|
3207
|
-
|
|
3208
|
-
|
|
3209
|
-
starterText: starter?.text
|
|
3210
|
-
});
|
|
3255
|
+
const snippet = formatSlackThreadLabelSnippet(starter?.text ?? "").trim();
|
|
3256
|
+
threadLabel = `Slack thread ${params.roomLabel}${snippet ? ` (assistant root): ${snippet}` : ""}`;
|
|
3211
3257
|
logVerbose("slack: retained current-bot thread starter as assistant root context");
|
|
3212
3258
|
}
|
|
3213
|
-
const threadInitialHistoryLimit = params.account.config?.thread?.initialHistoryLimit ?? 20;
|
|
3259
|
+
const threadInitialHistoryLimit = Math.min(params.account.config?.thread?.initialHistoryLimit ?? 20, params.historyLimit ?? Number.POSITIVE_INFINITY);
|
|
3214
3260
|
if (threadInitialHistoryLimit > 0 && shouldLoadInitialThreadHistory) {
|
|
3215
3261
|
const currentBotRootTs = starter?.ts ?? params.threadTs;
|
|
3262
|
+
let historyOmitted = false;
|
|
3216
3263
|
const threadHistory = await resolveSlackThreadHistory({
|
|
3217
3264
|
channelId: params.message.channel,
|
|
3218
3265
|
threadTs: params.threadTs,
|
|
3219
3266
|
client: params.eventScope?.client ?? params.ctx.app.client,
|
|
3220
3267
|
currentMessageTs: params.message.ts,
|
|
3221
|
-
limit: threadInitialHistoryLimit
|
|
3268
|
+
limit: threadInitialHistoryLimit,
|
|
3269
|
+
excludedMessageIds: params.excludedMessageIds,
|
|
3270
|
+
assertCurrent: params.assertHistoryCurrent,
|
|
3271
|
+
onOmission: (reason) => {
|
|
3272
|
+
historyOmitted = true;
|
|
3273
|
+
params.ctx.logger.warn({
|
|
3274
|
+
channelId: params.message.channel,
|
|
3275
|
+
threadTs: params.threadTs,
|
|
3276
|
+
teamId: params.eventScope?.teamId ?? params.ctx.teamId,
|
|
3277
|
+
accountId: params.account.accountId,
|
|
3278
|
+
reason
|
|
3279
|
+
}, "Slack automatic thread history omitted");
|
|
3280
|
+
}
|
|
3222
3281
|
});
|
|
3282
|
+
if (historyOmitted) return {
|
|
3283
|
+
threadStarterBody,
|
|
3284
|
+
threadHistoryBody,
|
|
3285
|
+
shouldSeedInitialThreadContext,
|
|
3286
|
+
threadLabel,
|
|
3287
|
+
threadStarterMedia
|
|
3288
|
+
};
|
|
3223
3289
|
const enrichedStarter = starter && threadStarterBody && threadStarterBody !== starter.text ? {
|
|
3224
3290
|
...starter,
|
|
3225
3291
|
text: threadStarterBody,
|
|
3226
3292
|
ts: currentBotRootTs
|
|
3227
3293
|
} : null;
|
|
3228
|
-
const
|
|
3229
|
-
|
|
3230
|
-
|
|
3231
|
-
|
|
3232
|
-
|
|
3233
|
-
ts: currentBotRootTs
|
|
3234
|
-
} : null
|
|
3235
|
-
});
|
|
3294
|
+
const threadHistoryWithEnrichedRoot = enrichedStarter && !threadHistory.some((entry) => entry.ts === currentBotRootTs) ? [enrichedStarter, ...threadHistory.length >= threadInitialHistoryLimit ? threadHistory.slice(1) : threadHistory] : threadHistory;
|
|
3295
|
+
const threadHistoryWithBotRoot = includeBotStarterAsRootContext && starter && !threadHistoryWithEnrichedRoot.some((entry) => entry.ts === currentBotRootTs) ? [{
|
|
3296
|
+
...starter,
|
|
3297
|
+
ts: currentBotRootTs
|
|
3298
|
+
}, ...threadHistoryWithEnrichedRoot] : threadHistoryWithEnrichedRoot;
|
|
3236
3299
|
if (threadHistoryWithBotRoot.length > 0) {
|
|
3237
|
-
const
|
|
3238
|
-
|
|
3239
|
-
|
|
3240
|
-
includeBotStarterAsRootContext,
|
|
3241
|
-
starterTs: currentBotRootTs,
|
|
3242
|
-
retainCurrentBotHistory: params.isGroupDm && (isMissingThreadSession || isOutboundOnlyThreadSession)
|
|
3243
|
-
}),
|
|
3244
|
-
identity: botIdentity
|
|
3245
|
-
});
|
|
3300
|
+
const retainCurrentBotHistory = params.isGroupDm && (isMissingThreadSession || isOutboundOnlyThreadSession);
|
|
3301
|
+
const threadHistoryWithoutCurrentBot = threadHistoryWithBotRoot.filter((entry) => !isCurrentBotAuthor(entry) || retainCurrentBotHistory || includeBotStarterAsRootContext && entry.ts === currentBotRootTs);
|
|
3302
|
+
const omittedCurrentBotHistoryCount = threadHistoryWithBotRoot.length - threadHistoryWithoutCurrentBot.length;
|
|
3246
3303
|
const userMapForFilter = params.contextVisibilityMode !== "all" && params.allowNameMatching && params.allowFromLower.length > 0 ? await resolveSlackThreadUserMap({
|
|
3247
3304
|
ctx: params.ctx,
|
|
3248
3305
|
messages: threadHistoryWithoutCurrentBot,
|
|
3249
3306
|
eventScope: params.eventScope
|
|
3250
3307
|
}) : /* @__PURE__ */ new Map();
|
|
3308
|
+
params.assertHistoryCurrent?.();
|
|
3251
3309
|
const { items: filteredThreadHistory, omitted: omittedHistoryCount } = params.contextVisibilityMode === "all" ? {
|
|
3252
3310
|
items: threadHistoryWithoutCurrentBot,
|
|
3253
3311
|
omitted: 0
|
|
@@ -3256,34 +3314,29 @@ async function resolveSlackThreadContextData(params) {
|
|
|
3256
3314
|
mode: params.contextVisibilityMode,
|
|
3257
3315
|
kind: "thread",
|
|
3258
3316
|
isSenderAllowed: (historyMsg) => {
|
|
3259
|
-
if (isCurrentBotAuthor(
|
|
3260
|
-
userId: historyMsg.userId,
|
|
3261
|
-
botId: historyMsg.botId
|
|
3262
|
-
})) return true;
|
|
3317
|
+
if (isCurrentBotAuthor(historyMsg)) return true;
|
|
3263
3318
|
const msgUser = historyMsg.userId ? userMapForFilter.get(historyMsg.userId) : null;
|
|
3264
|
-
return
|
|
3265
|
-
|
|
3319
|
+
return resolveSlackUserAllowed({
|
|
3320
|
+
allowList: params.allowFromLower,
|
|
3321
|
+
teamId: params.eventScope?.teamId ?? params.ctx.teamId,
|
|
3266
3322
|
allowNameMatching: params.allowNameMatching,
|
|
3267
|
-
userId: historyMsg.userId,
|
|
3268
|
-
userName: msgUser?.name
|
|
3269
|
-
botId: historyMsg.botId
|
|
3323
|
+
userId: historyMsg.userId ?? historyMsg.botId,
|
|
3324
|
+
userName: msgUser?.name
|
|
3270
3325
|
});
|
|
3271
3326
|
}
|
|
3272
3327
|
});
|
|
3273
3328
|
const userMap = await resolveSlackThreadUserMap({
|
|
3274
3329
|
ctx: params.ctx,
|
|
3275
|
-
messages: filteredThreadHistory
|
|
3330
|
+
messages: filteredThreadHistory,
|
|
3331
|
+
eventScope: params.eventScope
|
|
3276
3332
|
});
|
|
3333
|
+
params.assertHistoryCurrent?.();
|
|
3277
3334
|
if (omittedHistoryCount > 0 || omittedCurrentBotHistoryCount > 0) logVerbose(`slack: omitted ${omittedHistoryCount + omittedCurrentBotHistoryCount} thread message(s) from context (mode=${params.contextVisibilityMode})`);
|
|
3278
3335
|
const historyParts = [];
|
|
3279
3336
|
for (const historyMsg of filteredThreadHistory) {
|
|
3280
3337
|
const msgUser = historyMsg.userId ? userMap.get(historyMsg.userId) : null;
|
|
3281
|
-
const
|
|
3282
|
-
const
|
|
3283
|
-
userId: historyMsg.userId,
|
|
3284
|
-
botId: historyMsg.botId
|
|
3285
|
-
});
|
|
3286
|
-
const role = isCurrentBot || isOtherBot || Boolean(historyMsg.botId) ? "assistant" : "user";
|
|
3338
|
+
const isCurrentBot = isCurrentBotAuthor(historyMsg);
|
|
3339
|
+
const role = isCurrentBot || historyMsg.botId ? "assistant" : "user";
|
|
3287
3340
|
const msgSenderName = isCurrentBot ? "Bot (this assistant)" : msgUser?.name ?? (historyMsg.botId ? `Bot (${historyMsg.botId})` : "Unknown");
|
|
3288
3341
|
const msgWithId = `${historyMsg.ts === currentBotRootTs && threadStarterBody ? threadStarterBody : historyMsg.text}\n[slack message id: ${historyMsg.ts ?? "unknown"} channel: ${params.message.channel}]`;
|
|
3289
3342
|
historyParts.push(formatInboundEnvelope({
|
|
@@ -3310,12 +3363,64 @@ async function resolveSlackThreadContextData(params) {
|
|
|
3310
3363
|
};
|
|
3311
3364
|
}
|
|
3312
3365
|
//#endregion
|
|
3366
|
+
//#region src/channels/mention-gating.ts
|
|
3367
|
+
function resolveBotThreadMentionPolicy(params) {
|
|
3368
|
+
if (!params.isBotOwnedThread || params.requireMentionInBotThreads === void 0) return {
|
|
3369
|
+
requireMention: params.requireMention,
|
|
3370
|
+
implicitMentionKinds: params.implicitMentionKinds
|
|
3371
|
+
};
|
|
3372
|
+
return {
|
|
3373
|
+
requireMention: params.requireMentionInBotThreads,
|
|
3374
|
+
implicitMentionKinds: params.requireMentionInBotThreads ? params.implicitMentionKinds?.filter((kind) => kind === "native") : params.implicitMentionKinds
|
|
3375
|
+
};
|
|
3376
|
+
}
|
|
3377
|
+
//#endregion
|
|
3378
|
+
//#region \0openclaw:bundled-sdk:openclaw/plugin-sdk/channel-mention-gating
|
|
3379
|
+
var channel_mention_gating_exports = /* @__PURE__ */ __exportAll({ resolveBotThreadMentionPolicy: () => resolveBotThreadMentionPolicy });
|
|
3380
|
+
import * as import_openclaw_plugin_sdk_channel_mention_gating from "openclaw/plugin-sdk/channel-mention-gating";
|
|
3381
|
+
__reExport(channel_mention_gating_exports, import_openclaw_plugin_sdk_channel_mention_gating);
|
|
3382
|
+
//#endregion
|
|
3383
|
+
//#region extensions/slack/src/monitor/message-handler/prepare-thread-mentions.ts
|
|
3384
|
+
async function resolveSlackThreadMentionPolicy(params) {
|
|
3385
|
+
const { ctx, account, message, conversation, thread } = params;
|
|
3386
|
+
const { isRoom, isDirectMessage, channelConfig } = conversation;
|
|
3387
|
+
let implicitMentionKinds = [];
|
|
3388
|
+
if (!isDirectMessage && message.thread_ts && !params.wasMentioned) {
|
|
3389
|
+
const replyToBotKinds = (0, channel_mention_gating_exports.implicitMentionKindWhen)("reply_to_bot", Boolean(ctx.botUserId && message.parent_user_id === ctx.botUserId));
|
|
3390
|
+
implicitMentionKinds = replyToBotKinds.length > 0 ? replyToBotKinds : (0, channel_mention_gating_exports.implicitMentionKindWhen)("bot_thread_participant", await hasSlackThreadParticipationWithPersistence({
|
|
3391
|
+
accountId: account.accountId,
|
|
3392
|
+
channelId: message.channel,
|
|
3393
|
+
threadTs: message.thread_ts,
|
|
3394
|
+
teamId: params.teamId
|
|
3395
|
+
}));
|
|
3396
|
+
}
|
|
3397
|
+
const requireMentionInBotThreads = channelConfig?.requireMentionInBotThreads ?? account.config.requireMentionInBotThreads;
|
|
3398
|
+
let isBotOwnedThread = false;
|
|
3399
|
+
if (isRoom && thread.isThreadReply && requireMentionInBotThreads !== void 0) {
|
|
3400
|
+
const parentUserId = normalizeOptionalString(message.parent_user_id);
|
|
3401
|
+
if (parentUserId) isBotOwnedThread = Boolean(ctx.botUserId && parentUserId === ctx.botUserId);
|
|
3402
|
+
else {
|
|
3403
|
+
const starter = await params.getThreadStarter();
|
|
3404
|
+
isBotOwnedThread = Boolean(starter && starter.ts === thread.threadTs && isSlackThreadAuthorCurrentBot({
|
|
3405
|
+
identity: ctx,
|
|
3406
|
+
author: starter
|
|
3407
|
+
}));
|
|
3408
|
+
}
|
|
3409
|
+
}
|
|
3410
|
+
return resolveBotThreadMentionPolicy({
|
|
3411
|
+
isBotOwnedThread,
|
|
3412
|
+
requireMentionInBotThreads,
|
|
3413
|
+
requireMention: isRoom ? channelConfig?.requireMention ?? ctx.defaultRequireMention : false,
|
|
3414
|
+
implicitMentionKinds
|
|
3415
|
+
});
|
|
3416
|
+
}
|
|
3417
|
+
//#endregion
|
|
3313
3418
|
//#region extensions/slack/src/monitor/message-handler/subteam-mentions.ts
|
|
3314
3419
|
const SUBTEAM_MENTION_RE = /<!subteam\^([A-Z0-9]+)(?:\|[^>]*)?>/gi;
|
|
3315
3420
|
const SUBTEAM_MEMBER_CACHE_TTL_MS = 3e5;
|
|
3316
3421
|
const subteamMemberCache = /* @__PURE__ */ new WeakMap();
|
|
3317
3422
|
function normalizeSlackId(value) {
|
|
3318
|
-
return
|
|
3423
|
+
return normalizeOptionalString(value)?.toUpperCase();
|
|
3319
3424
|
}
|
|
3320
3425
|
function extractSlackSubteamMentionIds(text) {
|
|
3321
3426
|
if (!text) return [];
|
|
@@ -3348,7 +3453,7 @@ async function readSlackSubteamUsers(params) {
|
|
|
3348
3453
|
params.log?.(`slack: failed to resolve user-group mention ${params.subteamId}: ${response.error ?? "unknown_error"}`);
|
|
3349
3454
|
return /* @__PURE__ */ new Set();
|
|
3350
3455
|
}
|
|
3351
|
-
const users = new Set((response.users ?? []).map((userId) =>
|
|
3456
|
+
const users = new Set((response.users ?? []).map(normalizeSlackId).filter((userId) => userId !== void 0));
|
|
3352
3457
|
const expiresAt = resolveExpiresAtMsFromDurationMs(SUBTEAM_MEMBER_CACHE_TTL_MS, { nowMs: params.now });
|
|
3353
3458
|
if (expiresAt !== void 0) bySubteam.set(cacheKey, {
|
|
3354
3459
|
expiresAt,
|
|
@@ -3382,10 +3487,6 @@ const SLACK_ANY_MENTION_RE = /<@[^>]+>|<!subteam\^[^>]+>/;
|
|
|
3382
3487
|
const SLACK_USER_MENTION_RE = /<@([^>|]+)(?:\|[^>]+)?>/g;
|
|
3383
3488
|
const SLACK_SUBTEAM_MENTION_RE = /<!subteam\^([^>|]+)(?:\|[^>]+)?>/g;
|
|
3384
3489
|
const SLACK_SUBTEAM_MENTION_MARKER = "<!subteam^";
|
|
3385
|
-
const SLACK_HISTORY_MEDIA_MAX_ATTACHMENTS = 4;
|
|
3386
|
-
const SLACK_HISTORY_MEDIA_MAX_BYTES = 10485760;
|
|
3387
|
-
const SLACK_HISTORY_MEDIA_IDLE_TIMEOUT_MS = 1e3;
|
|
3388
|
-
const SLACK_HISTORY_MEDIA_TOTAL_TIMEOUT_MS = 3e3;
|
|
3389
3490
|
const SLACK_CHANNEL_ACCESS_DOCS_URL = "https://docs.openclaw.ai/channels/slack#access-control-and-routing";
|
|
3390
3491
|
function resolveSlackGroupSessionSubject(params) {
|
|
3391
3492
|
const channelName = normalizeOptionalString(params.channelName);
|
|
@@ -3393,14 +3494,6 @@ function resolveSlackGroupSessionSubject(params) {
|
|
|
3393
3494
|
if (channelName && workspaceName) return `${workspaceName} #${channelName}`;
|
|
3394
3495
|
return `Slack Channel (Workspace ID: ${params.workspaceId}, Channel ID: ${params.channelId})`;
|
|
3395
3496
|
}
|
|
3396
|
-
function recordString(record, key) {
|
|
3397
|
-
return normalizeOptionalString(record?.[key]);
|
|
3398
|
-
}
|
|
3399
|
-
function recordNullableString(record, key) {
|
|
3400
|
-
if (!record || !(key in record)) return;
|
|
3401
|
-
if (record[key] === null) return null;
|
|
3402
|
-
return normalizeOptionalString(record[key]);
|
|
3403
|
-
}
|
|
3404
3497
|
function mergeSlackAssistantThreadContext(primary, fallback) {
|
|
3405
3498
|
if (!primary) return fallback;
|
|
3406
3499
|
if (!fallback) return primary;
|
|
@@ -3420,16 +3513,16 @@ function resolveSlackMessageAssistantThreadContext(message) {
|
|
|
3420
3513
|
const thread = asOptionalRecord(message.assistant_thread);
|
|
3421
3514
|
if (!thread) return;
|
|
3422
3515
|
const context = asOptionalRecord(thread.context);
|
|
3423
|
-
const assistantChannelId =
|
|
3424
|
-
const threadTs =
|
|
3516
|
+
const assistantChannelId = normalizeOptionalString(thread.channel_id) ?? message.channel;
|
|
3517
|
+
const threadTs = normalizeOptionalString(thread.thread_ts) ?? message.thread_ts ?? message.ts;
|
|
3425
3518
|
if (!assistantChannelId || !threadTs) return;
|
|
3426
3519
|
return {
|
|
3427
3520
|
assistantChannelId,
|
|
3428
3521
|
threadTs,
|
|
3429
|
-
userId:
|
|
3430
|
-
channelId:
|
|
3431
|
-
teamId:
|
|
3432
|
-
enterpriseId:
|
|
3522
|
+
userId: normalizeOptionalString(thread.user_id) ?? message.user,
|
|
3523
|
+
channelId: normalizeOptionalString(context?.channel_id),
|
|
3524
|
+
teamId: normalizeOptionalString(context?.team_id),
|
|
3525
|
+
enterpriseId: context?.enterprise_id === null ? null : normalizeOptionalString(context?.enterprise_id)
|
|
3433
3526
|
};
|
|
3434
3527
|
}
|
|
3435
3528
|
async function restoreSlackAssistantThreadContextFromMetadata(params) {
|
|
@@ -3465,61 +3558,6 @@ function resolveCachedMentionRegexes(ctx, agentId, options) {
|
|
|
3465
3558
|
byAgent.set(key, built);
|
|
3466
3559
|
return built;
|
|
3467
3560
|
}
|
|
3468
|
-
function isSlackImageFileCandidate(file) {
|
|
3469
|
-
if ((file.mimetype?.split(";")[0]?.trim().toLowerCase())?.startsWith("image/")) return true;
|
|
3470
|
-
return Boolean(mimeTypeFromFilePath(file.name)?.startsWith("image/"));
|
|
3471
|
-
}
|
|
3472
|
-
function sliceSlackImageFileCandidates(files, limit) {
|
|
3473
|
-
if (limit <= 0 || !files?.length) return [];
|
|
3474
|
-
return files.filter(isSlackImageFileCandidate).slice(0, limit);
|
|
3475
|
-
}
|
|
3476
|
-
function sliceSlackHistoryAttachmentCandidates(attachments, limit) {
|
|
3477
|
-
if (limit <= 0 || !attachments?.length) return [];
|
|
3478
|
-
const out = [];
|
|
3479
|
-
let remaining = limit;
|
|
3480
|
-
for (const attachment of attachments) {
|
|
3481
|
-
if (attachment.is_share !== true) continue;
|
|
3482
|
-
const hasImageUrl = Boolean(normalizeOptionalString(attachment.image_url));
|
|
3483
|
-
const files = sliceSlackImageFileCandidates(attachment.files, remaining - (hasImageUrl ? 1 : 0));
|
|
3484
|
-
if (!hasImageUrl && files.length === 0) continue;
|
|
3485
|
-
out.push({
|
|
3486
|
-
...attachment,
|
|
3487
|
-
files
|
|
3488
|
-
});
|
|
3489
|
-
remaining -= (hasImageUrl ? 1 : 0) + files.length;
|
|
3490
|
-
if (remaining <= 0) break;
|
|
3491
|
-
}
|
|
3492
|
-
return out;
|
|
3493
|
-
}
|
|
3494
|
-
function buildSlackHistoryMediaCandidateMessage(message) {
|
|
3495
|
-
const files = sliceSlackImageFileCandidates(message.files, SLACK_HISTORY_MEDIA_MAX_ATTACHMENTS);
|
|
3496
|
-
const attachments = sliceSlackHistoryAttachmentCandidates(message.attachments, Math.max(0, SLACK_HISTORY_MEDIA_MAX_ATTACHMENTS - files.length));
|
|
3497
|
-
if (files.length === 0 && attachments.length === 0) return null;
|
|
3498
|
-
return {
|
|
3499
|
-
...message,
|
|
3500
|
-
files,
|
|
3501
|
-
attachments
|
|
3502
|
-
};
|
|
3503
|
-
}
|
|
3504
|
-
async function resolveSlackHistoryMediaForPendingRecord(params) {
|
|
3505
|
-
const mediaMessage = buildSlackHistoryMediaCandidateMessage(params.message);
|
|
3506
|
-
if (!mediaMessage) return [];
|
|
3507
|
-
const content = await resolveSlackMessageContent({
|
|
3508
|
-
message: mediaMessage,
|
|
3509
|
-
isThreadReply: params.isThreadReply,
|
|
3510
|
-
threadStarter: params.threadStarter,
|
|
3511
|
-
isBotMessage: params.isBotMessage,
|
|
3512
|
-
client: params.eventScope?.client ?? params.ctx.app.client,
|
|
3513
|
-
botToken: params.ctx.botToken,
|
|
3514
|
-
mediaMaxBytes: Math.min(params.ctx.mediaMaxBytes, SLACK_HISTORY_MEDIA_MAX_BYTES),
|
|
3515
|
-
mediaReadIdleTimeoutMs: SLACK_HISTORY_MEDIA_IDLE_TIMEOUT_MS,
|
|
3516
|
-
mediaTotalTimeoutMs: SLACK_HISTORY_MEDIA_TOTAL_TIMEOUT_MS
|
|
3517
|
-
});
|
|
3518
|
-
return await toInboundMediaFactsWithMetadata(content?.effectiveDirectMedia, {
|
|
3519
|
-
kind: "image",
|
|
3520
|
-
messageId: params.message.ts
|
|
3521
|
-
});
|
|
3522
|
-
}
|
|
3523
3561
|
function collectUniqueSlackMentionIds(text, regex) {
|
|
3524
3562
|
const ids = [];
|
|
3525
3563
|
regex.lastIndex = 0;
|
|
@@ -3566,7 +3604,7 @@ async function resolveSlackConversationContext(params) {
|
|
|
3566
3604
|
const cfg = ctx.cfg;
|
|
3567
3605
|
let channelInfo = {};
|
|
3568
3606
|
let resolvedChannelType = normalizeSlackChannelType(message.channel_type, message.channel);
|
|
3569
|
-
if (resolvedChannelType !== "im" &&
|
|
3607
|
+
if (resolvedChannelType !== "im" && message.channel_type !== "im") {
|
|
3570
3608
|
channelInfo = await ctx.resolveChannelName(message.channel, params.eventScope);
|
|
3571
3609
|
resolvedChannelType = normalizeSlackChannelType(message.channel_type ?? channelInfo.type ?? ctx.recallSlackChannelType(message.channel, params.eventScope), message.channel);
|
|
3572
3610
|
}
|
|
@@ -3585,7 +3623,7 @@ async function resolveSlackConversationContext(params) {
|
|
|
3585
3623
|
defaultRequireMention: ctx.defaultRequireMention,
|
|
3586
3624
|
allowNameMatching: ctx.allowNameMatching
|
|
3587
3625
|
}) : null;
|
|
3588
|
-
const allowBotsSetting = channelConfig?.allowBots ?? account.config?.allowBots ?? cfg.channels?.slack?.allowBots ??
|
|
3626
|
+
const allowBotsSetting = channelConfig?.allowBots ?? account.config?.allowBots ?? cfg.channels?.slack?.allowBots ?? true;
|
|
3589
3627
|
return {
|
|
3590
3628
|
channelInfo,
|
|
3591
3629
|
channelName,
|
|
@@ -3603,7 +3641,7 @@ async function authorizeSlackInboundMessage(params) {
|
|
|
3603
3641
|
const { ctx, account, message, conversation, drop } = params;
|
|
3604
3642
|
const { isDirectMessage, channelName, resolvedChannelType, isBotMessage, allowBotsMode } = conversation;
|
|
3605
3643
|
if (isBotMessage) {
|
|
3606
|
-
if (message.user
|
|
3644
|
+
if (ctx.botUserId && message.user === ctx.botUserId || ctx.botId && message.bot_id === ctx.botId) return null;
|
|
3607
3645
|
if (allowBotsMode === "off") return drop("bot-disabled");
|
|
3608
3646
|
}
|
|
3609
3647
|
if (isDirectMessage && !message.user) return drop("missing-user");
|
|
@@ -3752,20 +3790,21 @@ async function prepareSlackMessage(params) {
|
|
|
3752
3790
|
eventScope: opts.eventScope
|
|
3753
3791
|
});
|
|
3754
3792
|
const channelRequireMention = channelConfig?.requireMention ?? ctx.defaultRequireMention ?? true;
|
|
3755
|
-
const
|
|
3793
|
+
const chatType = resolveSlackChatType(conversation.resolvedChannelType);
|
|
3756
3794
|
const restoredAssistantThreadContext = await restoredAssistantThreadContextPromise;
|
|
3757
3795
|
const assistantThreadContext = mergeSlackAssistantThreadContext(messageAssistantThreadContext, cachedAssistantThreadContext ?? restoredAssistantThreadContext);
|
|
3758
3796
|
const assistantThreadContextToCache = messageAssistantThreadContext || restoredAssistantThreadContext ? assistantThreadContext : void 0;
|
|
3759
3797
|
if (assistantThreadContextToCache) ctx.saveSlackAssistantThreadContext(assistantThreadContextToCache, opts.eventScope);
|
|
3760
|
-
const
|
|
3798
|
+
const canUseManagedView = isDirectMessage && !opts.eventScope && !assistantThreadContext;
|
|
3799
|
+
const hasAgentViewMessageSignal = canUseManagedView && isSlackAppContext(message.app_context);
|
|
3761
3800
|
if (hasAgentViewMessageSignal) await ctx.recordSlackAgentView();
|
|
3762
3801
|
const managedViewThreadTs = message.thread_ts;
|
|
3763
|
-
const isManagedViewRoot =
|
|
3802
|
+
const isManagedViewRoot = canUseManagedView && !message.parent_user_id && Boolean(managedViewThreadTs && message.ts && managedViewThreadTs === message.ts);
|
|
3764
3803
|
if (isManagedViewRoot && managedViewThreadTs) await ctx.recordSlackManagedViewThread(message.channel, managedViewThreadTs);
|
|
3765
|
-
const hasManagedViewThread =
|
|
3766
|
-
const isAgentViewMessage =
|
|
3804
|
+
const hasManagedViewThread = canUseManagedView && Boolean(managedViewThreadTs && await ctx.isSlackManagedViewThread(message.channel, managedViewThreadTs));
|
|
3805
|
+
const isAgentViewMessage = canUseManagedView && (hasAgentViewMessageSignal || isManagedViewRoot || hasManagedViewThread || await ctx.isSlackAgentView());
|
|
3767
3806
|
const agentViewThreadTs = isAgentViewMessage ? message.thread_ts ?? message.ts : void 0;
|
|
3768
|
-
const channelReplyToMode = channelConfig?.replyToMode ?? resolveSlackReplyToMode(account,
|
|
3807
|
+
const channelReplyToMode = channelConfig?.replyToMode ?? resolveSlackReplyToMode(account, chatType);
|
|
3769
3808
|
const willImplicitlyThreadReply = isRoom && !channelRequireMention && channelReplyToMode !== "off";
|
|
3770
3809
|
const seedTopLevelRoomThreadBySource = opts.source === "app_mention" || opts.wasMentioned === true || explicitlyMentioned || willImplicitlyThreadReply;
|
|
3771
3810
|
const resolveMessageRouting = (seedTopLevelRoomThread) => resolveSlackRoutingContext({
|
|
@@ -3820,7 +3859,7 @@ async function prepareSlackMessage(params) {
|
|
|
3820
3859
|
let mentionRegexes = buildPolicyMentionRegexes(routing.route.agentId);
|
|
3821
3860
|
let wasMentioned = resolveWasMentioned(mentionRegexes);
|
|
3822
3861
|
const hasBoundSession = Boolean(routing.runtimeBoundSessionKey || routing.configuredBindingSessionKey);
|
|
3823
|
-
let { route, runtimeBinding, replyToMode, threadContext, threadTs, isThreadReply, threadKeys, sessionKey
|
|
3862
|
+
let { route, runtimeBinding, replyToMode, threadContext, threadTs, isThreadReply, threadKeys, sessionKey } = routing;
|
|
3824
3863
|
const { configuredBinding, configuredBindingSessionKey } = routing;
|
|
3825
3864
|
const isAssistantThreadMessage = Boolean(isDirectMessage && messageAssistantThreadContext);
|
|
3826
3865
|
const forcedAssistantReplyThreadTs = Boolean(assistantThreadContext?.threadTs && (isThreadReply || isAssistantThreadMessage || replyToMode !== "off")) ? assistantThreadContext?.threadTs : void 0;
|
|
@@ -3848,75 +3887,14 @@ async function prepareSlackMessage(params) {
|
|
|
3848
3887
|
ok: true,
|
|
3849
3888
|
name: void 0
|
|
3850
3889
|
});
|
|
3851
|
-
let implicitMentionKinds = [];
|
|
3852
|
-
if (!isDirectMessage && message.thread_ts && !wasMentioned) {
|
|
3853
|
-
const replyToBotKinds = implicitMentionKindWhen("reply_to_bot", Boolean(ctx.botUserId && message.parent_user_id === ctx.botUserId));
|
|
3854
|
-
implicitMentionKinds = replyToBotKinds.length > 0 ? replyToBotKinds : implicitMentionKindWhen("bot_thread_participant", await hasSlackThreadParticipationWithPersistence({
|
|
3855
|
-
accountId: account.accountId,
|
|
3856
|
-
channelId: message.channel,
|
|
3857
|
-
threadTs: message.thread_ts,
|
|
3858
|
-
teamId: opts.eventScope?.teamId
|
|
3859
|
-
}));
|
|
3860
|
-
}
|
|
3861
|
-
const recordDroppedHistory = async (reason) => {
|
|
3862
|
-
const pendingText = (message.text ?? "").trim();
|
|
3863
|
-
const historyMediaCandidate = buildSlackHistoryMediaCandidateMessage(message);
|
|
3864
|
-
const fallbackFile = message.files?.length ? `[Slack file: ${formatSlackFileReference(message.files[0])}]` : "";
|
|
3865
|
-
const pendingBody = pendingText || fallbackFile || (!fallbackFile && historyMediaCandidate ? "[Slack media attachment]" : "");
|
|
3866
|
-
const skippedThreadStarter = historyMediaCandidate && isThreadReply && threadTs ? await resolveSlackThreadStarter({
|
|
3867
|
-
channelId: message.channel,
|
|
3868
|
-
threadTs,
|
|
3869
|
-
client: slackClient,
|
|
3870
|
-
workspaceScope: threadStarterWorkspaceScope
|
|
3871
|
-
}) : null;
|
|
3872
|
-
const senderName = pendingBody ? await resolveSenderName() : void 0;
|
|
3873
|
-
await recordDroppedChannelInboundHistory({
|
|
3874
|
-
input: {
|
|
3875
|
-
id: message.ts ?? `${message.channel}:${Date.now()}`,
|
|
3876
|
-
timestamp: resolveSlackTimestampMs(message.ts),
|
|
3877
|
-
rawText: pendingBody,
|
|
3878
|
-
textForAgent: pendingBody,
|
|
3879
|
-
raw: message
|
|
3880
|
-
},
|
|
3881
|
-
admission: {
|
|
3882
|
-
kind: "drop",
|
|
3883
|
-
reason,
|
|
3884
|
-
recordHistory: true
|
|
3885
|
-
},
|
|
3886
|
-
preflight: {
|
|
3887
|
-
message: pendingBody ? {
|
|
3888
|
-
rawBody: pendingBody,
|
|
3889
|
-
body: pendingBody,
|
|
3890
|
-
bodyForAgent: pendingBody,
|
|
3891
|
-
senderLabel: senderName,
|
|
3892
|
-
envelopeFrom: senderName
|
|
3893
|
-
} : void 0,
|
|
3894
|
-
history: {
|
|
3895
|
-
key: historyKey,
|
|
3896
|
-
historyMap: ctx.channelHistories,
|
|
3897
|
-
limit: ctx.historyLimit,
|
|
3898
|
-
recordOnDrop: true,
|
|
3899
|
-
mediaLimit: SLACK_HISTORY_MEDIA_MAX_ATTACHMENTS,
|
|
3900
|
-
shouldRecord: opts.shouldRecordDroppedHistory
|
|
3901
|
-
},
|
|
3902
|
-
media: () => resolveSlackHistoryMediaForPendingRecord({
|
|
3903
|
-
ctx,
|
|
3904
|
-
message,
|
|
3905
|
-
isThreadReply,
|
|
3906
|
-
threadStarter: skippedThreadStarter,
|
|
3907
|
-
isBotMessage,
|
|
3908
|
-
eventScope: opts.eventScope
|
|
3909
|
-
})
|
|
3910
|
-
}
|
|
3911
|
-
});
|
|
3912
|
-
};
|
|
3913
3890
|
let threadStarterPromise;
|
|
3914
3891
|
const getThreadStarter = () => {
|
|
3915
3892
|
threadStarterPromise ??= isThreadReply && threadTs ? resolveSlackThreadStarter({
|
|
3916
3893
|
channelId: message.channel,
|
|
3917
3894
|
threadTs,
|
|
3918
3895
|
client: slackClient,
|
|
3919
|
-
workspaceScope: threadStarterWorkspaceScope
|
|
3896
|
+
workspaceScope: threadStarterWorkspaceScope,
|
|
3897
|
+
refresh: isRoomish && ctx.historyLimit > 0
|
|
3920
3898
|
}) : Promise.resolve(null);
|
|
3921
3899
|
return threadStarterPromise;
|
|
3922
3900
|
};
|
|
@@ -3944,7 +3922,18 @@ async function prepareSlackMessage(params) {
|
|
|
3944
3922
|
cfg,
|
|
3945
3923
|
surface: "slack"
|
|
3946
3924
|
});
|
|
3947
|
-
const
|
|
3925
|
+
const { requireMention: shouldRequireMention, implicitMentionKinds } = await resolveSlackThreadMentionPolicy({
|
|
3926
|
+
ctx,
|
|
3927
|
+
account,
|
|
3928
|
+
message,
|
|
3929
|
+
conversation,
|
|
3930
|
+
thread: routing,
|
|
3931
|
+
wasMentioned,
|
|
3932
|
+
teamId: opts.eventScope?.teamId,
|
|
3933
|
+
getThreadStarter
|
|
3934
|
+
});
|
|
3935
|
+
opts.abortSignal?.throwIfAborted();
|
|
3936
|
+
if (opts.isRuntimePolicyCurrent?.() === false) return drop("final-route-denied");
|
|
3948
3937
|
const implicitMentions = resolveChannelImplicitMentions({
|
|
3949
3938
|
cfg,
|
|
3950
3939
|
channel: "slack",
|
|
@@ -3960,6 +3949,7 @@ async function prepareSlackMessage(params) {
|
|
|
3960
3949
|
ctx,
|
|
3961
3950
|
teamId: opts.eventScope?.teamId ?? ctx.teamId,
|
|
3962
3951
|
senderId,
|
|
3952
|
+
senderAuthentication: message.user ? opts.senderAuthentication : void 0,
|
|
3963
3953
|
senderName: senderNameForAuth,
|
|
3964
3954
|
channelType: conversation.resolvedChannelType ?? "channel",
|
|
3965
3955
|
channelId: message.channel,
|
|
@@ -3993,7 +3983,7 @@ async function prepareSlackMessage(params) {
|
|
|
3993
3983
|
allowFromLower,
|
|
3994
3984
|
eventScope: opts.eventScope
|
|
3995
3985
|
})) return drop("unauthorized-bot");
|
|
3996
|
-
const threadContextAllowFromLower = isRoom ? channelUsersAllowlistConfigured ?
|
|
3986
|
+
const threadContextAllowFromLower = isRoom ? channelUsersAllowlistConfigured ? normalizeStringEntriesLower(channelConfig?.users) : [] : isDirectMessage ? allowFromLower : [];
|
|
3997
3987
|
const contextVisibilityMode = resolveChannelContextVisibilityMode({
|
|
3998
3988
|
cfg: ctx.cfg,
|
|
3999
3989
|
channel: "slack",
|
|
@@ -4067,7 +4057,7 @@ async function prepareSlackMessage(params) {
|
|
|
4067
4057
|
})) groupThread = void 0;
|
|
4068
4058
|
mentionRegexes = buildPolicyMentionRegexes(routing.route.agentId);
|
|
4069
4059
|
wasMentioned = resolveWasMentioned(mentionRegexes);
|
|
4070
|
-
({route, runtimeBinding, replyToMode, threadContext, threadTs, isThreadReply, threadKeys, sessionKey
|
|
4060
|
+
({route, runtimeBinding, replyToMode, threadContext, threadTs, isThreadReply, threadKeys, sessionKey} = routing);
|
|
4071
4061
|
canDetectMention = Boolean(groupThread) || Boolean(ctx.botUserId) || mentionRegexes.length > 0;
|
|
4072
4062
|
}
|
|
4073
4063
|
if (preflightAudioTranscript && !wasMentioned) {
|
|
@@ -4106,20 +4096,10 @@ async function prepareSlackMessage(params) {
|
|
|
4106
4096
|
if (isBotMessage && allowBotsMode === "mentions") {
|
|
4107
4097
|
if (!(isDirectMessage || effectiveWasMentioned || shouldBypassMention)) return drop("bot-missing-mention");
|
|
4108
4098
|
}
|
|
4109
|
-
if (isRoom && shouldRequireMention && !canDetectMention && !effectiveWasMentioned)
|
|
4110
|
-
await recordDroppedHistory("slack-mention-detection-unavailable");
|
|
4111
|
-
return drop("mention-detection-unavailable");
|
|
4112
|
-
}
|
|
4099
|
+
if (isRoom && shouldRequireMention && !canDetectMention && !effectiveWasMentioned) return drop("mention-detection-unavailable");
|
|
4113
4100
|
const ignoreOtherMentions = channelConfig?.ignoreOtherMentions ?? false;
|
|
4114
|
-
if (isRoom && ignoreOtherMentions && Boolean(ctx.botUserId) && hasAnyMention && !wasMentioned)
|
|
4115
|
-
|
|
4116
|
-
return drop("other-mention");
|
|
4117
|
-
}
|
|
4118
|
-
if (isRoom && shouldRequireMention && mentionDecision.shouldSkip) {
|
|
4119
|
-
await recordDroppedHistory("slack-no-mention");
|
|
4120
|
-
return drop("missing-mention");
|
|
4121
|
-
}
|
|
4122
|
-
const chatType = resolveSlackChatType(conversation.resolvedChannelType);
|
|
4101
|
+
if (isRoom && ignoreOtherMentions && Boolean(ctx.botUserId) && hasAnyMention && !wasMentioned) return drop("other-mention");
|
|
4102
|
+
if (isRoom && shouldRequireMention && mentionDecision.shouldSkip) return drop("missing-mention");
|
|
4123
4103
|
const inboundEventKind = classifyChannelInboundEvent({
|
|
4124
4104
|
conversation: { kind: chatType },
|
|
4125
4105
|
unmentionedGroupPolicy: resolveUnmentionedGroupInboundPolicy({
|
|
@@ -4132,6 +4112,8 @@ async function prepareSlackMessage(params) {
|
|
|
4132
4112
|
});
|
|
4133
4113
|
const threadStarter = await getThreadStarter();
|
|
4134
4114
|
const resolvedMessageContent = await getMessageContent();
|
|
4115
|
+
opts.abortSignal?.throwIfAborted();
|
|
4116
|
+
if (opts.isRuntimePolicyCurrent?.() === false) return drop("final-route-denied");
|
|
4135
4117
|
if (!resolvedMessageContent) return drop("empty-content");
|
|
4136
4118
|
const { rawBody, effectiveDirectMedia, commandSourceText, mentionStripPatterns } = resolvedMessageContent;
|
|
4137
4119
|
const bodyForAgent = preflightAudioTranscript ? formatSlackAudioTranscriptForAgent({
|
|
@@ -4152,7 +4134,7 @@ async function prepareSlackMessage(params) {
|
|
|
4152
4134
|
}) === "message_tool_only";
|
|
4153
4135
|
const statusReactionsExplicitlyEnabled = cfg.messages?.statusReactions?.enabled === true;
|
|
4154
4136
|
const isRoomEvent = inboundEventKind === "room_event";
|
|
4155
|
-
const shouldAckReaction$1 =
|
|
4137
|
+
const shouldAckReaction$1 = Boolean(ackReaction && shouldAckReaction({
|
|
4156
4138
|
scope: cfg.messages?.ackReactionScope,
|
|
4157
4139
|
inboundEventKind,
|
|
4158
4140
|
isDirect: isDirectMessage,
|
|
@@ -4163,7 +4145,7 @@ async function prepareSlackMessage(params) {
|
|
|
4163
4145
|
shouldBypassMention
|
|
4164
4146
|
}));
|
|
4165
4147
|
const ackReactionMessageTs = message.ts;
|
|
4166
|
-
const shouldSendAckReaction = shouldAckReaction$1
|
|
4148
|
+
const shouldSendAckReaction = shouldAckReaction$1 && (!sourceRepliesAreToolOnly || effectiveWasMentioned || shouldBypassMention || isRoomEvent);
|
|
4167
4149
|
const statusReactionsWillHandle = Boolean(ackReactionMessageTs) && !isRoomEvent && statusReactionsExplicitlyEnabled && shouldSendAckReaction;
|
|
4168
4150
|
const ackReactionPromise = !statusReactionsWillHandle && shouldSendAckReaction && ackReactionMessageTs && ackReactionValue ? reactSlackMessage(message.channel, ackReactionMessageTs, ackReactionValue, {
|
|
4169
4151
|
token: ctx.botToken,
|
|
@@ -4200,16 +4182,34 @@ async function prepareSlackMessage(params) {
|
|
|
4200
4182
|
const textWithId = `${bodyForAgent}\n[slack message id: ${message.ts} channel: ${message.channel}${threadInfo}]`;
|
|
4201
4183
|
const storePath = resolveStorePath(ctx.cfg.session?.store, { agentId: route.agentId });
|
|
4202
4184
|
const envelopeOptions = resolveEnvelopeFormatOptions(ctx.cfg);
|
|
4185
|
+
const effectiveMessageThreadId = assistantThreadContext?.threadTs ?? agentViewThreadTs ?? threadContext.messageThreadId;
|
|
4186
|
+
const boundMessageThreadId = directThreadRoutedToDmSession ? void 0 : effectiveMessageThreadId;
|
|
4187
|
+
messageIngress = await resolveMessageIngress({
|
|
4188
|
+
agentId: route.agentId,
|
|
4189
|
+
sessionKey,
|
|
4190
|
+
nativeChannelId: message.channel,
|
|
4191
|
+
messageId: threadContext.messageTs,
|
|
4192
|
+
inboundEventKind
|
|
4193
|
+
}, boundMessageThreadId);
|
|
4194
|
+
if (messageIngress.ingress.admission !== "dispatch") return drop("final-route-denied");
|
|
4203
4195
|
const sessionEntry = getSessionEntry({
|
|
4204
4196
|
storePath,
|
|
4205
4197
|
sessionKey
|
|
4206
4198
|
});
|
|
4207
4199
|
const previousTimestamp = sessionEntry?.updatedAt;
|
|
4208
|
-
|
|
4209
|
-
|
|
4210
|
-
|
|
4211
|
-
|
|
4212
|
-
|
|
4200
|
+
const excludedMessageIds = new Set(opts.sourceMessageIds);
|
|
4201
|
+
if (message.ts) excludedMessageIds.add(message.ts);
|
|
4202
|
+
const isHistorySessionCurrent = () => {
|
|
4203
|
+
const current = getSessionEntry({
|
|
4204
|
+
storePath,
|
|
4205
|
+
sessionKey
|
|
4206
|
+
});
|
|
4207
|
+
return current?.sessionId === sessionEntry?.sessionId && current?.lifecycleRevision === sessionEntry?.lifecycleRevision && current?.sessionStartedAt === sessionEntry?.sessionStartedAt && current?.updatedAt === 0 === (sessionEntry?.updatedAt === 0);
|
|
4208
|
+
};
|
|
4209
|
+
const assertHistoryCurrent = () => {
|
|
4210
|
+
opts.abortSignal?.throwIfAborted();
|
|
4211
|
+
if (opts.isRuntimePolicyCurrent?.() === false || !isHistorySessionCurrent()) throw new Error("Slack history policy or session changed during recovery");
|
|
4212
|
+
};
|
|
4213
4213
|
const dmHistoryLimit = isDirectMessage ? resolveSlackDmHistoryLimit({
|
|
4214
4214
|
account,
|
|
4215
4215
|
userId: message.user,
|
|
@@ -4240,26 +4240,12 @@ async function prepareSlackMessage(params) {
|
|
|
4240
4240
|
inboundHistory: void 0
|
|
4241
4241
|
};
|
|
4242
4242
|
if (dmHistoryContext.body) combinedBody = `${dmHistoryContext.body}\n\n${combinedBody}`;
|
|
4243
|
-
if (isRoomish && ctx.historyLimit > 0) combinedBody = channelHistory.buildPendingContext({
|
|
4244
|
-
historyKey,
|
|
4245
|
-
limit: ctx.historyLimit,
|
|
4246
|
-
currentMessage: combinedBody,
|
|
4247
|
-
formatEntry: (entry) => formatInboundEnvelope({
|
|
4248
|
-
channel: "Slack",
|
|
4249
|
-
from: roomLabel,
|
|
4250
|
-
timestamp: entry.timestamp,
|
|
4251
|
-
body: `${entry.body}${entry.messageId ? ` [id:${entry.messageId} channel:${message.channel}]` : ""}`,
|
|
4252
|
-
chatType: "channel",
|
|
4253
|
-
senderLabel: entry.sender,
|
|
4254
|
-
envelope: envelopeOptions
|
|
4255
|
-
})
|
|
4256
|
-
});
|
|
4257
4243
|
const { channelMetadata, groupSystemPrompt } = resolveSlackRoomContextHints({
|
|
4258
4244
|
isRoomish,
|
|
4259
4245
|
channelInfo,
|
|
4260
4246
|
channelConfig
|
|
4261
4247
|
});
|
|
4262
|
-
const
|
|
4248
|
+
const threadContextData = await resolveSlackThreadContextData({
|
|
4263
4249
|
ctx,
|
|
4264
4250
|
agentId: route.agentId,
|
|
4265
4251
|
account,
|
|
@@ -4277,25 +4263,64 @@ async function prepareSlackMessage(params) {
|
|
|
4277
4263
|
contextVisibilityMode,
|
|
4278
4264
|
envelopeOptions,
|
|
4279
4265
|
effectiveDirectMedia,
|
|
4280
|
-
eventScope: opts.eventScope
|
|
4266
|
+
eventScope: opts.eventScope,
|
|
4267
|
+
historyLimit: isRoomish ? ctx.historyLimit : void 0,
|
|
4268
|
+
excludedMessageIds,
|
|
4269
|
+
assertHistoryCurrent,
|
|
4270
|
+
abortSignal: opts.abortSignal
|
|
4271
|
+
});
|
|
4272
|
+
const { threadLabel, threadStarterMedia } = threadContextData;
|
|
4273
|
+
let { threadStarterBody, threadHistoryBody, shouldSeedInitialThreadContext } = threadContextData;
|
|
4274
|
+
const threadScopedHistory = isThreadReply && ctx.threadHistoryScope === "thread";
|
|
4275
|
+
let roomHistory = [];
|
|
4276
|
+
if (isRoomish && ctx.historyLimit > 0 && (!threadScopedHistory || !shouldSeedInitialThreadContext) && sessionEntry?.updatedAt !== 0) roomHistory = await resolveSlackRoomHistory({
|
|
4277
|
+
ctx,
|
|
4278
|
+
message,
|
|
4279
|
+
threadTs: threadScopedHistory ? threadTs : void 0,
|
|
4280
|
+
oldest: sessionEntry?.sessionStartedAt ? (sessionEntry.sessionStartedAt / 1e3).toFixed(6) : void 0,
|
|
4281
|
+
excludedMessageIds,
|
|
4282
|
+
allowFromLower: threadContextAllowFromLower,
|
|
4283
|
+
contextVisibilityMode,
|
|
4284
|
+
eventScope: opts.eventScope,
|
|
4285
|
+
assertCurrent: assertHistoryCurrent,
|
|
4286
|
+
abortSignal: opts.abortSignal
|
|
4281
4287
|
});
|
|
4282
4288
|
const effectiveMedia = effectiveDirectMedia ?? threadStarterMedia;
|
|
4283
|
-
|
|
4284
|
-
|
|
4285
|
-
|
|
4289
|
+
let inboundMedia = await toInboundMediaFactsWithMetadata(effectiveMedia, { transcribed: (entry) => effectiveMedia === effectiveDirectMedia && entry === preflightAudioMedia });
|
|
4290
|
+
opts.abortSignal?.throwIfAborted();
|
|
4291
|
+
if (opts.isRuntimePolicyCurrent?.() === false) return drop("final-route-denied");
|
|
4292
|
+
if (isRoomish && ctx.historyLimit > 0 && !isHistorySessionCurrent()) {
|
|
4293
|
+
roomHistory = [];
|
|
4294
|
+
threadHistoryBody = void 0;
|
|
4295
|
+
threadStarterBody = void 0;
|
|
4296
|
+
shouldSeedInitialThreadContext = false;
|
|
4297
|
+
if (effectiveMedia === threadStarterMedia) inboundMedia = [];
|
|
4298
|
+
ctx.logger.warn({
|
|
4299
|
+
channelId: message.channel,
|
|
4300
|
+
sessionKey
|
|
4301
|
+
}, "Slack automatic history omitted after session changed");
|
|
4302
|
+
}
|
|
4303
|
+
combinedBody = buildHistoryContextFromEntries({
|
|
4304
|
+
entries: roomHistory,
|
|
4305
|
+
currentMessage: combinedBody,
|
|
4306
|
+
historyKind: "recent",
|
|
4307
|
+
excludeLast: false,
|
|
4308
|
+
formatEntry: (entry) => formatInboundEnvelope({
|
|
4309
|
+
channel: "Slack",
|
|
4310
|
+
from: roomLabel,
|
|
4311
|
+
timestamp: entry.timestamp,
|
|
4312
|
+
body: `${entry.body} [id:${entry.messageId} channel:${message.channel}]`,
|
|
4313
|
+
chatType: "channel",
|
|
4314
|
+
senderLabel: entry.sender,
|
|
4315
|
+
envelope: envelopeOptions
|
|
4316
|
+
})
|
|
4317
|
+
});
|
|
4318
|
+
const inboundHistory = isRoomish && ctx.historyLimit > 0 ? buildInboundHistoryFromEntries({
|
|
4319
|
+
entries: roomHistory,
|
|
4286
4320
|
limit: ctx.historyLimit
|
|
4287
4321
|
}) : dmHistoryContext.inboundHistory;
|
|
4288
4322
|
const commandBody = textForCommandDetection.trim();
|
|
4289
4323
|
const supplementalThreadHistoryBody = directThreadRoutedToDmSession && !threadHistoryBody ? threadStarterBody : threadHistoryBody;
|
|
4290
|
-
const effectiveMessageThreadId = assistantThreadContext?.threadTs ?? agentViewThreadTs ?? threadContext.messageThreadId;
|
|
4291
|
-
const boundMessageThreadId = directThreadRoutedToDmSession ? void 0 : effectiveMessageThreadId;
|
|
4292
|
-
messageIngress = await resolveMessageIngress({
|
|
4293
|
-
agentId: route.agentId,
|
|
4294
|
-
sessionKey,
|
|
4295
|
-
messageId: threadContext.messageTs,
|
|
4296
|
-
inboundEventKind
|
|
4297
|
-
}, boundMessageThreadId);
|
|
4298
|
-
if (messageIngress.ingress.admission !== "dispatch") return drop("final-route-denied");
|
|
4299
4324
|
const agentContextEntities = isAgentViewMessage ? normalizeSlackAppContextEntities(message.app_context) : [];
|
|
4300
4325
|
const ctxPayload = (ctx.buildContext ?? buildChannelInboundEventContext)({
|
|
4301
4326
|
channelIngress: messageIngress,
|
|
@@ -4328,9 +4353,7 @@ async function prepareSlackMessage(params) {
|
|
|
4328
4353
|
avatar: conversationAvatar
|
|
4329
4354
|
},
|
|
4330
4355
|
route: {
|
|
4331
|
-
|
|
4332
|
-
dmScope: route.dmScope,
|
|
4333
|
-
accountId: route.accountId,
|
|
4356
|
+
...route,
|
|
4334
4357
|
routeSessionKey: route.sessionKey,
|
|
4335
4358
|
dispatchSessionKey: sessionKey,
|
|
4336
4359
|
parentSessionKey: threadKeys.parentSessionKey
|
|
@@ -4349,7 +4372,10 @@ async function prepareSlackMessage(params) {
|
|
|
4349
4372
|
commandBody,
|
|
4350
4373
|
inboundHistory
|
|
4351
4374
|
},
|
|
4352
|
-
sessionTranscript: {
|
|
4375
|
+
sessionTranscript: {
|
|
4376
|
+
historyLimit: isRoomish ? ctx.historyLimit : dmHistoryLimit,
|
|
4377
|
+
historyKind: isRoomish ? "recent" : "pending"
|
|
4378
|
+
},
|
|
4353
4379
|
access: {
|
|
4354
4380
|
mentions: {
|
|
4355
4381
|
canDetectMention: isRoomish,
|
|
@@ -4404,16 +4430,6 @@ async function prepareSlackMessage(params) {
|
|
|
4404
4430
|
}
|
|
4405
4431
|
});
|
|
4406
4432
|
ctxPayload.ReplyToMode = replyToMode;
|
|
4407
|
-
if (isRoomish && !shouldRequireMention) channelHistory.record({
|
|
4408
|
-
historyKey,
|
|
4409
|
-
limit: ctx.historyLimit,
|
|
4410
|
-
entry: {
|
|
4411
|
-
sender: senderName,
|
|
4412
|
-
body: rawBody,
|
|
4413
|
-
timestamp: resolveSlackTimestampMs(message.ts),
|
|
4414
|
-
messageId: message.ts
|
|
4415
|
-
}
|
|
4416
|
-
});
|
|
4417
4433
|
const pinnedMainDmOwner = isDirectMessage ? resolvePinnedMainDmOwnerFromAllowlist({
|
|
4418
4434
|
dmScope: cfg.session?.dmScope,
|
|
4419
4435
|
allowFrom: allowFromLower,
|
|
@@ -4467,13 +4483,7 @@ async function prepareSlackMessage(params) {
|
|
|
4467
4483
|
sessionKey
|
|
4468
4484
|
}, "failed updating session meta");
|
|
4469
4485
|
}
|
|
4470
|
-
}
|
|
4471
|
-
history: isRoomish && shouldRequireMention ? {
|
|
4472
|
-
isGroup: true,
|
|
4473
|
-
historyKey,
|
|
4474
|
-
historyMap: ctx.channelHistories,
|
|
4475
|
-
limit: ctx.historyLimit
|
|
4476
|
-
} : void 0
|
|
4486
|
+
}
|
|
4477
4487
|
},
|
|
4478
4488
|
replyToMode,
|
|
4479
4489
|
...forcedReplyThreadTs ? { forcedReplyThreadTs } : {},
|
|
@@ -4481,7 +4491,6 @@ async function prepareSlackMessage(params) {
|
|
|
4481
4491
|
requireMention: shouldRequireMention,
|
|
4482
4492
|
isDirectMessage,
|
|
4483
4493
|
isRoomish,
|
|
4484
|
-
historyKey,
|
|
4485
4494
|
preview,
|
|
4486
4495
|
ackReactionMessageTs,
|
|
4487
4496
|
ackReactionValue,
|