@openclaw/slack 2026.9.5 → 2026.9.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/.setup/{account-inspect-B86OaUEt.mjs → account-inspect-DP1Bcwj4.mjs} +1 -1
- package/dist/.setup/{accounts-C1FspRF-.mjs → accounts-BBHvg0pY.mjs} +11 -10
- package/dist/.setup/accounts.runtime-DN-PPocC.mjs +2 -0
- package/dist/.setup/{action-runtime-Aa-h24Fq.mjs → action-runtime-B01d85zt.mjs} +25 -29
- package/dist/.setup/action-runtime.runtime-C8R8CUan.mjs +2 -0
- package/dist/.setup/{actions-BvGUGk3w.mjs → actions-DKCtBgCI.mjs} +80 -49
- package/dist/.setup/{approval-handler.runtime-BcZNF-VP.mjs → approval-handler.runtime-DMszKn_7.mjs} +5 -5
- package/dist/.setup/{approval-message-updates-Cy1cxfBn.mjs → approval-message-updates-Tb_qRokK.mjs} +2 -2
- package/dist/.setup/{channel-DrBm0NFw.mjs → channel-CErYZ5zw.mjs} +33 -29
- package/dist/.setup/{channel-type-osC0XOES.mjs → channel-type-Dxk8VJUb.mjs} +3 -3
- package/dist/.setup/{channel.setup-BSY5hzVz.mjs → channel.setup-BVoUtdPn.mjs} +4 -4
- package/dist/.setup/{config-schema-DrY3S7Ee.mjs → config-schema-CyL279e7.mjs} +8 -0
- package/dist/.setup/{directory-config-CTs7YyuU.mjs → directory-config-CQTSH45W.mjs} +1 -1
- package/dist/.setup/{directory-live-Btq0063Q.mjs → directory-live-BCcj89QV.mjs} +2 -2
- package/dist/.setup/{message-tool-api-DRnDCVdY.mjs → message-tool-api-C0PTFaNV.mjs} +2 -2
- package/dist/.setup/{monitor-Dw5uuKWM.mjs → monitor-_Sht7Dqy.mjs} +3 -3
- package/dist/.setup/{outbound-adapter-K3Ek1iSR.mjs → outbound-adapter-A7Wdn8ZT.mjs} +4 -4
- package/dist/.setup/{pipeline.runtime-BZqGcbfi.mjs → pipeline.runtime-BlPOexmJ.mjs} +642 -487
- package/dist/.setup/{policy-Db_QWCZZ.mjs → policy-BApW53pI.mjs} +2 -2
- package/dist/.setup/{probe-64C6k3_Q.mjs → probe-DiYIMPJo.mjs} +1 -1
- package/dist/.setup/{provider-w36VTgZ3.mjs → provider-C-jPaGt2.mjs} +26 -27
- package/dist/.setup/{relay-source-CDqY76Vp.mjs → relay-source-DfOnjJTE.mjs} +1 -1
- package/dist/.setup/{replies-CWFhjS9S.mjs → replies-BBAJxUOQ.mjs} +4 -4
- package/dist/.setup/{reply-blocks-9uCeAJts.mjs → reply-blocks-Bm8kf6mK.mjs} +1 -1
- package/dist/.setup/{resolve-channels-x8fX1SEt.mjs → resolve-channels-BXbMBbJD.mjs} +1 -1
- package/dist/.setup/{resolve-users-B8BpBnH2.mjs → resolve-users-65WqvIqD.mjs} +1 -1
- package/dist/.setup/{scopes-CJ-6l4v4.mjs → scopes-h3YB-mMs.mjs} +1 -1
- package/dist/.setup/{send-6GCb3lBP.mjs → send-Cp6omkOg.mjs} +21 -31
- package/dist/.setup/{send.runtime-BmqRP-WG.mjs → send.runtime-B4caZU6T.mjs} +1 -1
- package/dist/.setup/{session-status-BhG6pdiH.mjs → session-status-Cf7AvWOt.mjs} +11 -15
- package/dist/.setup/{setup-plugin-api-DtCEByQB.mjs → setup-plugin-api-dLPkL06L.mjs} +1 -1
- package/dist/.setup/{setup-surface-DsE0hsYY.mjs → setup-surface-D3DLcCxu.mjs} +6 -6
- package/dist/.setup/{shared-BNmqCPgQ.mjs → shared-CJ3arAFL.mjs} +4 -4
- package/dist/.setup/{slash-dispatch.runtime-Io4ASZsY.mjs → slash-dispatch.runtime-HFy_XvyO.mjs} +1 -1
- package/dist/account-inspect-api.js +1 -1
- package/dist/api.js +13 -13
- 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/message-tool-api.js +1 -1
- package/dist/runtime-api.js +11 -11
- package/dist/setup-entry.js +1 -1
- package/dist/setup-plugin-api.js +1 -1
- package/node_modules/@slack/bolt/node_modules/@types/node/README.md +1 -1
- package/node_modules/@slack/bolt/node_modules/@types/node/package.json +2 -2
- package/node_modules/@slack/bolt/node_modules/@types/node/web-globals/streams.d.ts +4 -0
- package/node_modules/@slack/web-api/node_modules/@types/node/README.md +1 -1
- package/node_modules/@slack/web-api/node_modules/@types/node/package.json +2 -2
- package/node_modules/@slack/web-api/node_modules/@types/node/web-globals/streams.d.ts +4 -0
- 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 +18 -0
- package/package.json +5 -5
- package/dist/.setup/accounts.runtime-BpWv-6-2.mjs +0 -2
- package/dist/.setup/action-runtime.runtime-DwH3NdpT.mjs +0 -2
|
@@ -1,24 +1,24 @@
|
|
|
1
|
-
import { A as countSlackTextUtf8Bytes, C as buildSlackBlocksFallbackText, E as SLACK_EDIT_TEXT_MAX_BYTES, H as SLACK_SESSION_LINK_ACTION_ID, M as truncateSlackTextByUtf8Bytes, Pt as resolveSlackReplyToMode, Y as normalizeSlackOutboundText, c as qualifySlackRoutePeerId, j as truncateSlackText, k as SLACK_TEXT_LIMIT, ot as escapeSlackMrkdwn, v as hasSlackNativeDataBlock } from "./session-status-
|
|
1
|
+
import { A as countSlackTextUtf8Bytes, C as buildSlackBlocksFallbackText, E as SLACK_EDIT_TEXT_MAX_BYTES, H as SLACK_SESSION_LINK_ACTION_ID, M as truncateSlackTextByUtf8Bytes, Pt as resolveSlackReplyToMode, Y as normalizeSlackOutboundText, c as qualifySlackRoutePeerId, j as truncateSlackText, k as SLACK_TEXT_LIMIT, ot as escapeSlackMrkdwn, v as hasSlackNativeDataBlock } from "./session-status-Cf7AvWOt.mjs";
|
|
2
2
|
import { n as formatSlackTarget } from "./target-parsing-DEsPjngB.mjs";
|
|
3
|
-
import {
|
|
4
|
-
import { a as prepareSlackReply, l as resolveSlackReplyRenderPlan } from "./reply-blocks-
|
|
3
|
+
import { A as resolveSlackUserAllowed, E as normalizeSlackAllowOwnerEntry, T as normalizeAllowListLower, o as formatSlackError } from "./probe-DiYIMPJo.mjs";
|
|
4
|
+
import { a as prepareSlackReply, l as resolveSlackReplyRenderPlan } from "./reply-blocks-Bm8kf6mK.mjs";
|
|
5
5
|
import { n as resolveSlackReplyThreadTs } from "./thread-ts-CukseRVL.mjs";
|
|
6
6
|
import { n as resolveSlackStreamingMode, t as resolveSlackNativeStreaming } from "./streaming-compat-B-e0mqM0.mjs";
|
|
7
|
-
import { D as resolveSlackMessageText$1, E as resolveSlackBlocksText, O as buildSlackEditTextPayload, S as formatSlackFileReferenceList, T as isSlackUnfurlAttachment, a as editSlackRenderedMessage, d as reactSlackMessage, i as editSlackMessage, m as removeSlackReaction, n as deleteSlackMessage, v as logVerbose$1, w as hasSlackTableBlock, x as formatSlackFileReference } from "./actions-
|
|
8
|
-
import { c as hasSlackThreadFailureNotice, d as recordSlackThreadFailureNotice, f as recordSlackThreadParticipation, l as hasSlackThreadParticipation, m as buildSlackNativeDataDeliveryPlan, o as clearSlackThreadFailureNotice, r as sendMessageSlack, u as hasSlackThreadParticipationWithPersistence } from "./send-
|
|
9
|
-
import { A as resolveChannelContextVisibilityMode, D as readSlackAssistantThreadContext, E as buildSlackAssistantThreadMetadata, F as stripSlackMentionsForCommandDetection, M as resolveStorePath, N as updateLastRoute, O as getSessionEntry, T as resolveSlackChatType, _ as SlackStreamNotDeliveredError, b as startSlackStream, d as resolveSlackRoutingContext, f as registerSlackSessionRun, g as resolveSlackEffectiveAllowFrom, h as resolveSlackCommandIngress, j as resolveChannelResetConfig, k as readSessionUpdatedAt, l as authorizeSlackDirectMessage, m as authorizeSlackBotRoomMessage, o as resolveSlackRoomContextHints, p as resolveSlackThreadTargets, r as trackSlackDraftMessage, u as resolveConversationLabel, v as appendSlackStream, w as normalizeSlackChannelType, x as stopSlackStream, y as markSlackStreamFallbackDelivered } from "./provider-
|
|
10
|
-
import { n as resolveSlackChannelConfig } from "./policy-
|
|
11
|
-
import { a as resolveSlackThreadTs, i as readSlackReplyBlocks, n as deliverReplies, o as sanitizeSlackMonitorReplyPayload, s as emitSlackMessageSentHooks, t as createSlackReplyDeliveryPlan } from "./replies-
|
|
7
|
+
import { D as resolveSlackMessageText$1, E as resolveSlackBlocksText, O as buildSlackEditTextPayload, S as formatSlackFileReferenceList, T as isSlackUnfurlAttachment, a as editSlackRenderedMessage, d as reactSlackMessage, i as editSlackMessage, m as removeSlackReaction, n as deleteSlackMessage, v as logVerbose$1, w as hasSlackTableBlock, x as formatSlackFileReference } from "./actions-DKCtBgCI.mjs";
|
|
8
|
+
import { c as hasSlackThreadFailureNotice, d as recordSlackThreadFailureNotice, f as recordSlackThreadParticipation, l as hasSlackThreadParticipation, m as buildSlackNativeDataDeliveryPlan, o as clearSlackThreadFailureNotice, r as sendMessageSlack, u as hasSlackThreadParticipationWithPersistence } from "./send-Cp6omkOg.mjs";
|
|
9
|
+
import { A as resolveChannelContextVisibilityMode, D as readSlackAssistantThreadContext, E as buildSlackAssistantThreadMetadata, F as stripSlackMentionsForCommandDetection, M as resolveStorePath, N as updateLastRoute, O as getSessionEntry, T as resolveSlackChatType, _ as SlackStreamNotDeliveredError, b as startSlackStream, d as resolveSlackRoutingContext, f as registerSlackSessionRun, g as resolveSlackEffectiveAllowFrom, h as resolveSlackCommandIngress, j as resolveChannelResetConfig, k as readSessionUpdatedAt, l as authorizeSlackDirectMessage, m as authorizeSlackBotRoomMessage, o as resolveSlackRoomContextHints, p as resolveSlackThreadTargets, r as trackSlackDraftMessage, u as resolveConversationLabel, v as appendSlackStream, w as normalizeSlackChannelType, x as stopSlackStream, y as markSlackStreamFallbackDelivered } from "./provider-C-jPaGt2.mjs";
|
|
10
|
+
import { n as resolveSlackChannelConfig } from "./policy-BApW53pI.mjs";
|
|
11
|
+
import { a as resolveSlackThreadTs, i as readSlackReplyBlocks, n as deliverReplies, o as sanitizeSlackMonitorReplyPayload, s as emitSlackMessageSentHooks, t as createSlackReplyDeliveryPlan } from "./replies-BBAJxUOQ.mjs";
|
|
12
12
|
import { asOptionalRecord, normalizeLowercaseStringOrEmpty, normalizeOptionalLowercaseString, normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
13
13
|
import { resolveInboundLastRouteSessionKey } from "openclaw/plugin-sdk/routing";
|
|
14
|
-
import { buildChannelProgressDraftLine, createChannelMessageReplyPipeline, createChannelProgressDraftCompositor, createChannelProgressWorkCounter, createDraftStreamLoop,
|
|
14
|
+
import { buildChannelProgressDraftLine, createChannelMessageReplyPipeline, createChannelProgressDraftCompositor, createChannelProgressWorkCounter, createDraftStreamLoop, createFinalizableDraftLifecycle, createLivePreviewLifecycle, createMessageReceiptFromOutboundResults, formatChannelProgressDraftDiffStat, formatChannelProgressDraftText, formatPlanChecklistLines, resolveAgentOutboundIdentity, resolveChannelMessageSourceReplyDeliveryMode, resolveChannelProgressDraftConfig, resolveChannelProgressDraftMaxLineChars, resolveChannelStreamingBlockEnabled, resolveChannelStreamingPreviewToolProgress, resolveChannelStreamingSuppressDefaultToolProgressMessages } from "openclaw/plugin-sdk/channel-outbound";
|
|
15
15
|
import { createLazyRuntimeModule } from "openclaw/plugin-sdk/lazy-runtime";
|
|
16
16
|
import { danger, logVerbose, shouldLogVerbose } from "openclaw/plugin-sdk/runtime-env";
|
|
17
17
|
import { sanitizeAssistantVisibleText } from "openclaw/plugin-sdk/text-chunking";
|
|
18
18
|
import { truncateUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
|
|
19
19
|
import { resolveMarkdownTableMode } from "openclaw/plugin-sdk/markdown-table-runtime";
|
|
20
20
|
import { buildTtsSupplementMediaPayload, getReplyPayloadTtsSupplement, isReplyPayloadNonTerminalToolErrorWarning, resolveSendableOutboundReplyParts } from "openclaw/plugin-sdk/reply-payload";
|
|
21
|
-
import { asDateTimestampMs, asFiniteNumberInRange, parseStrictFiniteNumber, resolveExpiresAtMsFromDurationMs } from "openclaw/plugin-sdk/number-runtime";
|
|
21
|
+
import { asDateTimestampMs, asFiniteNumberInRange, parseStrictFiniteNumber, resolveExpiresAtMsFromDurationMs, resolvePromptHistoryLimit } from "openclaw/plugin-sdk/number-runtime";
|
|
22
22
|
import { hash } from "node:crypto";
|
|
23
23
|
import { pruneMapToMaxSize } from "openclaw/plugin-sdk/collection-runtime";
|
|
24
24
|
import { ensureConfiguredBindingRouteReady } from "openclaw/plugin-sdk/conversation-runtime";
|
|
@@ -29,17 +29,17 @@ import { formatErrorMessage, toErrorObject } from "openclaw/plugin-sdk/error-run
|
|
|
29
29
|
import { filterSupplementalContextItems, resolvePinnedMainDmOwnerFromAllowlist, shouldIncludeSupplementalContext } from "openclaw/plugin-sdk/security-runtime";
|
|
30
30
|
import { mimeTypeFromFilePath } from "openclaw/plugin-sdk/media-mime";
|
|
31
31
|
import { mergePairLoopGuardConfig } from "openclaw/plugin-sdk/pair-loop-guard-runtime";
|
|
32
|
-
import { createChannelHistoryWindow } from "openclaw/plugin-sdk/reply-history";
|
|
33
32
|
import { resolveHumanDelayConfig } from "openclaw/plugin-sdk/agent-runtime";
|
|
34
33
|
import { enqueueRoutedSystemEvent } from "openclaw/plugin-sdk/system-event-runtime";
|
|
35
34
|
import { getGlobalHookRunner } from "openclaw/plugin-sdk/plugin-runtime";
|
|
36
|
-
import { buildChannelInboundEventContext, buildMentionRegexes, classifyChannelInboundEvent, dispatchChannelInboundTurn, formatInboundEnvelope, formatInboundMediaUnavailableText, hasVisibleInboundReplyDispatch, implicitMentionKindWhen, isGroupThreadRouteExclusive, matchesMentionWithExplicit, readAgentRunTerminalOutcome,
|
|
35
|
+
import { buildChannelInboundEventContext, buildMentionRegexes, classifyChannelInboundEvent, dispatchChannelInboundTurn, formatInboundEnvelope, formatInboundMediaUnavailableText, hasVisibleInboundReplyDispatch, implicitMentionKindWhen, isGroupThreadRouteExclusive, matchesMentionWithExplicit, readAgentRunTerminalOutcome, resolveEnvelopeFormatOptions, resolveGroupThreadConfig, resolveGroupThreadMentionFacts, resolveInboundMentionDecision, resolveInboundReplyDispatchCounts, resolveUnmentionedGroupInboundPolicy, toInboundMediaFactsWithMetadata } from "openclaw/plugin-sdk/channel-inbound";
|
|
37
36
|
import { resolveGatewayPublicOrigin } from "openclaw/plugin-sdk/config-contracts";
|
|
38
37
|
import { buildControlUiSessionPath } from "openclaw/plugin-sdk/session-discussion";
|
|
39
38
|
import { createStatusReactionController, logAckFailure, logTypingFailure, resolveAckReaction, shouldAckReaction } from "openclaw/plugin-sdk/channel-feedback";
|
|
40
39
|
import { hasControlCommand } from "openclaw/plugin-sdk/command-detection";
|
|
41
40
|
import { isAbortRequestText } from "openclaw/plugin-sdk/command-primitives-runtime";
|
|
42
41
|
import { shouldHandleTextCommands } from "openclaw/plugin-sdk/command-surface";
|
|
42
|
+
import { DEFAULT_GROUP_HISTORY_LIMIT, buildHistoryContextFromEntries, buildInboundHistoryFromEntries } from "openclaw/plugin-sdk/reply-history";
|
|
43
43
|
import { createChannelPreflightAudio, formatAudioTranscriptForAgent } from "openclaw/plugin-sdk/media-understanding-runtime";
|
|
44
44
|
//#region extensions/slack/src/monitor/message-handler/timestamp.ts
|
|
45
45
|
const SLACK_TIMESTAMP_RE = /^\d+(?:\.\d+)?$/;
|
|
@@ -206,12 +206,12 @@ function createSlackDraftStream(params) {
|
|
|
206
206
|
const edit = params.edit ?? editSlackMessage;
|
|
207
207
|
const remove = params.remove ?? deleteSlackMessage;
|
|
208
208
|
let streamMessage;
|
|
209
|
+
let streamGeneration = 0;
|
|
210
|
+
let cleanupGeneration = -1;
|
|
209
211
|
let untrackConversationBoundary;
|
|
210
212
|
let lastVisibleUpdate;
|
|
211
213
|
let lastSentKey = "";
|
|
212
|
-
|
|
213
|
-
let cleanupTail = Promise.resolve();
|
|
214
|
-
const finalizedMessageIds = /* @__PURE__ */ new Set();
|
|
214
|
+
let preserveHumanReplies = false;
|
|
215
215
|
const streamState = {
|
|
216
216
|
stopped: false,
|
|
217
217
|
final: false
|
|
@@ -232,8 +232,10 @@ function createSlackDraftStream(params) {
|
|
|
232
232
|
const sentKey = `${trimmed}\n${blocks ? JSON.stringify(blocks) : ""}`;
|
|
233
233
|
if (sentKey === lastSentKey) return;
|
|
234
234
|
lastSentKey = sentKey;
|
|
235
|
+
const generation = streamGeneration;
|
|
235
236
|
try {
|
|
236
237
|
if (streamMessage) {
|
|
238
|
+
const message = streamMessage;
|
|
237
239
|
await edit(streamMessage.channelId, streamMessage.messageId, trimmed, {
|
|
238
240
|
cfg: params.cfg,
|
|
239
241
|
token: params.token,
|
|
@@ -241,7 +243,7 @@ function createSlackDraftStream(params) {
|
|
|
241
243
|
...params.eventScope ? { client: params.eventScope.client } : {},
|
|
242
244
|
...blocks ? { blocks } : {}
|
|
243
245
|
});
|
|
244
|
-
lastVisibleUpdate = {
|
|
246
|
+
if (streamMessage === message) lastVisibleUpdate = {
|
|
245
247
|
text: trimmed,
|
|
246
248
|
...blocks ? { blocks } : {}
|
|
247
249
|
};
|
|
@@ -266,16 +268,22 @@ function createSlackDraftStream(params) {
|
|
|
266
268
|
...params.metadata ? { metadata: params.metadata } : {},
|
|
267
269
|
...blocks ? { blocks } : {}
|
|
268
270
|
});
|
|
271
|
+
const sentMessage = {
|
|
272
|
+
channelId: sent.channelId,
|
|
273
|
+
messageId: sent.messageId,
|
|
274
|
+
generation
|
|
275
|
+
};
|
|
276
|
+
if (generation !== streamGeneration) {
|
|
277
|
+
if (sent.channelId && sent.messageId) lifecycle.retire(sentMessage, { defer: true });
|
|
278
|
+
return;
|
|
279
|
+
}
|
|
269
280
|
if (!sent.channelId || !sent.messageId) {
|
|
270
281
|
stopTrackingConversationBoundary();
|
|
271
282
|
streamState.stopped = true;
|
|
272
283
|
params.warn?.("slack stream preview stopped (missing identifiers from sendMessage)");
|
|
273
284
|
return;
|
|
274
285
|
}
|
|
275
|
-
streamMessage =
|
|
276
|
-
channelId: sent.channelId,
|
|
277
|
-
messageId: sent.messageId
|
|
278
|
-
};
|
|
286
|
+
streamMessage = sentMessage;
|
|
279
287
|
lastVisibleUpdate = {
|
|
280
288
|
text: trimmed,
|
|
281
289
|
...blocks ? { blocks } : {}
|
|
@@ -293,68 +301,88 @@ function createSlackDraftStream(params) {
|
|
|
293
301
|
}).stop;
|
|
294
302
|
}
|
|
295
303
|
} catch (err) {
|
|
296
|
-
|
|
297
|
-
|
|
304
|
+
if (generation === streamGeneration) {
|
|
305
|
+
stopTrackingConversationBoundary();
|
|
306
|
+
streamState.stopped = true;
|
|
307
|
+
}
|
|
298
308
|
params.warn?.(`slack stream preview failed: ${formatSlackError(err)}`);
|
|
299
309
|
}
|
|
300
310
|
};
|
|
301
|
-
const
|
|
311
|
+
const lifecycle = createFinalizableDraftLifecycle({
|
|
302
312
|
throttleMs,
|
|
303
313
|
coalesceInFlight: true,
|
|
304
314
|
state: streamState,
|
|
305
315
|
sendOrEditStreamMessage,
|
|
306
316
|
emptyValue: "",
|
|
307
|
-
isEmpty: (value) => !normalizeUpdate(value).text.trim()
|
|
317
|
+
isEmpty: (value) => !normalizeUpdate(value).text.trim(),
|
|
318
|
+
readMessageId: () => streamMessage,
|
|
319
|
+
clearMessageId: () => {
|
|
320
|
+
streamMessage = void 0;
|
|
321
|
+
lastVisibleUpdate = void 0;
|
|
322
|
+
lastSentKey = "";
|
|
323
|
+
},
|
|
324
|
+
isValidMessageId: (value) => typeof value === "object" && value !== null,
|
|
325
|
+
deleteMessage: async (message) => {
|
|
326
|
+
if (message.generation > cleanupGeneration) return false;
|
|
327
|
+
if (!message.retained && !(preserveHumanReplies && message.detachedByHuman)) await remove(message.channelId, message.messageId, {
|
|
328
|
+
token: params.token,
|
|
329
|
+
accountId: params.accountId,
|
|
330
|
+
...params.eventScope ? { client: params.eventScope.client } : {}
|
|
331
|
+
});
|
|
332
|
+
return true;
|
|
333
|
+
},
|
|
334
|
+
warn: params.warn,
|
|
335
|
+
warnPrefix: "slack stream preview cleanup failed"
|
|
308
336
|
});
|
|
337
|
+
const { loop, update, discardPending, seal } = lifecycle;
|
|
309
338
|
const stopTrackingConversationBoundary = () => {
|
|
310
339
|
untrackConversationBoundary?.();
|
|
311
340
|
untrackConversationBoundary = void 0;
|
|
312
341
|
};
|
|
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
|
-
}
|
|
342
|
+
const dropDetachedMessages = () => {
|
|
343
|
+
const generation = streamGeneration;
|
|
344
|
+
return lifecycle.cleanupPending(() => {
|
|
345
|
+
preserveHumanReplies = false;
|
|
346
|
+
cleanupGeneration = generation;
|
|
334
347
|
});
|
|
335
|
-
return cleanupTail;
|
|
336
348
|
};
|
|
337
349
|
const discardPendingAndStopTracking = async () => {
|
|
350
|
+
const generation = streamGeneration;
|
|
338
351
|
await discardPending();
|
|
339
|
-
stopTrackingConversationBoundary();
|
|
352
|
+
if (generation === streamGeneration) stopTrackingConversationBoundary();
|
|
340
353
|
};
|
|
341
354
|
const clear = async (options) => {
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
355
|
+
const generation = streamGeneration;
|
|
356
|
+
let clearingMessage = streamMessage;
|
|
357
|
+
await lifecycle.clearWithStop(async () => {
|
|
358
|
+
if (generation === streamGeneration) {
|
|
359
|
+
await discardPendingAndStopTracking();
|
|
360
|
+
if (generation === streamGeneration) {
|
|
361
|
+
clearingMessage = streamMessage;
|
|
362
|
+
streamMessage = void 0;
|
|
363
|
+
lastVisibleUpdate = void 0;
|
|
364
|
+
lastSentKey = "";
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
cleanupGeneration = generation;
|
|
368
|
+
preserveHumanReplies = options?.preserveHumanReplies === true;
|
|
369
|
+
}, {
|
|
370
|
+
readMessageId: () => clearingMessage,
|
|
371
|
+
clearMessageId: () => {
|
|
372
|
+
clearingMessage = void 0;
|
|
373
|
+
}
|
|
374
|
+
});
|
|
350
375
|
};
|
|
351
376
|
const forceNewMessage = (reason = "turn") => {
|
|
352
377
|
stopTrackingConversationBoundary();
|
|
353
|
-
if (reason === "turn")
|
|
378
|
+
if (reason === "turn") {
|
|
379
|
+
streamState.stopped = false;
|
|
380
|
+
streamGeneration += 1;
|
|
381
|
+
}
|
|
354
382
|
streamState.final = false;
|
|
355
|
-
if (streamMessage && !
|
|
383
|
+
if (streamMessage && !streamMessage.retained) {
|
|
356
384
|
streamMessage.detachedByHuman = reason === "human";
|
|
357
|
-
|
|
385
|
+
lifecycle.retire(streamMessage, { defer: true });
|
|
358
386
|
}
|
|
359
387
|
streamMessage = void 0;
|
|
360
388
|
lastVisibleUpdate = void 0;
|
|
@@ -368,7 +396,7 @@ function createSlackDraftStream(params) {
|
|
|
368
396
|
const { channelId } = currentMessage;
|
|
369
397
|
await editFinal();
|
|
370
398
|
if (streamMessage?.channelId === channelId && streamMessage.messageId === messageId) {
|
|
371
|
-
|
|
399
|
+
currentMessage.retained = true;
|
|
372
400
|
stopTrackingConversationBoundary();
|
|
373
401
|
return true;
|
|
374
402
|
}
|
|
@@ -1174,7 +1202,7 @@ function createSlackNativeProgressTransport(params) {
|
|
|
1174
1202
|
//#endregion
|
|
1175
1203
|
//#region extensions/slack/src/monitor/message-handler/dispatch-progress.ts
|
|
1176
1204
|
function createSlackProgressRuntime(runtimeParams) {
|
|
1177
|
-
const { setup, delivery
|
|
1205
|
+
const { setup, delivery } = runtimeParams;
|
|
1178
1206
|
const { account, cfg, ctx, hasSlackCustomIdentity, message, prepared, replyPlan, runtime, slackClient, slackIdentity, slackMessageMetadata, slackStreaming, shouldUseDraftStream, useStreaming, previewStreamingEnabled } = setup;
|
|
1179
1207
|
const draftStream = shouldUseDraftStream ? createSlackDraftStream({
|
|
1180
1208
|
target: prepared.replyTarget,
|
|
@@ -1347,21 +1375,21 @@ function createSlackProgressRuntime(runtimeParams) {
|
|
|
1347
1375
|
};
|
|
1348
1376
|
const appendNativeNarration = (payload, kind) => withNativeStreamOrder(() => appendNativeNarrationNow(payload, kind));
|
|
1349
1377
|
const appendNativeNarrationNow = async (payload, kind) => {
|
|
1350
|
-
if (isRenderedAsProgressTitle(payload.text)) return false;
|
|
1378
|
+
if (isRenderedAsProgressTitle(payload.text)) return { visibleReplySent: false };
|
|
1351
1379
|
const narrationUpdate = resolveNarrationUpdate(payload.text?.trimEnd());
|
|
1352
|
-
if (!narrationUpdate.delta) return false;
|
|
1353
|
-
await delivery.deliverWithStreaming({
|
|
1380
|
+
if (!narrationUpdate.delta) return { visibleReplySent: false };
|
|
1381
|
+
const result = await delivery.deliverWithStreaming({
|
|
1354
1382
|
payload,
|
|
1355
1383
|
kind,
|
|
1356
1384
|
streamText: narrationUpdate.delta,
|
|
1357
1385
|
appendSeparator: false,
|
|
1358
1386
|
taskDisplayMode: "plan"
|
|
1359
1387
|
});
|
|
1360
|
-
if (!delivery.streamFailed) {
|
|
1388
|
+
if (result.visibleReplySent && !delivery.streamFailed) {
|
|
1361
1389
|
nativeNarrationRenderedText = narrationUpdate.next.rendered;
|
|
1362
1390
|
nativeNarrationSourceText = narrationUpdate.next.source;
|
|
1363
1391
|
}
|
|
1364
|
-
return
|
|
1392
|
+
return result;
|
|
1365
1393
|
};
|
|
1366
1394
|
const resetProgressTurnState = () => {
|
|
1367
1395
|
progressWorkCounter.reset();
|
|
@@ -1369,6 +1397,7 @@ function createSlackProgressRuntime(runtimeParams) {
|
|
|
1369
1397
|
nativeNarrationSourceText = "";
|
|
1370
1398
|
};
|
|
1371
1399
|
const progressDraft = createChannelProgressDraftCompositor({
|
|
1400
|
+
preparedItems: true,
|
|
1372
1401
|
entry: account.config,
|
|
1373
1402
|
mode: slackStreaming.mode,
|
|
1374
1403
|
active: progressDraftActive,
|
|
@@ -1415,31 +1444,50 @@ function createSlackProgressRuntime(runtimeParams) {
|
|
|
1415
1444
|
}
|
|
1416
1445
|
}
|
|
1417
1446
|
});
|
|
1447
|
+
const previewLifecycle = createLivePreviewLifecycle({
|
|
1448
|
+
draft: draftStream && !useDraftProgressCard ? {
|
|
1449
|
+
flush: draftStream.flush,
|
|
1450
|
+
discardPending: draftStream.discardPending,
|
|
1451
|
+
seal: draftStream.seal,
|
|
1452
|
+
id: () => {
|
|
1453
|
+
const channelId = draftStream.channelId();
|
|
1454
|
+
const messageId = draftStream.messageId();
|
|
1455
|
+
return channelId && messageId ? {
|
|
1456
|
+
channelId,
|
|
1457
|
+
messageId
|
|
1458
|
+
} : void 0;
|
|
1459
|
+
},
|
|
1460
|
+
clear: async () => {
|
|
1461
|
+
await draftStream.clear({ preserveHumanReplies: !isProgressMode && previewLifecycle.finalDelivered });
|
|
1462
|
+
}
|
|
1463
|
+
} : void 0,
|
|
1464
|
+
cleanupUndelivered: true,
|
|
1465
|
+
onFinalStarted: () => progressDraft.markFinalReplyStarted(),
|
|
1466
|
+
onFinalDelivered: () => progressDraft.markFinalReplyDelivered(),
|
|
1467
|
+
onCleanupFailure: (error) => logVerbose(`slack: progress preview cleanup failed (${formatSlackError(error)})`)
|
|
1468
|
+
});
|
|
1418
1469
|
const commentaryProgressEnabled = progressDraft.commentaryProgressEnabled;
|
|
1419
1470
|
const deliverNativeFinal = async (payload, kind) => {
|
|
1420
|
-
progressDraft.markFinalReplyStarted();
|
|
1421
1471
|
await cancelNativeUpdates();
|
|
1422
|
-
await withNativeStreamOrder(() => deliverNativeFinalNow(payload, kind));
|
|
1472
|
+
return await withNativeStreamOrder(() => deliverNativeFinalNow(payload, kind));
|
|
1423
1473
|
};
|
|
1424
1474
|
const deliverNativeFinalNow = async (payload, kind) => {
|
|
1425
|
-
progressDraft.markFinalReplyStarted();
|
|
1426
1475
|
const streamReady = await nativeTransport.waitForStart();
|
|
1427
1476
|
const finalThreadTs = delivery.streamSession?.threadTs ?? delivery.nativeProgressStreamThreadTs;
|
|
1428
1477
|
if (payload.isError !== true && streamReady && Boolean(delivery.streamSession) && delivery.isStreamingEligible(payload, { maxTextBytes: 4e3 })) {
|
|
1429
1478
|
await appendNativeProgressCompletion(false);
|
|
1430
|
-
await delivery.deliverWithStreaming({
|
|
1479
|
+
return await delivery.deliverWithStreaming({
|
|
1431
1480
|
payload,
|
|
1432
1481
|
kind
|
|
1433
1482
|
});
|
|
1434
|
-
} else {
|
|
1435
|
-
await delivery.deliverNormally({
|
|
1436
|
-
payload,
|
|
1437
|
-
kind,
|
|
1438
|
-
forcedThreadTs: finalThreadTs
|
|
1439
|
-
});
|
|
1440
|
-
await appendNativeProgressCompletion(payload.isError === true);
|
|
1441
1483
|
}
|
|
1442
|
-
|
|
1484
|
+
const result = await delivery.deliverNormally({
|
|
1485
|
+
payload,
|
|
1486
|
+
kind,
|
|
1487
|
+
forcedThreadTs: finalThreadTs
|
|
1488
|
+
});
|
|
1489
|
+
await appendNativeProgressCompletion(payload.isError === true);
|
|
1490
|
+
return result;
|
|
1443
1491
|
};
|
|
1444
1492
|
const buildNativeProgressCompletionChunks = (finalInProgressStatus) => {
|
|
1445
1493
|
const snapshot = progressDraft.getSnapshot();
|
|
@@ -1536,6 +1584,7 @@ function createSlackProgressRuntime(runtimeParams) {
|
|
|
1536
1584
|
if (useNativeProgressStreaming) await finishNativeProgressTurn(completionChunks);
|
|
1537
1585
|
else {
|
|
1538
1586
|
await progressCard.finalize("success", priorSnapshot, priorFallbackText);
|
|
1587
|
+
await previewLifecycle.cleanup();
|
|
1539
1588
|
draftStream?.forceNewMessage();
|
|
1540
1589
|
await dropDetachedProgressCards();
|
|
1541
1590
|
}
|
|
@@ -1546,7 +1595,7 @@ function createSlackProgressRuntime(runtimeParams) {
|
|
|
1546
1595
|
nativeUpdatesStopped = false;
|
|
1547
1596
|
nativeUpdates.resetThrottleWindow();
|
|
1548
1597
|
progressCard.reset();
|
|
1549
|
-
|
|
1598
|
+
previewLifecycle.reset();
|
|
1550
1599
|
delivery.resetDeliveryTracker();
|
|
1551
1600
|
return true;
|
|
1552
1601
|
};
|
|
@@ -1561,26 +1610,26 @@ function createSlackProgressRuntime(runtimeParams) {
|
|
|
1561
1610
|
};
|
|
1562
1611
|
const onQueuedFollowupAdmitted = !shouldUseDraftStream && !useNativeProgressStreaming ? void 0 : async () => {
|
|
1563
1612
|
await draftStream?.flush();
|
|
1564
|
-
resetPreviewDeliveryState();
|
|
1565
1613
|
if (isProgressMode) await beginNewProgressTurn({ force: true });
|
|
1566
|
-
else
|
|
1614
|
+
else {
|
|
1615
|
+
await previewLifecycle.cleanup();
|
|
1616
|
+
previewLifecycle.reset();
|
|
1617
|
+
draftStream?.forceNewMessage();
|
|
1618
|
+
}
|
|
1567
1619
|
delivery.resetDeliveryTracker();
|
|
1568
1620
|
resetDraftDeliveryState();
|
|
1569
1621
|
progressDraft.reset();
|
|
1570
1622
|
};
|
|
1571
|
-
const onQueuedFollowupSettled = !
|
|
1623
|
+
const onQueuedFollowupSettled = !draftStream && !useNativeProgressStreaming ? void 0 : async () => {
|
|
1572
1624
|
if (useNativeProgressStreaming) {
|
|
1573
1625
|
progressDraft.markFinalReplyStarted();
|
|
1574
1626
|
await cancelNativeUpdates();
|
|
1575
1627
|
await finishNativeProgressTurn(nativeProgressCompletionSent ? void 0 : buildNativeProgressCompletionChunks(nativeProgressTerminalStatus));
|
|
1576
|
-
progressDraft.markFinalReplyDelivered();
|
|
1577
1628
|
return;
|
|
1578
1629
|
}
|
|
1579
|
-
if (
|
|
1630
|
+
if (!useDraftProgressCard) {
|
|
1580
1631
|
progressDraft.markFinalReplyStarted();
|
|
1581
|
-
await
|
|
1582
|
-
await draftStream?.dropDetachedMessages();
|
|
1583
|
-
progressDraft.markFinalReplyDelivered();
|
|
1632
|
+
await previewLifecycle.cleanup();
|
|
1584
1633
|
return;
|
|
1585
1634
|
}
|
|
1586
1635
|
if (!progressCard.hasTerminalized) await draftStream?.clear();
|
|
@@ -1588,6 +1637,7 @@ function createSlackProgressRuntime(runtimeParams) {
|
|
|
1588
1637
|
};
|
|
1589
1638
|
return {
|
|
1590
1639
|
draftStream,
|
|
1640
|
+
previewLifecycle,
|
|
1591
1641
|
isProgressMode,
|
|
1592
1642
|
useDraftProgressCard,
|
|
1593
1643
|
useNativeProgressStreaming,
|
|
@@ -1701,6 +1751,7 @@ async function createSlackDispatchSetup(prepared) {
|
|
|
1701
1751
|
const messageTs = message.ts ?? message.event_ts;
|
|
1702
1752
|
const incomingThreadTs = message.thread_ts;
|
|
1703
1753
|
let didSetStatus = false;
|
|
1754
|
+
let statusWasSet = false;
|
|
1704
1755
|
let didAddTypingReaction = false;
|
|
1705
1756
|
const statusReactionsEnabled = prepared.ctxPayload.InboundEventKind !== "room_event" && Boolean(prepared.ackReactionPromise) && Boolean(reactionMessageTs) && cfg.messages?.statusReactions?.enabled === true;
|
|
1706
1757
|
const statusReactions = createStatusReactionController({
|
|
@@ -1752,7 +1803,7 @@ async function createSlackDispatchSetup(prepared) {
|
|
|
1752
1803
|
start: async () => {
|
|
1753
1804
|
if (!didSetStatus && !threadStatusGate.hasVisibleOutput()) {
|
|
1754
1805
|
didSetStatus = true;
|
|
1755
|
-
await ctx.setSlackSessionStatus({
|
|
1806
|
+
statusWasSet = await ctx.setSlackSessionStatus({
|
|
1756
1807
|
channelId: message.channel,
|
|
1757
1808
|
threadTs: statusThreadTs,
|
|
1758
1809
|
status: "processing",
|
|
@@ -1773,12 +1824,17 @@ async function createSlackDispatchSetup(prepared) {
|
|
|
1773
1824
|
stop: async () => {
|
|
1774
1825
|
if (didSetStatus) {
|
|
1775
1826
|
didSetStatus = false;
|
|
1776
|
-
|
|
1827
|
+
const reportFailure = statusWasSet;
|
|
1828
|
+
statusWasSet = false;
|
|
1829
|
+
const restored = await ctx.setSlackSessionStatus({
|
|
1777
1830
|
channelId: message.channel,
|
|
1778
1831
|
threadTs: statusThreadTs,
|
|
1779
1832
|
status: "active",
|
|
1780
1833
|
eventScope: prepared.eventScope
|
|
1781
1834
|
});
|
|
1835
|
+
if (reportFailure && !restored) try {
|
|
1836
|
+
runtime.error?.("Slack session status could not return to active after processing. Enable verbose logging to inspect the Slack API failure.");
|
|
1837
|
+
} catch {}
|
|
1782
1838
|
}
|
|
1783
1839
|
if (didAddTypingReaction && typingReaction && message.ts) {
|
|
1784
1840
|
didAddTypingReaction = false;
|
|
@@ -1888,8 +1944,7 @@ function createSlackStreamingDeliveryRuntime(setup) {
|
|
|
1888
1944
|
streamFailed: false,
|
|
1889
1945
|
usedReplyThreadTs: void 0,
|
|
1890
1946
|
usedBlockReplyThreadTs: void 0,
|
|
1891
|
-
observedReplyDelivery: false
|
|
1892
|
-
observedFinalReplyDelivery: false
|
|
1947
|
+
observedReplyDelivery: false
|
|
1893
1948
|
};
|
|
1894
1949
|
const emitStreamedDelivery = (content, result) => {
|
|
1895
1950
|
emitSlackMessageSentHooks({
|
|
@@ -1930,14 +1985,18 @@ function createSlackStreamingDeliveryRuntime(setup) {
|
|
|
1930
1985
|
if (session.stoppedBySlack) return;
|
|
1931
1986
|
state.observedReplyDelivery = true;
|
|
1932
1987
|
state.usedReplyThreadTs ??= session.threadTs;
|
|
1933
|
-
return
|
|
1988
|
+
return {
|
|
1989
|
+
visibleReplySent: session.delivered,
|
|
1990
|
+
...stopResult.messageId ? { messageIds: [stopResult.messageId] } : {},
|
|
1991
|
+
threadId: session.threadTs
|
|
1992
|
+
};
|
|
1934
1993
|
} catch (stopErr) {
|
|
1935
1994
|
if (stopErr instanceof SlackStreamNotDeliveredError) fallbackError = stopErr;
|
|
1936
1995
|
else throw stopErr;
|
|
1937
1996
|
}
|
|
1938
1997
|
const fallbackText = fallbackError.pendingText.trim();
|
|
1939
1998
|
if (!fallbackText) return;
|
|
1940
|
-
await deliverReplies({
|
|
1999
|
+
const sent = await deliverReplies({
|
|
1941
2000
|
cfg: ctx.cfg,
|
|
1942
2001
|
replies: [prepareSlackReply({ text: fallbackText })],
|
|
1943
2002
|
target: prepared.replyTarget,
|
|
@@ -1954,6 +2013,7 @@ function createSlackStreamingDeliveryRuntime(setup) {
|
|
|
1954
2013
|
deferMessageSentHooks: true,
|
|
1955
2014
|
eventScope: prepared.eventScope
|
|
1956
2015
|
});
|
|
2016
|
+
if (!sent?.receipt.platformMessageIds.length) return;
|
|
1957
2017
|
markSlackStreamFallbackDelivered(session);
|
|
1958
2018
|
if (!session.stopped) try {
|
|
1959
2019
|
await stopSlackStream({
|
|
@@ -1966,7 +2026,12 @@ function createSlackStreamingDeliveryRuntime(setup) {
|
|
|
1966
2026
|
state.observedReplyDelivery = true;
|
|
1967
2027
|
state.usedReplyThreadTs ??= session.threadTs;
|
|
1968
2028
|
logVerbose(`slack-stream: streamed delivery failed (${fallbackError.slackCode}); delivered ${fallbackText.length} chars via deliverReplies fallback`);
|
|
1969
|
-
return {
|
|
2029
|
+
return {
|
|
2030
|
+
visibleReplySent: true,
|
|
2031
|
+
messageIds: sent.receipt.platformMessageIds,
|
|
2032
|
+
receipt: sent.receipt,
|
|
2033
|
+
threadId: sent.threadTs ?? session.threadTs
|
|
2034
|
+
};
|
|
1970
2035
|
};
|
|
1971
2036
|
const finishStream = async (chunks) => {
|
|
1972
2037
|
const session = state.streamSession;
|
|
@@ -1988,7 +2053,7 @@ function createSlackStreamingDeliveryRuntime(setup) {
|
|
|
1988
2053
|
}
|
|
1989
2054
|
};
|
|
1990
2055
|
const deliverNormally = async (params) => {
|
|
1991
|
-
if (state.streamSession?.stoppedBySlack) return;
|
|
2056
|
+
if (state.streamSession?.stoppedBySlack) return { visibleReplySent: false };
|
|
1992
2057
|
const replyThreadTs = resolveDeliveryThreadTs(params);
|
|
1993
2058
|
const deliveryReplyThreadTs = replyDeliveryMode === "off" && !forcedReplyThreadTs && !isThreadReply ? void 0 : replyThreadTs;
|
|
1994
2059
|
const preparedReply = prepareSlackReply(params.payload);
|
|
@@ -1999,9 +2064,9 @@ function createSlackStreamingDeliveryRuntime(setup) {
|
|
|
1999
2064
|
}, preparedReply);
|
|
2000
2065
|
if (deliveryTracker.hasDelivered(deliveryKey)) {
|
|
2001
2066
|
logVerbose("slack: suppressed duplicate normal delivery within the same turn");
|
|
2002
|
-
return
|
|
2067
|
+
return { visibleReplySent: false };
|
|
2003
2068
|
}
|
|
2004
|
-
await deliverReplies({
|
|
2069
|
+
const sent = await deliverReplies({
|
|
2005
2070
|
cfg: ctx.cfg,
|
|
2006
2071
|
replies: [preparedReply],
|
|
2007
2072
|
target: prepared.replyTarget,
|
|
@@ -2017,8 +2082,8 @@ function createSlackStreamingDeliveryRuntime(setup) {
|
|
|
2017
2082
|
...messageSentDeliveryHookContext,
|
|
2018
2083
|
eventScope: prepared.eventScope
|
|
2019
2084
|
});
|
|
2085
|
+
if (!sent?.receipt.platformMessageIds.length) return { visibleReplySent: false };
|
|
2020
2086
|
state.observedReplyDelivery = true;
|
|
2021
|
-
if (params.kind === "final") state.observedFinalReplyDelivery = true;
|
|
2022
2087
|
const deliveredThreadTs = resolveSlackReplyThreadTs({
|
|
2023
2088
|
replyToMode: replyDeliveryMode,
|
|
2024
2089
|
replyToId: params.payload.replyToId,
|
|
@@ -2028,7 +2093,12 @@ function createSlackStreamingDeliveryRuntime(setup) {
|
|
|
2028
2093
|
rememberDeliveredThreadTs(params.kind, deliveredThreadTs);
|
|
2029
2094
|
replyPlan.markSent();
|
|
2030
2095
|
deliveryTracker.markDelivered(deliveryKey);
|
|
2031
|
-
return
|
|
2096
|
+
return {
|
|
2097
|
+
visibleReplySent: true,
|
|
2098
|
+
messageIds: sent.receipt.platformMessageIds,
|
|
2099
|
+
receipt: sent.receipt,
|
|
2100
|
+
threadId: sent.threadTs ?? deliveredThreadTs
|
|
2101
|
+
};
|
|
2032
2102
|
};
|
|
2033
2103
|
const isStreamingEligible = (payload, options) => {
|
|
2034
2104
|
const reply = resolveSendableOutboundReplyParts(payload);
|
|
@@ -2037,27 +2107,23 @@ function createSlackStreamingDeliveryRuntime(setup) {
|
|
|
2037
2107
|
return !state.streamFailed && !reply.hasMedia && renderPlan.mode !== "split" && !renderPlan.textIsSlackPlainText && !plannedBlocks?.length && !readSlackReplyBlocks(payload)?.length && reply.hasText && (!options?.maxTextBytes || countSlackTextUtf8Bytes(reply.trimmedText) <= options.maxTextBytes);
|
|
2038
2108
|
};
|
|
2039
2109
|
const deliverWithStreaming = async (params) => {
|
|
2040
|
-
if (state.streamSession?.stoppedBySlack) return;
|
|
2041
|
-
if (!isStreamingEligible(params.payload)) {
|
|
2042
|
-
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
});
|
|
2047
|
-
return;
|
|
2048
|
-
}
|
|
2110
|
+
if (state.streamSession?.stoppedBySlack) return { visibleReplySent: false };
|
|
2111
|
+
if (!isStreamingEligible(params.payload)) return await deliverNormally({
|
|
2112
|
+
payload: params.payload,
|
|
2113
|
+
kind: params.kind,
|
|
2114
|
+
forcedThreadTs: state.streamSession?.threadTs ?? state.nativeProgressStreamThreadTs
|
|
2115
|
+
});
|
|
2049
2116
|
if (!state.streamSession && state.nativeProgressStreamStartPromise) await state.nativeProgressStreamStartPromise;
|
|
2050
|
-
if (state.streamSession?.stoppedBySlack) return;
|
|
2117
|
+
if (state.streamSession?.stoppedBySlack) return { visibleReplySent: false };
|
|
2051
2118
|
let session = state.streamSession;
|
|
2052
2119
|
const threadTs = session?.threadTs ?? replyPlan.nextThreadTs();
|
|
2053
2120
|
if (state.streamFailed || !threadTs) {
|
|
2054
2121
|
state.streamFailed = true;
|
|
2055
|
-
await deliverNormally({
|
|
2122
|
+
return await deliverNormally({
|
|
2056
2123
|
payload: params.payload,
|
|
2057
2124
|
kind: params.kind,
|
|
2058
2125
|
forcedThreadTs: threadTs ?? state.nativeProgressStreamThreadTs
|
|
2059
2126
|
});
|
|
2060
|
-
return;
|
|
2061
2127
|
}
|
|
2062
2128
|
const hookContent = resolveSendableOutboundReplyParts(params.payload).trimmedText;
|
|
2063
2129
|
const text = params.streamText ?? hookContent;
|
|
@@ -2068,9 +2134,10 @@ function createSlackStreamingDeliveryRuntime(setup) {
|
|
|
2068
2134
|
});
|
|
2069
2135
|
if (deliveryTracker.hasDelivered(deliveryKey)) {
|
|
2070
2136
|
logVerbose("slack-stream: suppressed duplicate reply payload");
|
|
2071
|
-
return;
|
|
2137
|
+
return { visibleReplySent: false };
|
|
2072
2138
|
}
|
|
2073
2139
|
let messageId;
|
|
2140
|
+
let fallbackDelivery;
|
|
2074
2141
|
try {
|
|
2075
2142
|
if (session) await appendSlackStream({
|
|
2076
2143
|
session,
|
|
@@ -2107,18 +2174,16 @@ function createSlackStreamingDeliveryRuntime(setup) {
|
|
|
2107
2174
|
});
|
|
2108
2175
|
throw error;
|
|
2109
2176
|
}
|
|
2110
|
-
if (!session) {
|
|
2111
|
-
|
|
2112
|
-
|
|
2113
|
-
|
|
2114
|
-
|
|
2115
|
-
});
|
|
2116
|
-
return;
|
|
2117
|
-
}
|
|
2177
|
+
if (!session) return await deliverNormally({
|
|
2178
|
+
payload: params.payload,
|
|
2179
|
+
kind: params.kind,
|
|
2180
|
+
forcedThreadTs: threadTs
|
|
2181
|
+
});
|
|
2118
2182
|
try {
|
|
2119
2183
|
const fallback = await deliverPendingStreamFallback(session, error);
|
|
2120
2184
|
if (!fallback && !session.stoppedBySlack) throw error;
|
|
2121
|
-
|
|
2185
|
+
fallbackDelivery = fallback;
|
|
2186
|
+
messageId = fallback?.receipt ? void 0 : fallback?.messageIds?.[0];
|
|
2122
2187
|
} catch (fallbackError) {
|
|
2123
2188
|
emitStreamedDelivery(hookContent, {
|
|
2124
2189
|
success: false,
|
|
@@ -2132,10 +2197,10 @@ function createSlackStreamingDeliveryRuntime(setup) {
|
|
|
2132
2197
|
success: false,
|
|
2133
2198
|
error: "Stopped by Slack user"
|
|
2134
2199
|
});
|
|
2135
|
-
return;
|
|
2200
|
+
return { visibleReplySent: false };
|
|
2136
2201
|
}
|
|
2202
|
+
if (!fallbackDelivery?.visibleReplySent && (!session.delivered || session.pendingText)) return { visibleReplySent: false };
|
|
2137
2203
|
state.observedReplyDelivery = true;
|
|
2138
|
-
if (params.kind === "final") state.observedFinalReplyDelivery = true;
|
|
2139
2204
|
rememberDeliveredThreadTs(params.kind, threadTs);
|
|
2140
2205
|
replyPlan.markSent();
|
|
2141
2206
|
deliveryTracker.markDelivered(deliveryKey);
|
|
@@ -2143,12 +2208,16 @@ function createSlackStreamingDeliveryRuntime(setup) {
|
|
|
2143
2208
|
success: true,
|
|
2144
2209
|
...messageId ? { messageId } : {}
|
|
2145
2210
|
});
|
|
2211
|
+
return fallbackDelivery ?? {
|
|
2212
|
+
visibleReplySent: true,
|
|
2213
|
+
...messageId ? { messageIds: [messageId] } : {},
|
|
2214
|
+
threadId: threadTs
|
|
2215
|
+
};
|
|
2146
2216
|
};
|
|
2147
2217
|
return Object.assign(state, {
|
|
2148
2218
|
deliverNormally,
|
|
2149
2219
|
deliverWithStreaming,
|
|
2150
2220
|
finishStream,
|
|
2151
|
-
hasDelivered: (params) => deliveryTracker.hasDelivered(buildSlackEventDeliveryKey(params)),
|
|
2152
2221
|
isStreamingEligible,
|
|
2153
2222
|
markPreviewPayloadDelivered,
|
|
2154
2223
|
rememberDeliveredThreadTs,
|
|
@@ -2194,17 +2263,12 @@ async function dispatchSlackMessageWithSetup(setup, beginSessionRun, turnAdoptio
|
|
|
2194
2263
|
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
2264
|
let dispatchError;
|
|
2196
2265
|
const delivery = createSlackStreamingDeliveryRuntime(setup);
|
|
2197
|
-
const draftPreviewCommitted = { value: false };
|
|
2198
2266
|
const progress = createSlackProgressRuntime({
|
|
2199
2267
|
setup,
|
|
2200
|
-
delivery
|
|
2201
|
-
resetPreviewDeliveryState: () => {
|
|
2202
|
-
draftPreviewCommitted.value = false;
|
|
2203
|
-
delivery.observedFinalReplyDelivery = false;
|
|
2204
|
-
}
|
|
2268
|
+
delivery
|
|
2205
2269
|
});
|
|
2206
|
-
const draftStream = progress
|
|
2207
|
-
setup.threadStatusGate.hasVisibleOutput = () => delivery.observedReplyDelivery ||
|
|
2270
|
+
const { draftStream, previewLifecycle } = progress;
|
|
2271
|
+
setup.threadStatusGate.hasVisibleOutput = () => delivery.observedReplyDelivery || previewLifecycle.previewFinalized || Boolean(draftStream?.messageId());
|
|
2208
2272
|
const failureNoticeThreadTs = message.thread_ts;
|
|
2209
2273
|
const failureNoticeTeamId = prepared.eventScope?.teamId;
|
|
2210
2274
|
let sawTerminalFailurePayload = false;
|
|
@@ -2212,7 +2276,7 @@ async function dispatchSlackMessageWithSetup(setup, beginSessionRun, turnAdoptio
|
|
|
2212
2276
|
const filterPassiveThreadFailure = (payload) => {
|
|
2213
2277
|
if (payload.isError !== true || prepared.ctxPayload.ChatType !== "channel" || isReplyPayloadNonTerminalToolErrorWarning(payload)) return payload;
|
|
2214
2278
|
sawTerminalFailurePayload = true;
|
|
2215
|
-
if (delivery.observedReplyDelivery ||
|
|
2279
|
+
if (delivery.observedReplyDelivery || previewLifecycle.previewFinalized) return payload;
|
|
2216
2280
|
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
2281
|
const noticeThreadTs = failureNoticeThreadTs ?? (explicitlyAddressed ? statusThreadTs : void 0);
|
|
2218
2282
|
const notice = {
|
|
@@ -2233,14 +2297,6 @@ async function dispatchSlackMessageWithSetup(setup, beginSessionRun, turnAdoptio
|
|
|
2233
2297
|
pendingFailureNotice = notice;
|
|
2234
2298
|
return payload;
|
|
2235
2299
|
};
|
|
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
2300
|
const deliverSlackPayload = async (incomingPayload, info) => {
|
|
2245
2301
|
let payload = incomingPayload;
|
|
2246
2302
|
if (info.participant && (payload.text || payload.mediaUrl || payload.mediaUrls?.length)) payload = {
|
|
@@ -2248,66 +2304,49 @@ async function dispatchSlackMessageWithSetup(setup, beginSessionRun, turnAdoptio
|
|
|
2248
2304
|
text: formatSlackGroupThreadReply(payload.text ?? "", info.participant)
|
|
2249
2305
|
};
|
|
2250
2306
|
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,
|
|
2307
|
+
const supplement = getReplyPayloadTtsSupplement(payload);
|
|
2308
|
+
const finalPayload = !progress.useDraftProgressCard && !progress.useNativeProgressStreaming && supplement && !supplement.visibleTextAlreadyDelivered && !payload.text?.trim() ? {
|
|
2309
|
+
...payload,
|
|
2310
|
+
text: supplement.spokenText
|
|
2311
|
+
} : payload;
|
|
2312
|
+
return (await previewLifecycle.deliver({
|
|
2313
|
+
kind: info.kind,
|
|
2314
|
+
payload: finalPayload,
|
|
2315
|
+
isError: payload.isError === true,
|
|
2316
|
+
deliverNormally: (reply) => progress.useNativeProgressStreaming ? progress.deliverNativeFinal(reply, info.kind) : delivery.deliverNormally({
|
|
2317
|
+
payload: reply,
|
|
2277
2318
|
kind: info.kind,
|
|
2278
2319
|
forcedThreadTs: delivery.usedReplyThreadTs
|
|
2279
|
-
})
|
|
2280
|
-
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
}
|
|
2320
|
+
}),
|
|
2321
|
+
onNormalDelivered: progress.useDraftProgressCard ? async () => {
|
|
2322
|
+
if (!await progress.finalizeDraftProgressCard(payload.isError === true ? "error" : "success")) await draftStream?.clear();
|
|
2323
|
+
} : void 0
|
|
2324
|
+
})).deliveryResult ?? { visibleReplySent: false };
|
|
2284
2325
|
}
|
|
2285
2326
|
if (progress.useNativeProgressStreaming) {
|
|
2286
2327
|
if (info.kind !== "final" && payload.isError !== true) {
|
|
2287
|
-
if (!delivery.isStreamingEligible(payload)) {
|
|
2288
|
-
|
|
2289
|
-
|
|
2290
|
-
|
|
2291
|
-
|
|
2292
|
-
|
|
2293
|
-
return;
|
|
2294
|
-
}
|
|
2295
|
-
return await progress.appendNativeNarration(payload, info.kind) ? void 0 : { visibleReplySent: false };
|
|
2328
|
+
if (!delivery.isStreamingEligible(payload)) return await delivery.deliverNormally({
|
|
2329
|
+
payload,
|
|
2330
|
+
kind: info.kind,
|
|
2331
|
+
forcedThreadTs: delivery.streamSession?.threadTs ?? delivery.nativeProgressStreamThreadTs
|
|
2332
|
+
});
|
|
2333
|
+
return await progress.appendNativeNarration(payload, info.kind);
|
|
2296
2334
|
}
|
|
2297
|
-
await delivery.deliverNormally({
|
|
2335
|
+
return await delivery.deliverNormally({
|
|
2298
2336
|
payload,
|
|
2299
2337
|
kind: info.kind,
|
|
2300
2338
|
forcedThreadTs: delivery.streamSession?.threadTs ?? delivery.nativeProgressStreamThreadTs
|
|
2301
2339
|
});
|
|
2302
|
-
return;
|
|
2303
2340
|
}
|
|
2304
|
-
if (useStreaming) {
|
|
2305
|
-
|
|
2306
|
-
|
|
2341
|
+
if (useStreaming) return (await previewLifecycle.deliver({
|
|
2342
|
+
kind: info.kind,
|
|
2343
|
+
payload,
|
|
2344
|
+
isError: payload.isError === true,
|
|
2345
|
+
deliverNormally: (reply) => delivery.deliverWithStreaming({
|
|
2346
|
+
payload: reply,
|
|
2307
2347
|
kind: info.kind
|
|
2308
|
-
})
|
|
2309
|
-
|
|
2310
|
-
}
|
|
2348
|
+
})
|
|
2349
|
+
})).deliveryResult ?? { visibleReplySent: false };
|
|
2311
2350
|
const reply = resolveSendableOutboundReplyParts(payload);
|
|
2312
2351
|
const ttsSupplement = getReplyPayloadTtsSupplement(payload);
|
|
2313
2352
|
const replySourceText = payload.text ?? ttsSupplement?.spokenText;
|
|
@@ -2321,26 +2360,13 @@ async function dispatchSlackMessageWithSetup(setup, beginSessionRun, turnAdoptio
|
|
|
2321
2360
|
accountId: account.accountId
|
|
2322
2361
|
}) });
|
|
2323
2362
|
const previewFinalTextFitsEdit = countSlackTextUtf8Bytes(previewFinalText) <= SLACK_EDIT_TEXT_MAX_BYTES;
|
|
2324
|
-
const shouldRestoreTtsSupplementTextForPreviewFallback = Boolean(ttsSupplement) && ttsSupplement?.visibleTextAlreadyDelivered !== true && Boolean(draftStream) && !
|
|
2363
|
+
const shouldRestoreTtsSupplementTextForPreviewFallback = Boolean(ttsSupplement) && ttsSupplement?.visibleTextAlreadyDelivered !== true && Boolean(draftStream) && !previewLifecycle.previewFinalized && !previewLifecycle.finalDelivered && previewStreamingEnabled && !payload.text?.trim();
|
|
2325
2364
|
let ttsPreviewFinalization;
|
|
2326
|
-
await
|
|
2365
|
+
return (await previewLifecycle.deliver({
|
|
2327
2366
|
kind: info.kind,
|
|
2328
2367
|
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,
|
|
2368
|
+
isError: payload.isError === true,
|
|
2369
|
+
adapter: {
|
|
2344
2370
|
buildFinalEdit: () => {
|
|
2345
2371
|
if (hasSlackCustomIdentity || !previewStreamingEnabled || reply.hasMedia && !ttsSupplement || payload.isError || requiresSeparateFallbackDelivery || !previewFinalTextFitsEdit || trimmedFinalText.length === 0 && !slackBlocks?.length) return;
|
|
2346
2372
|
return {
|
|
@@ -2350,11 +2376,6 @@ async function dispatchSlackMessageWithSetup(setup, beginSessionRun, turnAdoptio
|
|
|
2350
2376
|
};
|
|
2351
2377
|
},
|
|
2352
2378
|
editFinal: async (preview, edit) => {
|
|
2353
|
-
if (delivery.hasDelivered({
|
|
2354
|
-
kind: info.kind,
|
|
2355
|
-
payload,
|
|
2356
|
-
threadTs: edit.threadTs
|
|
2357
|
-
})) return;
|
|
2358
2379
|
if (ttsSupplement) ttsPreviewFinalization = { threadTs: edit.threadTs };
|
|
2359
2380
|
if (!await draftStream?.finalizeMessage(preview.messageId, async () => {
|
|
2360
2381
|
await finalizeSlackPreviewEdit({
|
|
@@ -2368,59 +2389,66 @@ async function dispatchSlackMessageWithSetup(setup, beginSessionRun, turnAdoptio
|
|
|
2368
2389
|
threadTs: edit.threadTs
|
|
2369
2390
|
});
|
|
2370
2391
|
})) 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
2392
|
},
|
|
2382
|
-
|
|
2383
|
-
|
|
2384
|
-
|
|
2393
|
+
createPreviewReceipt: (preview, edit) => createMessageReceiptFromOutboundResults({
|
|
2394
|
+
results: [{
|
|
2395
|
+
channel: "slack",
|
|
2396
|
+
channelId: preview.channelId,
|
|
2397
|
+
messageId: preview.messageId
|
|
2398
|
+
}],
|
|
2399
|
+
threadId: edit.threadTs,
|
|
2400
|
+
kind: "text"
|
|
2401
|
+
}),
|
|
2402
|
+
onPreviewFinalized: (preview) => {
|
|
2385
2403
|
const finalThreadTs = delivery.usedReplyThreadTs ?? statusThreadTs;
|
|
2386
2404
|
delivery.observedReplyDelivery = true;
|
|
2387
2405
|
replyPlan.markSent();
|
|
2388
|
-
if (!ttsSupplement)
|
|
2389
|
-
|
|
2390
|
-
|
|
2391
|
-
|
|
2392
|
-
|
|
2406
|
+
if (!ttsSupplement) {
|
|
2407
|
+
delivery.markPreviewPayloadDelivered({
|
|
2408
|
+
kind: info.kind,
|
|
2409
|
+
payload,
|
|
2410
|
+
threadTs: finalThreadTs
|
|
2411
|
+
});
|
|
2412
|
+
emitSlackMessageSentHooks({
|
|
2413
|
+
...messageSentHookContext,
|
|
2414
|
+
to: messageSentHookTarget,
|
|
2415
|
+
accountId: account.accountId,
|
|
2416
|
+
content: trimmedFinalText,
|
|
2417
|
+
success: true,
|
|
2418
|
+
messageId: preview.messageId
|
|
2419
|
+
});
|
|
2420
|
+
}
|
|
2393
2421
|
},
|
|
2394
2422
|
buildSupplementalPayload: () => ttsSupplement ? buildTtsSupplementMediaPayload(payload) : void 0,
|
|
2395
2423
|
deliverSupplemental: async (supplementalPayload) => {
|
|
2396
2424
|
const previewThreadTs = delivery.usedReplyThreadTs ?? statusThreadTs;
|
|
2397
|
-
const
|
|
2425
|
+
const supplementalResult = await delivery.deliverNormally({
|
|
2398
2426
|
payload: supplementalPayload,
|
|
2399
2427
|
kind: info.kind,
|
|
2400
2428
|
forcedThreadTs: previewThreadTs
|
|
2401
2429
|
});
|
|
2402
|
-
delivery.markPreviewPayloadDelivered({
|
|
2430
|
+
if (supplementalResult.visibleReplySent) delivery.markPreviewPayloadDelivered({
|
|
2403
2431
|
kind: info.kind,
|
|
2404
2432
|
payload,
|
|
2405
|
-
threadTs:
|
|
2433
|
+
threadTs: supplementalResult.threadId
|
|
2406
2434
|
});
|
|
2435
|
+
return supplementalResult;
|
|
2407
2436
|
},
|
|
2408
2437
|
logPreviewEditFailure: (err) => {
|
|
2409
2438
|
logVerbose(`slack: preview final edit failed; falling back to standard send (${formatSlackError(err)})`);
|
|
2410
2439
|
}
|
|
2411
|
-
}
|
|
2412
|
-
deliverNormally: async () => {
|
|
2413
|
-
await delivery.deliverNormally({
|
|
2414
|
-
payload: shouldRestoreTtsSupplementTextForPreviewFallback || ttsPreviewFinalization && !payload.text?.trim() ? {
|
|
2415
|
-
...
|
|
2440
|
+
},
|
|
2441
|
+
deliverNormally: async (normalPayload) => {
|
|
2442
|
+
return await delivery.deliverNormally({
|
|
2443
|
+
payload: normalPayload === payload && (shouldRestoreTtsSupplementTextForPreviewFallback || ttsPreviewFinalization && !payload.text?.trim()) ? {
|
|
2444
|
+
...normalPayload,
|
|
2416
2445
|
text: ttsSupplement?.spokenText
|
|
2417
|
-
} :
|
|
2446
|
+
} : normalPayload,
|
|
2418
2447
|
kind: info.kind,
|
|
2419
2448
|
...ttsPreviewFinalization?.threadTs ? { forcedThreadTs: ttsPreviewFinalization.threadTs } : {}
|
|
2420
2449
|
});
|
|
2421
2450
|
}
|
|
2422
|
-
});
|
|
2423
|
-
if (info.kind === "final") progress.progressDraft.markFinalReplyDelivered();
|
|
2451
|
+
})).deliveryResult ?? { visibleReplySent: false };
|
|
2424
2452
|
};
|
|
2425
2453
|
let agentRunFailed = false;
|
|
2426
2454
|
let settledDispatchResult;
|
|
@@ -2452,7 +2480,6 @@ async function dispatchSlackMessageWithSetup(setup, beginSessionRun, turnAdoptio
|
|
|
2452
2480
|
}
|
|
2453
2481
|
},
|
|
2454
2482
|
record: prepared.turn.record,
|
|
2455
|
-
history: prepared.turn.history,
|
|
2456
2483
|
botLoopProtection: resolveSlackBotLoopProtection(prepared),
|
|
2457
2484
|
replyOptions: {
|
|
2458
2485
|
groupThreadReplyFormatter: formatSlackGroupThreadReply,
|
|
@@ -2494,30 +2521,19 @@ async function dispatchSlackMessageWithSetup(setup, beginSessionRun, turnAdoptio
|
|
|
2494
2521
|
},
|
|
2495
2522
|
onToolStart: async (payload) => {
|
|
2496
2523
|
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
2524
|
return await progress.progressDraft.pushToolEvent(payload);
|
|
2500
2525
|
},
|
|
2501
2526
|
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);
|
|
2527
|
+
if (payload.hideFromChannelProgress || payload.suppressChannelProgress) return progress.preambleOnlyProgress ? false : progress.progressDraft.pushItemEvent(payload);
|
|
2528
|
+
if (payload.kind === "preamble" && progress.shouldYieldDraftProgress()) return false;
|
|
2529
|
+
progress.progressWorkCounter.noteItem(payload);
|
|
2530
|
+
return progress.preambleOnlyProgress && payload.kind !== "preamble" ? await progress.progressDraft.noteActivity() : await progress.progressDraft.pushItemEvent(payload);
|
|
2513
2531
|
},
|
|
2514
2532
|
onPlanUpdate: async (payload) => {
|
|
2515
2533
|
if (payload.phase !== "update") return false;
|
|
2516
2534
|
return await progress.pushPlanProgress(payload.steps, payload.explanation, payload.explanationFormat);
|
|
2517
2535
|
},
|
|
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)
|
|
2536
|
+
onApprovalEvent: (payload) => progress.progressDraft.pushApprovalEvent(payload)
|
|
2521
2537
|
}
|
|
2522
2538
|
});
|
|
2523
2539
|
if (turnResult.dispatched) {
|
|
@@ -2541,9 +2557,11 @@ async function dispatchSlackMessageWithSetup(setup, beginSessionRun, turnAdoptio
|
|
|
2541
2557
|
const completionChunks = progress.useNativeProgressStreaming && !progress.nativeProgressCompletionSent ? progress.buildNativeProgressCompletionChunks(dispatchError || agentRunFailed ? "error" : progress.nativeProgressTerminalStatus) : void 0;
|
|
2542
2558
|
if (completionChunks?.length) progress.nativeProgressCompletionSent = true;
|
|
2543
2559
|
await delivery.finishStream(completionChunks);
|
|
2544
|
-
const anyReplyDelivered = hasVisibleInboundReplyDispatch(settledDispatchResult, { observedReplyDelivery: delivery.observedReplyDelivery });
|
|
2545
|
-
if (
|
|
2546
|
-
|
|
2560
|
+
const anyReplyDelivered = hasVisibleInboundReplyDispatch(settledDispatchResult, { observedReplyDelivery: delivery.observedReplyDelivery || previewLifecycle.finalDelivered });
|
|
2561
|
+
if (anyReplyDelivered && !previewLifecycle.finalStarted && !dispatchError && !agentRunFailed) {
|
|
2562
|
+
if (hasVisibleInboundReplyDispatch(settledDispatchResult)) await previewLifecycle.observeDelivery({ visibleReplySent: true });
|
|
2563
|
+
}
|
|
2564
|
+
await previewLifecycle.cleanup({ failed: Boolean(dispatchError || agentRunFailed) });
|
|
2547
2565
|
if (pendingFailureNotice && anyReplyDelivered) recordSlackThreadFailureNotice(pendingFailureNotice);
|
|
2548
2566
|
if (dispatchError || agentRunFailed) await progress.finalizeDraftProgressCard("error");
|
|
2549
2567
|
await progress.dropDetachedProgressCards();
|
|
@@ -2562,9 +2580,8 @@ async function dispatchSlackMessageWithSetup(setup, beginSessionRun, turnAdoptio
|
|
|
2562
2580
|
teamId: prepared.eventScope?.teamId
|
|
2563
2581
|
});
|
|
2564
2582
|
if (dispatchError) throw toErrorObject(dispatchError, "Slack dispatch failed");
|
|
2565
|
-
if (!anyReplyDelivered && !
|
|
2566
|
-
await draftStream?.clear();
|
|
2567
|
-
await draftStream?.dropDetachedMessages();
|
|
2583
|
+
if (!anyReplyDelivered && !previewLifecycle.previewFinalized && !(agentRunFailed && progress.useDraftProgressCard)) {
|
|
2584
|
+
if (progress.useDraftProgressCard) await draftStream?.clear();
|
|
2568
2585
|
return;
|
|
2569
2586
|
}
|
|
2570
2587
|
if (shouldLogVerbose()) {
|
|
@@ -2655,7 +2672,7 @@ function resolveSlackAttachmentFallbackText(attachments) {
|
|
|
2655
2672
|
return parts.length > 0 ? parts.join("\n") : void 0;
|
|
2656
2673
|
}
|
|
2657
2674
|
function resolveSlackMessageText(message) {
|
|
2658
|
-
const messageText = normalizeOptionalString(message.text) ?? resolveSlackAttachmentFallbackText(message.attachments);
|
|
2675
|
+
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
2676
|
return resolveSlackMessageText$1({
|
|
2660
2677
|
...message,
|
|
2661
2678
|
text: messageText
|
|
@@ -2670,11 +2687,12 @@ async function resolveSlackThreadStarter(params) {
|
|
|
2670
2687
|
params.threadTs
|
|
2671
2688
|
]);
|
|
2672
2689
|
const cached = THREAD_STARTER_CACHE.get(cacheKey);
|
|
2673
|
-
if (cached) {
|
|
2690
|
+
if (cached && !params.refresh) {
|
|
2674
2691
|
const now = asDateTimestampMs(Date.now());
|
|
2675
2692
|
if (now !== void 0 && cached.expiresAt > now) return cached.value;
|
|
2676
2693
|
THREAD_STARTER_CACHE.delete(cacheKey);
|
|
2677
2694
|
}
|
|
2695
|
+
if (params.refresh) THREAD_STARTER_CACHE.delete(cacheKey);
|
|
2678
2696
|
try {
|
|
2679
2697
|
const message = (await params.client.conversations.replies({
|
|
2680
2698
|
channel: params.channelId,
|
|
@@ -2725,25 +2743,36 @@ async function resolveSlackThreadHistory(params) {
|
|
|
2725
2743
|
try {
|
|
2726
2744
|
do {
|
|
2727
2745
|
pagesFetched += 1;
|
|
2746
|
+
params.assertCurrent?.();
|
|
2728
2747
|
const response = await params.client.conversations.replies({
|
|
2729
2748
|
channel: params.channelId,
|
|
2730
2749
|
ts: params.threadTs,
|
|
2731
2750
|
limit: fetchLimit,
|
|
2732
|
-
inclusive:
|
|
2751
|
+
inclusive: false,
|
|
2752
|
+
...params.currentMessageTs ? { latest: params.currentMessageTs } : {},
|
|
2753
|
+
...params.oldest ? { oldest: params.oldest } : {},
|
|
2733
2754
|
...cursor ? { cursor } : {}
|
|
2734
2755
|
});
|
|
2756
|
+
params.assertCurrent?.();
|
|
2735
2757
|
for (const msg of response.messages ?? []) {
|
|
2758
|
+
const timestamp = resolveSlackTimestampMs(msg.ts);
|
|
2736
2759
|
const text = resolveSlackMessageText(msg);
|
|
2737
2760
|
if (!text && !msg.files?.length) continue;
|
|
2738
|
-
if (params.currentMessageTs && msg.ts
|
|
2761
|
+
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;
|
|
2762
|
+
if (retained.some(([entry]) => entry.ts === msg.ts)) continue;
|
|
2739
2763
|
retained.push([msg, text]);
|
|
2740
2764
|
}
|
|
2741
2765
|
if (retained.length > maxMessages) retained.splice(0, retained.length - maxMessages);
|
|
2742
2766
|
const next = response.response_metadata?.next_cursor;
|
|
2743
2767
|
cursor = typeof next === "string" && next.trim().length > 0 ? next.trim() : void 0;
|
|
2768
|
+
if (response.has_more && !cursor) {
|
|
2769
|
+
params.onOmission?.("Slack returned an incomplete thread page without a cursor");
|
|
2770
|
+
return [];
|
|
2771
|
+
}
|
|
2744
2772
|
} while (cursor && pagesFetched < SLACK_THREAD_HISTORY_MAX_PAGES);
|
|
2745
2773
|
if (cursor) {
|
|
2746
2774
|
logVerbose$1(`slack thread history capped channel=${params.channelId} ts=${params.threadTs} pages=${SLACK_THREAD_HISTORY_MAX_PAGES}`);
|
|
2775
|
+
params.onOmission?.("Slack thread exceeds the three-page automatic history budget");
|
|
2747
2776
|
return [];
|
|
2748
2777
|
}
|
|
2749
2778
|
return retained.map(([message, text]) => ({
|
|
@@ -2751,13 +2780,55 @@ async function resolveSlackThreadHistory(params) {
|
|
|
2751
2780
|
userId: message.user,
|
|
2752
2781
|
botId: message.bot_id,
|
|
2753
2782
|
ts: message.ts,
|
|
2754
|
-
files: message.files
|
|
2783
|
+
files: message.files,
|
|
2784
|
+
attachments: message.attachments
|
|
2755
2785
|
}));
|
|
2756
2786
|
} catch (err) {
|
|
2787
|
+
params.assertCurrent?.();
|
|
2788
|
+
params.onOmission?.(formatErrorMessage(err));
|
|
2757
2789
|
logVerbose$1(`slack thread history fetch failed channel=${params.channelId} ts=${params.threadTs}: ${formatErrorMessage(err)}`);
|
|
2758
2790
|
return [];
|
|
2759
2791
|
}
|
|
2760
2792
|
}
|
|
2793
|
+
/** Slack channel history is newest first, unlike chronological thread replies. */
|
|
2794
|
+
async function resolveSlackChannelHistory(params) {
|
|
2795
|
+
if (!Number.isFinite(params.limit) || params.limit <= 0) return [];
|
|
2796
|
+
const messages = [];
|
|
2797
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2798
|
+
let cursor;
|
|
2799
|
+
let scanned = 0;
|
|
2800
|
+
const maxPages = Math.ceil(params.limit / 200);
|
|
2801
|
+
for (let page = 0; page < maxPages; page += 1) {
|
|
2802
|
+
params.assertCurrent?.();
|
|
2803
|
+
const response = await params.client.conversations.history({
|
|
2804
|
+
channel: params.channelId,
|
|
2805
|
+
latest: params.currentMessageTs,
|
|
2806
|
+
...params.oldest ? { oldest: params.oldest } : {},
|
|
2807
|
+
inclusive: false,
|
|
2808
|
+
limit: Math.min(200, params.limit - scanned),
|
|
2809
|
+
...cursor ? { cursor } : {}
|
|
2810
|
+
});
|
|
2811
|
+
params.assertCurrent?.();
|
|
2812
|
+
for (const message of response.messages ?? []) {
|
|
2813
|
+
scanned += 1;
|
|
2814
|
+
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;
|
|
2815
|
+
seen.add(message.ts);
|
|
2816
|
+
const text = resolveSlackMessageText(message);
|
|
2817
|
+
if (!text && !message.files?.length) continue;
|
|
2818
|
+
messages.push({
|
|
2819
|
+
text: text ?? formatSlackFilePlaceholder(message.files),
|
|
2820
|
+
userId: message.user,
|
|
2821
|
+
botId: message.bot_id,
|
|
2822
|
+
ts: message.ts,
|
|
2823
|
+
files: message.files,
|
|
2824
|
+
attachments: message.attachments
|
|
2825
|
+
});
|
|
2826
|
+
}
|
|
2827
|
+
cursor = response.response_metadata?.next_cursor?.trim() || void 0;
|
|
2828
|
+
if (!cursor || scanned >= params.limit) break;
|
|
2829
|
+
}
|
|
2830
|
+
return messages.slice(0, params.limit).toReversed();
|
|
2831
|
+
}
|
|
2761
2832
|
//#endregion
|
|
2762
2833
|
//#region extensions/slack/src/monitor/message-handler/preflight-audio.ts
|
|
2763
2834
|
function isSlackAudioFile(file) {
|
|
@@ -2810,7 +2881,7 @@ const SLACK_MENTION_RESOLUTION_CONCURRENCY = 4;
|
|
|
2810
2881
|
const SLACK_MENTION_RESOLUTION_MAX_LOOKUPS_PER_MESSAGE = 20;
|
|
2811
2882
|
const SLACK_USER_MENTION_RE$1 = /<@([A-Z0-9]+)(?:\|[^>]+)?>/gi;
|
|
2812
2883
|
const MAX_SLACK_UNAVAILABLE_FILE_TEXT_CHARS = 2e3;
|
|
2813
|
-
const loadSlackMediaModule$1 = createLazyRuntimeModule(() => import("./actions-
|
|
2884
|
+
const loadSlackMediaModule$1 = createLazyRuntimeModule(() => import("./actions-DKCtBgCI.mjs").then((n) => n._));
|
|
2814
2885
|
function formatSlackUnavailableMedia(params) {
|
|
2815
2886
|
let fileReferences = params.files?.map((file) => `${formatSlackFileReference(file)} unavailable (${file.reason})`).join(", ");
|
|
2816
2887
|
if (fileReferences && fileReferences.length > MAX_SLACK_UNAVAILABLE_FILE_TEXT_CHARS) fileReferences = `${truncateUtf16Safe(fileReferences, MAX_SLACK_UNAVAILABLE_FILE_TEXT_CHARS)}; … (file references truncated)`;
|
|
@@ -2873,6 +2944,7 @@ async function resolveSlackMessageContent(params) {
|
|
|
2873
2944
|
readIdleTimeoutMs: params.mediaReadIdleTimeoutMs,
|
|
2874
2945
|
totalTimeoutMs: params.mediaTotalTimeoutMs,
|
|
2875
2946
|
abortSignal: params.abortSignal,
|
|
2947
|
+
assertCurrent: params.assertCurrent,
|
|
2876
2948
|
preloadedMedia: params.preloadedMedia
|
|
2877
2949
|
})) : null;
|
|
2878
2950
|
const effectiveDirectMedia = attachmentContent?.media.length ? attachmentContent.media : null;
|
|
@@ -2940,7 +3012,7 @@ async function resolveSlackMessageContent(params) {
|
|
|
2940
3012
|
//#region extensions/slack/src/monitor/message-handler/prepare-dm-history.ts
|
|
2941
3013
|
function resolveSlackDmHistoryLimit(params) {
|
|
2942
3014
|
const override = params.userId && params.account.config.dms?.[params.userId]?.historyLimit !== void 0 ? params.account.config.dms[params.userId]?.historyLimit : void 0;
|
|
2943
|
-
return
|
|
3015
|
+
return resolvePromptHistoryLimit(override ?? params.defaultLimit, 0);
|
|
2944
3016
|
}
|
|
2945
3017
|
async function resolveSlackDmHistoryContext(params) {
|
|
2946
3018
|
const maxMessages = Math.max(0, Math.floor(params.limit));
|
|
@@ -3063,8 +3135,172 @@ function formatSlackThreadLabelSnippet(text) {
|
|
|
3063
3135
|
return truncateUtf16Safe(text.replace(/\s+/g, " "), 80);
|
|
3064
3136
|
}
|
|
3065
3137
|
//#endregion
|
|
3138
|
+
//#region extensions/slack/src/monitor/message-handler/prepare-room-history.ts
|
|
3139
|
+
const SLACK_HISTORY_MEDIA_MAX_ATTACHMENTS = 4;
|
|
3140
|
+
const SLACK_HISTORY_MEDIA_MAX_BYTES = 10485760;
|
|
3141
|
+
const SLACK_HISTORY_MEDIA_IDLE_TIMEOUT_MS = 1e3;
|
|
3142
|
+
const SLACK_HISTORY_MEDIA_TOTAL_TIMEOUT_MS = 3e3;
|
|
3143
|
+
async function resolveSlackRoomHistory(params) {
|
|
3144
|
+
if (params.ctx.historyLimit <= 0 || !params.message.ts) return [];
|
|
3145
|
+
const warnOmission = (reason) => {
|
|
3146
|
+
params.ctx.logger.warn({
|
|
3147
|
+
accountId: params.ctx.accountId,
|
|
3148
|
+
teamId: params.eventScope?.teamId ?? params.ctx.teamId,
|
|
3149
|
+
channelId: params.message.channel,
|
|
3150
|
+
threadTs: params.threadTs,
|
|
3151
|
+
reason
|
|
3152
|
+
}, "Slack automatic history omitted");
|
|
3153
|
+
};
|
|
3154
|
+
try {
|
|
3155
|
+
params.assertCurrent();
|
|
3156
|
+
const request = {
|
|
3157
|
+
channelId: params.message.channel,
|
|
3158
|
+
client: params.eventScope?.client ?? params.ctx.app.client,
|
|
3159
|
+
currentMessageTs: params.message.ts,
|
|
3160
|
+
oldest: params.oldest,
|
|
3161
|
+
excludedMessageIds: params.excludedMessageIds,
|
|
3162
|
+
limit: Math.max(DEFAULT_GROUP_HISTORY_LIMIT, params.ctx.historyLimit),
|
|
3163
|
+
assertCurrent: params.assertCurrent
|
|
3164
|
+
};
|
|
3165
|
+
const messages = params.threadTs ? await resolveSlackThreadHistory({
|
|
3166
|
+
...request,
|
|
3167
|
+
threadTs: params.threadTs,
|
|
3168
|
+
onOmission: warnOmission
|
|
3169
|
+
}) : await resolveSlackChannelHistory(request);
|
|
3170
|
+
params.assertCurrent();
|
|
3171
|
+
const permitted = [];
|
|
3172
|
+
for (const message of messages) {
|
|
3173
|
+
if (isSlackThreadAuthorCurrentBot({
|
|
3174
|
+
identity: params.ctx,
|
|
3175
|
+
author: message
|
|
3176
|
+
})) continue;
|
|
3177
|
+
const user = message.userId ? await params.ctx.resolveUserName(message.userId, params.eventScope) : void 0;
|
|
3178
|
+
params.assertCurrent();
|
|
3179
|
+
const senderAllowed = resolveSlackUserAllowed({
|
|
3180
|
+
allowList: params.allowFromLower,
|
|
3181
|
+
teamId: params.eventScope?.teamId ?? params.ctx.teamId,
|
|
3182
|
+
userId: message.userId ?? message.botId,
|
|
3183
|
+
userName: user?.name,
|
|
3184
|
+
allowNameMatching: params.ctx.allowNameMatching
|
|
3185
|
+
});
|
|
3186
|
+
if (!shouldIncludeSupplementalContext({
|
|
3187
|
+
mode: params.contextVisibilityMode,
|
|
3188
|
+
kind: "history",
|
|
3189
|
+
senderAllowed
|
|
3190
|
+
})) continue;
|
|
3191
|
+
permitted.push({
|
|
3192
|
+
message,
|
|
3193
|
+
sender: user?.name ?? message.userId ?? `Bot (${message.botId ?? "unknown"})`
|
|
3194
|
+
});
|
|
3195
|
+
}
|
|
3196
|
+
const entries = [];
|
|
3197
|
+
let mediaRemaining = SLACK_HISTORY_MEDIA_MAX_ATTACHMENTS;
|
|
3198
|
+
for (const { message, sender } of permitted.slice(-params.ctx.historyLimit)) {
|
|
3199
|
+
const { media, attempted } = mediaRemaining > 0 && (message.files?.length || message.attachments?.length) ? await resolveSlackHistoryMedia({
|
|
3200
|
+
ctx: params.ctx,
|
|
3201
|
+
eventScope: params.eventScope,
|
|
3202
|
+
maxAttachments: mediaRemaining,
|
|
3203
|
+
assertCurrent: params.assertCurrent,
|
|
3204
|
+
abortSignal: params.abortSignal,
|
|
3205
|
+
message: {
|
|
3206
|
+
type: "message",
|
|
3207
|
+
channel: params.message.channel,
|
|
3208
|
+
ts: message.ts,
|
|
3209
|
+
user: message.userId,
|
|
3210
|
+
bot_id: message.botId,
|
|
3211
|
+
text: message.text,
|
|
3212
|
+
files: message.files,
|
|
3213
|
+
attachments: message.attachments
|
|
3214
|
+
}
|
|
3215
|
+
}) : {
|
|
3216
|
+
media: [],
|
|
3217
|
+
attempted: 0
|
|
3218
|
+
};
|
|
3219
|
+
params.assertCurrent();
|
|
3220
|
+
mediaRemaining -= attempted;
|
|
3221
|
+
entries.push({
|
|
3222
|
+
sender,
|
|
3223
|
+
body: message.text,
|
|
3224
|
+
timestamp: resolveSlackTimestampMs(message.ts),
|
|
3225
|
+
messageId: message.ts,
|
|
3226
|
+
...media.length > 0 ? { media } : {}
|
|
3227
|
+
});
|
|
3228
|
+
}
|
|
3229
|
+
return entries;
|
|
3230
|
+
} catch (error) {
|
|
3231
|
+
warnOmission(formatErrorMessage(error));
|
|
3232
|
+
return [];
|
|
3233
|
+
}
|
|
3234
|
+
}
|
|
3235
|
+
function isSlackImageFileCandidate(file) {
|
|
3236
|
+
if ((file.mimetype?.split(";")[0]?.trim().toLowerCase())?.startsWith("image/")) return true;
|
|
3237
|
+
return Boolean(mimeTypeFromFilePath(file.name)?.startsWith("image/"));
|
|
3238
|
+
}
|
|
3239
|
+
function sliceSlackImageFileCandidates(files, limit) {
|
|
3240
|
+
if (limit <= 0 || !files?.length) return [];
|
|
3241
|
+
return files.filter(isSlackImageFileCandidate).slice(0, limit);
|
|
3242
|
+
}
|
|
3243
|
+
function sliceSlackHistoryAttachmentCandidates(attachments, limit) {
|
|
3244
|
+
if (limit <= 0 || !attachments?.length) return [];
|
|
3245
|
+
const out = [];
|
|
3246
|
+
let remaining = limit;
|
|
3247
|
+
for (const attachment of attachments) {
|
|
3248
|
+
if (attachment.is_share !== true) continue;
|
|
3249
|
+
const hasImageUrl = Boolean(normalizeOptionalString(attachment.image_url));
|
|
3250
|
+
const files = sliceSlackImageFileCandidates(attachment.files, remaining - (hasImageUrl ? 1 : 0));
|
|
3251
|
+
if (!hasImageUrl && files.length === 0) continue;
|
|
3252
|
+
out.push({
|
|
3253
|
+
...attachment,
|
|
3254
|
+
files
|
|
3255
|
+
});
|
|
3256
|
+
remaining -= (hasImageUrl ? 1 : 0) + files.length;
|
|
3257
|
+
if (remaining <= 0) break;
|
|
3258
|
+
}
|
|
3259
|
+
return out;
|
|
3260
|
+
}
|
|
3261
|
+
function buildSlackHistoryMediaCandidateMessage(message, maxAttachments) {
|
|
3262
|
+
const files = sliceSlackImageFileCandidates(message.files, maxAttachments);
|
|
3263
|
+
const attachments = sliceSlackHistoryAttachmentCandidates(message.attachments, Math.max(0, maxAttachments - files.length));
|
|
3264
|
+
if (files.length === 0 && attachments.length === 0) return null;
|
|
3265
|
+
return {
|
|
3266
|
+
message: {
|
|
3267
|
+
...message,
|
|
3268
|
+
files,
|
|
3269
|
+
attachments
|
|
3270
|
+
},
|
|
3271
|
+
attempted: files.length + attachments.reduce((count, attachment) => count + (normalizeOptionalString(attachment.image_url) ? 1 : 0) + (attachment.files?.length ?? 0), 0)
|
|
3272
|
+
};
|
|
3273
|
+
}
|
|
3274
|
+
async function resolveSlackHistoryMedia(params) {
|
|
3275
|
+
const candidate = buildSlackHistoryMediaCandidateMessage(params.message, params.maxAttachments);
|
|
3276
|
+
if (!candidate) return {
|
|
3277
|
+
media: [],
|
|
3278
|
+
attempted: 0
|
|
3279
|
+
};
|
|
3280
|
+
const content = await resolveSlackMessageContent({
|
|
3281
|
+
message: candidate.message,
|
|
3282
|
+
isThreadReply: false,
|
|
3283
|
+
threadStarter: null,
|
|
3284
|
+
isBotMessage: Boolean(params.message.bot_id),
|
|
3285
|
+
client: params.eventScope?.client ?? params.ctx.app.client,
|
|
3286
|
+
botToken: params.ctx.botToken,
|
|
3287
|
+
mediaMaxBytes: Math.min(params.ctx.mediaMaxBytes, SLACK_HISTORY_MEDIA_MAX_BYTES),
|
|
3288
|
+
mediaReadIdleTimeoutMs: SLACK_HISTORY_MEDIA_IDLE_TIMEOUT_MS,
|
|
3289
|
+
mediaTotalTimeoutMs: SLACK_HISTORY_MEDIA_TOTAL_TIMEOUT_MS,
|
|
3290
|
+
assertCurrent: params.assertCurrent,
|
|
3291
|
+
abortSignal: params.abortSignal
|
|
3292
|
+
});
|
|
3293
|
+
return {
|
|
3294
|
+
media: await toInboundMediaFactsWithMetadata(content?.effectiveDirectMedia, {
|
|
3295
|
+
kind: "image",
|
|
3296
|
+
messageId: params.message.ts
|
|
3297
|
+
}),
|
|
3298
|
+
attempted: candidate.attempted
|
|
3299
|
+
};
|
|
3300
|
+
}
|
|
3301
|
+
//#endregion
|
|
3066
3302
|
//#region extensions/slack/src/monitor/message-handler/prepare-thread-context.ts
|
|
3067
|
-
const loadSlackMediaModule = createLazyRuntimeModule(() => import("./actions-
|
|
3303
|
+
const loadSlackMediaModule = createLazyRuntimeModule(() => import("./actions-DKCtBgCI.mjs").then((n) => n._));
|
|
3068
3304
|
const SLACK_THREAD_CONTEXT_USER_LOOKUP_CONCURRENCY = 4;
|
|
3069
3305
|
function resolveSlackThreadSessionFreshness(params) {
|
|
3070
3306
|
return params.ctx.channelRuntime?.session?.resolveEntryResetFreshness?.({
|
|
@@ -3079,23 +3315,6 @@ function resolveSlackThreadSessionFreshness(params) {
|
|
|
3079
3315
|
})
|
|
3080
3316
|
});
|
|
3081
3317
|
}
|
|
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
3318
|
async function resolveSlackThreadUserMap(params) {
|
|
3100
3319
|
const uniqueUserIds = [];
|
|
3101
3320
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -3155,16 +3374,17 @@ async function resolveSlackThreadContextData(params) {
|
|
|
3155
3374
|
};
|
|
3156
3375
|
const starter = params.threadStarter;
|
|
3157
3376
|
const starterSenderName = params.allowNameMatching && params.allowFromLower.length > 0 && starter?.userId ? (await params.ctx.resolveUserName(starter.userId, params.eventScope))?.name : void 0;
|
|
3377
|
+
params.assertHistoryCurrent?.();
|
|
3158
3378
|
const starterIsCurrentBot = Boolean(starter && isCurrentBotAuthor({
|
|
3159
3379
|
userId: starter.userId,
|
|
3160
3380
|
botId: starter.botId
|
|
3161
3381
|
}));
|
|
3162
|
-
const starterAllowed = !starter || !starterIsCurrentBot &&
|
|
3163
|
-
|
|
3382
|
+
const starterAllowed = !starter || !starterIsCurrentBot && resolveSlackUserAllowed({
|
|
3383
|
+
allowList: params.allowFromLower,
|
|
3384
|
+
teamId: params.eventScope?.teamId ?? params.ctx.teamId,
|
|
3164
3385
|
allowNameMatching: params.allowNameMatching,
|
|
3165
|
-
userId: starter.userId,
|
|
3166
|
-
userName: starterSenderName
|
|
3167
|
-
botId: starter.botId
|
|
3386
|
+
userId: starter.userId ?? starter.botId,
|
|
3387
|
+
userName: starterSenderName
|
|
3168
3388
|
});
|
|
3169
3389
|
const includeStarterContext = !starter || !starterIsCurrentBot && shouldIncludeSupplementalContext({
|
|
3170
3390
|
mode: params.contextVisibilityMode,
|
|
@@ -3177,12 +3397,16 @@ async function resolveSlackThreadContextData(params) {
|
|
|
3177
3397
|
threadLabel = `Slack thread ${params.roomLabel}${snippet ? `: ${snippet}` : ""}`;
|
|
3178
3398
|
if (shouldSeedInitialThreadContext && !params.effectiveDirectMedia && starter.files && starter.files.length > 0) {
|
|
3179
3399
|
const { resolveSlackAttachmentContent } = await loadSlackMediaModule();
|
|
3400
|
+
params.assertHistoryCurrent?.();
|
|
3180
3401
|
const attachmentContent = await resolveSlackAttachmentContent({
|
|
3181
3402
|
files: starter.files,
|
|
3182
3403
|
client: params.eventScope?.client ?? params.ctx.app.client,
|
|
3183
3404
|
token: params.ctx.botToken,
|
|
3184
|
-
maxBytes: params.ctx.mediaMaxBytes
|
|
3405
|
+
maxBytes: params.ctx.mediaMaxBytes,
|
|
3406
|
+
assertCurrent: params.assertHistoryCurrent,
|
|
3407
|
+
abortSignal: params.abortSignal
|
|
3185
3408
|
});
|
|
3409
|
+
params.assertHistoryCurrent?.();
|
|
3186
3410
|
threadStarterMedia = attachmentContent?.media.length ? attachmentContent.media : null;
|
|
3187
3411
|
if (attachmentContent) threadStarterBody = formatSlackUnavailableMedia({
|
|
3188
3412
|
body: threadStarterBody,
|
|
@@ -3210,16 +3434,36 @@ async function resolveSlackThreadContextData(params) {
|
|
|
3210
3434
|
});
|
|
3211
3435
|
logVerbose("slack: retained current-bot thread starter as assistant root context");
|
|
3212
3436
|
}
|
|
3213
|
-
const threadInitialHistoryLimit = params.account.config?.thread?.initialHistoryLimit ?? 20;
|
|
3437
|
+
const threadInitialHistoryLimit = Math.min(params.account.config?.thread?.initialHistoryLimit ?? 20, params.historyLimit ?? Number.POSITIVE_INFINITY);
|
|
3214
3438
|
if (threadInitialHistoryLimit > 0 && shouldLoadInitialThreadHistory) {
|
|
3215
3439
|
const currentBotRootTs = starter?.ts ?? params.threadTs;
|
|
3440
|
+
let historyOmitted = false;
|
|
3216
3441
|
const threadHistory = await resolveSlackThreadHistory({
|
|
3217
3442
|
channelId: params.message.channel,
|
|
3218
3443
|
threadTs: params.threadTs,
|
|
3219
3444
|
client: params.eventScope?.client ?? params.ctx.app.client,
|
|
3220
3445
|
currentMessageTs: params.message.ts,
|
|
3221
|
-
limit: threadInitialHistoryLimit
|
|
3446
|
+
limit: threadInitialHistoryLimit,
|
|
3447
|
+
excludedMessageIds: params.excludedMessageIds,
|
|
3448
|
+
assertCurrent: params.assertHistoryCurrent,
|
|
3449
|
+
onOmission: (reason) => {
|
|
3450
|
+
historyOmitted = true;
|
|
3451
|
+
params.ctx.logger.warn({
|
|
3452
|
+
channelId: params.message.channel,
|
|
3453
|
+
threadTs: params.threadTs,
|
|
3454
|
+
teamId: params.eventScope?.teamId ?? params.ctx.teamId,
|
|
3455
|
+
accountId: params.account.accountId,
|
|
3456
|
+
reason
|
|
3457
|
+
}, "Slack automatic thread history omitted");
|
|
3458
|
+
}
|
|
3222
3459
|
});
|
|
3460
|
+
if (historyOmitted) return {
|
|
3461
|
+
threadStarterBody,
|
|
3462
|
+
threadHistoryBody,
|
|
3463
|
+
shouldSeedInitialThreadContext,
|
|
3464
|
+
threadLabel,
|
|
3465
|
+
threadStarterMedia
|
|
3466
|
+
};
|
|
3223
3467
|
const enrichedStarter = starter && threadStarterBody && threadStarterBody !== starter.text ? {
|
|
3224
3468
|
...starter,
|
|
3225
3469
|
text: threadStarterBody,
|
|
@@ -3248,6 +3492,7 @@ async function resolveSlackThreadContextData(params) {
|
|
|
3248
3492
|
messages: threadHistoryWithoutCurrentBot,
|
|
3249
3493
|
eventScope: params.eventScope
|
|
3250
3494
|
}) : /* @__PURE__ */ new Map();
|
|
3495
|
+
params.assertHistoryCurrent?.();
|
|
3251
3496
|
const { items: filteredThreadHistory, omitted: omittedHistoryCount } = params.contextVisibilityMode === "all" ? {
|
|
3252
3497
|
items: threadHistoryWithoutCurrentBot,
|
|
3253
3498
|
omitted: 0
|
|
@@ -3261,29 +3506,30 @@ async function resolveSlackThreadContextData(params) {
|
|
|
3261
3506
|
botId: historyMsg.botId
|
|
3262
3507
|
})) return true;
|
|
3263
3508
|
const msgUser = historyMsg.userId ? userMapForFilter.get(historyMsg.userId) : null;
|
|
3264
|
-
return
|
|
3265
|
-
|
|
3509
|
+
return resolveSlackUserAllowed({
|
|
3510
|
+
allowList: params.allowFromLower,
|
|
3511
|
+
teamId: params.eventScope?.teamId ?? params.ctx.teamId,
|
|
3266
3512
|
allowNameMatching: params.allowNameMatching,
|
|
3267
|
-
userId: historyMsg.userId,
|
|
3268
|
-
userName: msgUser?.name
|
|
3269
|
-
botId: historyMsg.botId
|
|
3513
|
+
userId: historyMsg.userId ?? historyMsg.botId,
|
|
3514
|
+
userName: msgUser?.name
|
|
3270
3515
|
});
|
|
3271
3516
|
}
|
|
3272
3517
|
});
|
|
3273
3518
|
const userMap = await resolveSlackThreadUserMap({
|
|
3274
3519
|
ctx: params.ctx,
|
|
3275
|
-
messages: filteredThreadHistory
|
|
3520
|
+
messages: filteredThreadHistory,
|
|
3521
|
+
eventScope: params.eventScope
|
|
3276
3522
|
});
|
|
3523
|
+
params.assertHistoryCurrent?.();
|
|
3277
3524
|
if (omittedHistoryCount > 0 || omittedCurrentBotHistoryCount > 0) logVerbose(`slack: omitted ${omittedHistoryCount + omittedCurrentBotHistoryCount} thread message(s) from context (mode=${params.contextVisibilityMode})`);
|
|
3278
3525
|
const historyParts = [];
|
|
3279
3526
|
for (const historyMsg of filteredThreadHistory) {
|
|
3280
3527
|
const msgUser = historyMsg.userId ? userMap.get(historyMsg.userId) : null;
|
|
3281
|
-
const isOtherBot = Boolean(historyMsg.botId) && historyMsg.botId !== params.ctx.botId;
|
|
3282
3528
|
const isCurrentBot = isCurrentBotAuthor({
|
|
3283
3529
|
userId: historyMsg.userId,
|
|
3284
3530
|
botId: historyMsg.botId
|
|
3285
3531
|
});
|
|
3286
|
-
const role = isCurrentBot ||
|
|
3532
|
+
const role = isCurrentBot || historyMsg.botId ? "assistant" : "user";
|
|
3287
3533
|
const msgSenderName = isCurrentBot ? "Bot (this assistant)" : msgUser?.name ?? (historyMsg.botId ? `Bot (${historyMsg.botId})` : "Unknown");
|
|
3288
3534
|
const msgWithId = `${historyMsg.ts === currentBotRootTs && threadStarterBody ? threadStarterBody : historyMsg.text}\n[slack message id: ${historyMsg.ts ?? "unknown"} channel: ${params.message.channel}]`;
|
|
3289
3535
|
historyParts.push(formatInboundEnvelope({
|
|
@@ -3382,10 +3628,6 @@ const SLACK_ANY_MENTION_RE = /<@[^>]+>|<!subteam\^[^>]+>/;
|
|
|
3382
3628
|
const SLACK_USER_MENTION_RE = /<@([^>|]+)(?:\|[^>]+)?>/g;
|
|
3383
3629
|
const SLACK_SUBTEAM_MENTION_RE = /<!subteam\^([^>|]+)(?:\|[^>]+)?>/g;
|
|
3384
3630
|
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
3631
|
const SLACK_CHANNEL_ACCESS_DOCS_URL = "https://docs.openclaw.ai/channels/slack#access-control-and-routing";
|
|
3390
3632
|
function resolveSlackGroupSessionSubject(params) {
|
|
3391
3633
|
const channelName = normalizeOptionalString(params.channelName);
|
|
@@ -3397,9 +3639,8 @@ function recordString(record, key) {
|
|
|
3397
3639
|
return normalizeOptionalString(record?.[key]);
|
|
3398
3640
|
}
|
|
3399
3641
|
function recordNullableString(record, key) {
|
|
3400
|
-
|
|
3401
|
-
|
|
3402
|
-
return normalizeOptionalString(record[key]);
|
|
3642
|
+
const value = record?.[key];
|
|
3643
|
+
return value === null ? null : normalizeOptionalString(value);
|
|
3403
3644
|
}
|
|
3404
3645
|
function mergeSlackAssistantThreadContext(primary, fallback) {
|
|
3405
3646
|
if (!primary) return fallback;
|
|
@@ -3465,61 +3706,6 @@ function resolveCachedMentionRegexes(ctx, agentId, options) {
|
|
|
3465
3706
|
byAgent.set(key, built);
|
|
3466
3707
|
return built;
|
|
3467
3708
|
}
|
|
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
3709
|
function collectUniqueSlackMentionIds(text, regex) {
|
|
3524
3710
|
const ids = [];
|
|
3525
3711
|
regex.lastIndex = 0;
|
|
@@ -3820,7 +4006,7 @@ async function prepareSlackMessage(params) {
|
|
|
3820
4006
|
let mentionRegexes = buildPolicyMentionRegexes(routing.route.agentId);
|
|
3821
4007
|
let wasMentioned = resolveWasMentioned(mentionRegexes);
|
|
3822
4008
|
const hasBoundSession = Boolean(routing.runtimeBoundSessionKey || routing.configuredBindingSessionKey);
|
|
3823
|
-
let { route, runtimeBinding, replyToMode, threadContext, threadTs, isThreadReply, threadKeys, sessionKey
|
|
4009
|
+
let { route, runtimeBinding, replyToMode, threadContext, threadTs, isThreadReply, threadKeys, sessionKey } = routing;
|
|
3824
4010
|
const { configuredBinding, configuredBindingSessionKey } = routing;
|
|
3825
4011
|
const isAssistantThreadMessage = Boolean(isDirectMessage && messageAssistantThreadContext);
|
|
3826
4012
|
const forcedAssistantReplyThreadTs = Boolean(assistantThreadContext?.threadTs && (isThreadReply || isAssistantThreadMessage || replyToMode !== "off")) ? assistantThreadContext?.threadTs : void 0;
|
|
@@ -3858,65 +4044,14 @@ async function prepareSlackMessage(params) {
|
|
|
3858
4044
|
teamId: opts.eventScope?.teamId
|
|
3859
4045
|
}));
|
|
3860
4046
|
}
|
|
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
4047
|
let threadStarterPromise;
|
|
3914
4048
|
const getThreadStarter = () => {
|
|
3915
4049
|
threadStarterPromise ??= isThreadReply && threadTs ? resolveSlackThreadStarter({
|
|
3916
4050
|
channelId: message.channel,
|
|
3917
4051
|
threadTs,
|
|
3918
4052
|
client: slackClient,
|
|
3919
|
-
workspaceScope: threadStarterWorkspaceScope
|
|
4053
|
+
workspaceScope: threadStarterWorkspaceScope,
|
|
4054
|
+
refresh: isRoomish && ctx.historyLimit > 0
|
|
3920
4055
|
}) : Promise.resolve(null);
|
|
3921
4056
|
return threadStarterPromise;
|
|
3922
4057
|
};
|
|
@@ -4067,7 +4202,7 @@ async function prepareSlackMessage(params) {
|
|
|
4067
4202
|
})) groupThread = void 0;
|
|
4068
4203
|
mentionRegexes = buildPolicyMentionRegexes(routing.route.agentId);
|
|
4069
4204
|
wasMentioned = resolveWasMentioned(mentionRegexes);
|
|
4070
|
-
({route, runtimeBinding, replyToMode, threadContext, threadTs, isThreadReply, threadKeys, sessionKey
|
|
4205
|
+
({route, runtimeBinding, replyToMode, threadContext, threadTs, isThreadReply, threadKeys, sessionKey} = routing);
|
|
4071
4206
|
canDetectMention = Boolean(groupThread) || Boolean(ctx.botUserId) || mentionRegexes.length > 0;
|
|
4072
4207
|
}
|
|
4073
4208
|
if (preflightAudioTranscript && !wasMentioned) {
|
|
@@ -4106,19 +4241,10 @@ async function prepareSlackMessage(params) {
|
|
|
4106
4241
|
if (isBotMessage && allowBotsMode === "mentions") {
|
|
4107
4242
|
if (!(isDirectMessage || effectiveWasMentioned || shouldBypassMention)) return drop("bot-missing-mention");
|
|
4108
4243
|
}
|
|
4109
|
-
if (isRoom && shouldRequireMention && !canDetectMention && !effectiveWasMentioned)
|
|
4110
|
-
await recordDroppedHistory("slack-mention-detection-unavailable");
|
|
4111
|
-
return drop("mention-detection-unavailable");
|
|
4112
|
-
}
|
|
4244
|
+
if (isRoom && shouldRequireMention && !canDetectMention && !effectiveWasMentioned) return drop("mention-detection-unavailable");
|
|
4113
4245
|
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
|
-
}
|
|
4246
|
+
if (isRoom && ignoreOtherMentions && Boolean(ctx.botUserId) && hasAnyMention && !wasMentioned) return drop("other-mention");
|
|
4247
|
+
if (isRoom && shouldRequireMention && mentionDecision.shouldSkip) return drop("missing-mention");
|
|
4122
4248
|
const chatType = resolveSlackChatType(conversation.resolvedChannelType);
|
|
4123
4249
|
const inboundEventKind = classifyChannelInboundEvent({
|
|
4124
4250
|
conversation: { kind: chatType },
|
|
@@ -4200,16 +4326,34 @@ async function prepareSlackMessage(params) {
|
|
|
4200
4326
|
const textWithId = `${bodyForAgent}\n[slack message id: ${message.ts} channel: ${message.channel}${threadInfo}]`;
|
|
4201
4327
|
const storePath = resolveStorePath(ctx.cfg.session?.store, { agentId: route.agentId });
|
|
4202
4328
|
const envelopeOptions = resolveEnvelopeFormatOptions(ctx.cfg);
|
|
4329
|
+
const effectiveMessageThreadId = assistantThreadContext?.threadTs ?? agentViewThreadTs ?? threadContext.messageThreadId;
|
|
4330
|
+
const boundMessageThreadId = directThreadRoutedToDmSession ? void 0 : effectiveMessageThreadId;
|
|
4331
|
+
messageIngress = await resolveMessageIngress({
|
|
4332
|
+
agentId: route.agentId,
|
|
4333
|
+
sessionKey,
|
|
4334
|
+
nativeChannelId: message.channel,
|
|
4335
|
+
messageId: threadContext.messageTs,
|
|
4336
|
+
inboundEventKind
|
|
4337
|
+
}, boundMessageThreadId);
|
|
4338
|
+
if (messageIngress.ingress.admission !== "dispatch") return drop("final-route-denied");
|
|
4203
4339
|
const sessionEntry = getSessionEntry({
|
|
4204
4340
|
storePath,
|
|
4205
4341
|
sessionKey
|
|
4206
4342
|
});
|
|
4207
4343
|
const previousTimestamp = sessionEntry?.updatedAt;
|
|
4208
|
-
|
|
4209
|
-
|
|
4210
|
-
|
|
4211
|
-
|
|
4212
|
-
|
|
4344
|
+
const excludedMessageIds = new Set(opts.sourceMessageIds);
|
|
4345
|
+
if (message.ts) excludedMessageIds.add(message.ts);
|
|
4346
|
+
const isHistorySessionCurrent = () => {
|
|
4347
|
+
const current = getSessionEntry({
|
|
4348
|
+
storePath,
|
|
4349
|
+
sessionKey
|
|
4350
|
+
});
|
|
4351
|
+
return current?.sessionId === sessionEntry?.sessionId && current?.lifecycleRevision === sessionEntry?.lifecycleRevision && current?.sessionStartedAt === sessionEntry?.sessionStartedAt && current?.updatedAt === 0 === (sessionEntry?.updatedAt === 0);
|
|
4352
|
+
};
|
|
4353
|
+
const assertHistoryCurrent = () => {
|
|
4354
|
+
opts.abortSignal?.throwIfAborted();
|
|
4355
|
+
if (opts.isRuntimePolicyCurrent?.() === false || !isHistorySessionCurrent()) throw new Error("Slack history policy or session changed during recovery");
|
|
4356
|
+
};
|
|
4213
4357
|
const dmHistoryLimit = isDirectMessage ? resolveSlackDmHistoryLimit({
|
|
4214
4358
|
account,
|
|
4215
4359
|
userId: message.user,
|
|
@@ -4240,26 +4384,12 @@ async function prepareSlackMessage(params) {
|
|
|
4240
4384
|
inboundHistory: void 0
|
|
4241
4385
|
};
|
|
4242
4386
|
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
4387
|
const { channelMetadata, groupSystemPrompt } = resolveSlackRoomContextHints({
|
|
4258
4388
|
isRoomish,
|
|
4259
4389
|
channelInfo,
|
|
4260
4390
|
channelConfig
|
|
4261
4391
|
});
|
|
4262
|
-
const
|
|
4392
|
+
const threadContextData = await resolveSlackThreadContextData({
|
|
4263
4393
|
ctx,
|
|
4264
4394
|
agentId: route.agentId,
|
|
4265
4395
|
account,
|
|
@@ -4277,25 +4407,66 @@ async function prepareSlackMessage(params) {
|
|
|
4277
4407
|
contextVisibilityMode,
|
|
4278
4408
|
envelopeOptions,
|
|
4279
4409
|
effectiveDirectMedia,
|
|
4280
|
-
eventScope: opts.eventScope
|
|
4410
|
+
eventScope: opts.eventScope,
|
|
4411
|
+
historyLimit: isRoomish ? ctx.historyLimit : void 0,
|
|
4412
|
+
excludedMessageIds,
|
|
4413
|
+
assertHistoryCurrent,
|
|
4414
|
+
abortSignal: opts.abortSignal
|
|
4281
4415
|
});
|
|
4416
|
+
const { threadLabel, threadStarterMedia } = threadContextData;
|
|
4417
|
+
let { threadStarterBody, threadHistoryBody, shouldSeedInitialThreadContext } = threadContextData;
|
|
4418
|
+
const threadScopedHistory = isThreadReply && ctx.threadHistoryScope === "thread";
|
|
4419
|
+
let roomHistory = [];
|
|
4420
|
+
if (isRoomish && ctx.historyLimit > 0 && (!threadScopedHistory || !shouldSeedInitialThreadContext)) {
|
|
4421
|
+
if (sessionEntry?.updatedAt !== 0) roomHistory = await resolveSlackRoomHistory({
|
|
4422
|
+
ctx,
|
|
4423
|
+
message,
|
|
4424
|
+
threadTs: threadScopedHistory ? threadTs : void 0,
|
|
4425
|
+
oldest: sessionEntry?.sessionStartedAt ? (sessionEntry.sessionStartedAt / 1e3).toFixed(6) : void 0,
|
|
4426
|
+
excludedMessageIds,
|
|
4427
|
+
allowFromLower: threadContextAllowFromLower,
|
|
4428
|
+
contextVisibilityMode,
|
|
4429
|
+
eventScope: opts.eventScope,
|
|
4430
|
+
assertCurrent: assertHistoryCurrent,
|
|
4431
|
+
abortSignal: opts.abortSignal
|
|
4432
|
+
});
|
|
4433
|
+
}
|
|
4282
4434
|
const effectiveMedia = effectiveDirectMedia ?? threadStarterMedia;
|
|
4283
|
-
|
|
4284
|
-
|
|
4285
|
-
|
|
4435
|
+
let inboundMedia = await toInboundMediaFactsWithMetadata(effectiveMedia, { transcribed: (entry) => effectiveMedia === effectiveDirectMedia && entry === preflightAudioMedia });
|
|
4436
|
+
opts.abortSignal?.throwIfAborted();
|
|
4437
|
+
if (opts.isRuntimePolicyCurrent?.() === false) return drop("final-route-denied");
|
|
4438
|
+
if (isRoomish && ctx.historyLimit > 0 && !isHistorySessionCurrent()) {
|
|
4439
|
+
roomHistory = [];
|
|
4440
|
+
threadHistoryBody = void 0;
|
|
4441
|
+
threadStarterBody = void 0;
|
|
4442
|
+
shouldSeedInitialThreadContext = false;
|
|
4443
|
+
if (effectiveMedia === threadStarterMedia) inboundMedia = [];
|
|
4444
|
+
ctx.logger.warn({
|
|
4445
|
+
channelId: message.channel,
|
|
4446
|
+
sessionKey
|
|
4447
|
+
}, "Slack automatic history omitted after session changed");
|
|
4448
|
+
}
|
|
4449
|
+
combinedBody = buildHistoryContextFromEntries({
|
|
4450
|
+
entries: roomHistory,
|
|
4451
|
+
currentMessage: combinedBody,
|
|
4452
|
+
historyKind: "recent",
|
|
4453
|
+
excludeLast: false,
|
|
4454
|
+
formatEntry: (entry) => formatInboundEnvelope({
|
|
4455
|
+
channel: "Slack",
|
|
4456
|
+
from: roomLabel,
|
|
4457
|
+
timestamp: entry.timestamp,
|
|
4458
|
+
body: `${entry.body} [id:${entry.messageId} channel:${message.channel}]`,
|
|
4459
|
+
chatType: "channel",
|
|
4460
|
+
senderLabel: entry.sender,
|
|
4461
|
+
envelope: envelopeOptions
|
|
4462
|
+
})
|
|
4463
|
+
});
|
|
4464
|
+
const inboundHistory = isRoomish && ctx.historyLimit > 0 ? buildInboundHistoryFromEntries({
|
|
4465
|
+
entries: roomHistory,
|
|
4286
4466
|
limit: ctx.historyLimit
|
|
4287
4467
|
}) : dmHistoryContext.inboundHistory;
|
|
4288
4468
|
const commandBody = textForCommandDetection.trim();
|
|
4289
4469
|
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
4470
|
const agentContextEntities = isAgentViewMessage ? normalizeSlackAppContextEntities(message.app_context) : [];
|
|
4300
4471
|
const ctxPayload = (ctx.buildContext ?? buildChannelInboundEventContext)({
|
|
4301
4472
|
channelIngress: messageIngress,
|
|
@@ -4328,9 +4499,7 @@ async function prepareSlackMessage(params) {
|
|
|
4328
4499
|
avatar: conversationAvatar
|
|
4329
4500
|
},
|
|
4330
4501
|
route: {
|
|
4331
|
-
|
|
4332
|
-
dmScope: route.dmScope,
|
|
4333
|
-
accountId: route.accountId,
|
|
4502
|
+
...route,
|
|
4334
4503
|
routeSessionKey: route.sessionKey,
|
|
4335
4504
|
dispatchSessionKey: sessionKey,
|
|
4336
4505
|
parentSessionKey: threadKeys.parentSessionKey
|
|
@@ -4349,7 +4518,10 @@ async function prepareSlackMessage(params) {
|
|
|
4349
4518
|
commandBody,
|
|
4350
4519
|
inboundHistory
|
|
4351
4520
|
},
|
|
4352
|
-
sessionTranscript: {
|
|
4521
|
+
sessionTranscript: {
|
|
4522
|
+
historyLimit: isRoomish ? ctx.historyLimit : dmHistoryLimit,
|
|
4523
|
+
historyKind: isRoomish ? "recent" : "pending"
|
|
4524
|
+
},
|
|
4353
4525
|
access: {
|
|
4354
4526
|
mentions: {
|
|
4355
4527
|
canDetectMention: isRoomish,
|
|
@@ -4404,16 +4576,6 @@ async function prepareSlackMessage(params) {
|
|
|
4404
4576
|
}
|
|
4405
4577
|
});
|
|
4406
4578
|
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
4579
|
const pinnedMainDmOwner = isDirectMessage ? resolvePinnedMainDmOwnerFromAllowlist({
|
|
4418
4580
|
dmScope: cfg.session?.dmScope,
|
|
4419
4581
|
allowFrom: allowFromLower,
|
|
@@ -4467,13 +4629,7 @@ async function prepareSlackMessage(params) {
|
|
|
4467
4629
|
sessionKey
|
|
4468
4630
|
}, "failed updating session meta");
|
|
4469
4631
|
}
|
|
4470
|
-
}
|
|
4471
|
-
history: isRoomish && shouldRequireMention ? {
|
|
4472
|
-
isGroup: true,
|
|
4473
|
-
historyKey,
|
|
4474
|
-
historyMap: ctx.channelHistories,
|
|
4475
|
-
limit: ctx.historyLimit
|
|
4476
|
-
} : void 0
|
|
4632
|
+
}
|
|
4477
4633
|
},
|
|
4478
4634
|
replyToMode,
|
|
4479
4635
|
...forcedReplyThreadTs ? { forcedReplyThreadTs } : {},
|
|
@@ -4481,7 +4637,6 @@ async function prepareSlackMessage(params) {
|
|
|
4481
4637
|
requireMention: shouldRequireMention,
|
|
4482
4638
|
isDirectMessage,
|
|
4483
4639
|
isRoomish,
|
|
4484
|
-
historyKey,
|
|
4485
4640
|
preview,
|
|
4486
4641
|
ackReactionMessageTs,
|
|
4487
4642
|
ackReactionValue,
|