@openclaw/discord 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/{activities-api-DBwRt5ES.mjs → activities-api-COU4-0nR.mjs} +4 -4
- package/dist/.setup/{approval-handler.runtime-Du3n5ypX.mjs → approval-handler.runtime-CbBktBb4.mjs} +5 -5
- package/dist/.setup/{approval-message-updates-BN7JtScm.mjs → approval-message-updates-jf9zMaIC.mjs} +1 -1
- package/dist/.setup/{audit-C8uaKoa9.mjs → audit-vKbh-LFR.mjs} +3 -3
- package/dist/.setup/{channel-ChKdlBgH.mjs → channel-Dv4e3Jpc.mjs} +19 -16
- package/dist/.setup/{channel-actions.runtime-CJmiFfps.mjs → channel-actions.runtime-leZuw01r.mjs} +13 -7
- package/dist/.setup/{channel.setup-BlC3-Kzz.mjs → channel.setup-0NX6FFwi.mjs} +1 -1
- package/dist/.setup/{components-MqMWUWnE.mjs → components-yBEb75bB.mjs} +1 -2
- package/dist/.setup/{conversation-binding-route-_rz33QHO.mjs → conversation-binding-route-B7qImK_b.mjs} +6 -3
- package/dist/.setup/{doctor-DxcdkXzz.mjs → doctor-D1R-uFIu.mjs} +2 -2
- package/dist/.setup/{handle-action.guild-admin-DAFyh_yV.mjs → handle-action.guild-admin-DcFa8NwA.mjs} +3 -3
- package/dist/.setup/{message-handler-DnUrDpaU.mjs → message-handler-X6ejmbtY.mjs} +6 -5
- package/dist/.setup/{message-handler.preflight-CtqaF_fb.mjs → message-handler.preflight-DE_POxFc.mjs} +14 -117
- package/dist/.setup/message-handler.preflight-pluralkit-8Xji34AF.mjs +143 -0
- package/dist/.setup/{message-handler.process-Dz1xvuQU.mjs → message-handler.process-CCmIVnxy.mjs} +387 -317
- package/dist/.setup/{outbound-adapter-C8v79z9Z.mjs → outbound-adapter-ClIgmu4F.mjs} +5 -5
- package/dist/.setup/{outbound-session-route-CqWbuMOm.mjs → outbound-session-route-VulUE0yV.mjs} +7 -6
- package/dist/.setup/{preflight-audio-DrnqFA8U.mjs → preflight-audio-DHGIHEpv.mjs} +2 -1
- package/dist/.setup/{provider-72zIvN-i.mjs → provider-iOf73HW-.mjs} +425 -286
- package/dist/.setup/{provider-session.runtime-BW7QrF5C.mjs → provider-session.runtime-DrGAYnZv.mjs} +3 -3
- package/dist/.setup/provider.runtime-BmjW_pIw.mjs +2 -0
- package/dist/.setup/{realtime-session.runtime-DTccTgTM.mjs → realtime-session.runtime-Dz8uVutq.mjs} +338 -297
- package/dist/.setup/receive-recovery-DHst8WRx.mjs +517 -0
- package/dist/.setup/{retry-DBfcEgmO.mjs → retry-BEYkDy0P.mjs} +78 -13
- package/dist/.setup/{runtime-SchNfUsQ.mjs → runtime-B8lJfyrA.mjs} +30 -11
- package/dist/.setup/{runtime-BVoa7hhx.mjs → runtime-DisDbixd.mjs} +1 -1
- package/dist/.setup/{send-CKDczUNL.mjs → send-CIBzvXjS.mjs} +23 -9
- package/dist/.setup/{send.components-DWQjXhPV.mjs → send.components-ChY21qr-.mjs} +4 -4
- package/dist/.setup/{send.outbound-D0hQ7s50.mjs → send.outbound-QTyuFupn.mjs} +15 -16
- package/dist/.setup/{send.shared-Zwx6BxQ5.mjs → send.shared-VNvWfX2T.mjs} +2 -2
- package/dist/.setup/setup-plugin-api-Dvr41dyx.mjs +3 -0
- package/dist/.setup/{shared-CaA3Vv4n.mjs → shared-DHPDaMSx.mjs} +1 -1
- package/dist/.setup/{subagent-hooks-Bired9q6.mjs → subagent-hooks-CjW7r8Pe.mjs} +1 -1
- package/dist/.setup/{target-resolver-B6MrxbYv.mjs → target-resolver-BXpy6VT8.mjs} +1 -1
- package/dist/.setup/targets-CvemhN3i.mjs +3 -0
- package/dist/.setup/{thread-bindings-CK5272V3.mjs → thread-bindings-CEh2dhqP.mjs} +3 -3
- package/dist/.setup/{thread-bindings.manager-eexkKyrG.mjs → thread-bindings.manager-ve-i6oqt.mjs} +94 -45
- package/dist/.setup/{transcripts-source-CuWYgayu.mjs → transcripts-source-DVegW0WI.mjs} +61 -7
- package/dist/.setup/{voice-runtime-DHVQ2mFz.mjs → voice-runtime-elTtjEIG.mjs} +553 -901
- package/dist/action-runtime-api.js +1 -1
- package/dist/activities-api.js +1 -1
- package/dist/api.js +10 -10
- package/dist/channel-plugin-api.js +1 -1
- package/dist/index.js +1 -1
- package/dist/runtime-api.js +12 -12
- package/dist/setup-entry.js +1 -1
- package/dist/setup-plugin-api.js +1 -1
- package/dist/src/voice/audio-worker.runtime.js +1065 -0
- package/dist/subagent-hooks-api.js +1 -1
- package/dist/transcripts-source-api.js +1 -1
- package/node_modules/@napi-rs/wasm-runtime/dist/emnapi-plugins.cjs +8 -4
- package/node_modules/@napi-rs/wasm-runtime/dist/emnapi-plugins.js +8 -4
- package/node_modules/@napi-rs/wasm-runtime/dist/fs-proxy.cjs +1 -1
- package/node_modules/@napi-rs/wasm-runtime/dist/fs.js +770 -695
- package/node_modules/@napi-rs/wasm-runtime/fs-proxy.js +3 -2
- package/node_modules/@napi-rs/wasm-runtime/package.json +1 -1
- package/node_modules/@tybys/wasm-util/LICENSE +21 -0
- package/node_modules/@tybys/wasm-util/package.json +1 -1
- package/node_modules/@types/node/README.md +1 -1
- package/node_modules/@types/node/package.json +2 -2
- package/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/package.json +8 -5
- package/dist/.setup/message-handler.history-CJOsN9w5.mjs +0 -28
- package/dist/.setup/provider.runtime-DuhmKdDU.mjs +0 -2
- package/dist/.setup/setup-plugin-api-CINIEBLa.mjs +0 -3
- package/dist/.setup/targets-D1mAB5yO.mjs +0 -3
package/dist/.setup/{realtime-session.runtime-DTccTgTM.mjs → realtime-session.runtime-Dz8uVutq.mjs}
RENAMED
|
@@ -1,16 +1,82 @@
|
|
|
1
|
-
import { a as
|
|
1
|
+
import { a as buildProviderConfigOverrides, o as buildProviderConfigs } from "./transcripts-source-DVegW0WI.mjs";
|
|
2
|
+
import { S as setDiscordAudioOutputStatus, _ as getDiscordAudioOutputStatus, d as createDiscordPcmToRealtimeConverter, g as admitDiscordAudioInput, h as DiscordAudioOutputStatus, v as releaseDiscordAudioInput, y as restoreDiscordAudioError } from "./receive-recovery-DHst8WRx.mjs";
|
|
2
3
|
import { n as discordRealtimeVoiceSecretOwnerId } from "./secret-config-contract-DFu9hfU8.mjs";
|
|
3
|
-
import {
|
|
4
|
+
import { a as handleDiscordVoiceAgentControlToolCall, c as formatRealtimeInterruptionLog, d as shouldLogRealtimeVerboseEvent, i as formatVoiceIngressPrompt, l as formatRealtimeLifecycleLog, n as DiscordRealtimeRecording, o as logDiscordVoiceAgentControlResult, r as logVoiceVerbose, s as maybeControlDiscordVoiceAgentRun, u as formatVoiceLogPreview } from "./voice-runtime-elTtjEIG.mjs";
|
|
4
5
|
import { randomUUID } from "node:crypto";
|
|
5
6
|
import { asDateTimestampMs, resolveExpiresAtMsFromDurationMs } from "openclaw/plugin-sdk/number-runtime";
|
|
6
7
|
import { formatErrorMessage } from "openclaw/plugin-sdk/ssrf-runtime";
|
|
7
8
|
import { formatErrorMessage as formatErrorMessage$1, readErrorName, toErrorObject } from "openclaw/plugin-sdk/error-runtime";
|
|
8
9
|
import { createSubsystemLogger } from "openclaw/plugin-sdk/runtime-env";
|
|
9
10
|
import { sliceUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
|
|
11
|
+
import { MessageChannel } from "node:worker_threads";
|
|
10
12
|
import { createDeferred } from "openclaw/plugin-sdk/extension-shared";
|
|
11
13
|
import { REALTIME_VOICE_AGENT_CONSULT_TOOL_NAME, REALTIME_VOICE_AGENT_CONTROL_TOOL, REALTIME_VOICE_AGENT_CONTROL_TOOL_NAME, REALTIME_VOICE_AUDIO_FORMAT_PCM16_24KHZ, buildRealtimeVoiceAgentErrorProviderResult, buildRealtimeVoiceSessionInstructions, buildRealtimeVoiceSpeakExactMessage, canonicalizeRealtimeVoiceProviderId, classifyRealtimeVoiceConsultToolCall, classifySkippableRealtimeVoiceConsultTranscript, createRealtimeVoiceAgentTalkbackQueue, createRealtimeVoiceOutputActivityTracker, createRealtimeVoiceSessionHarness, isRealtimeVoiceAudioAudible, isRealtimeVoiceWakeNameRequired, matchRealtimeVoiceActivationName, matchRealtimeVoiceConsultQuestions, projectInternalRealtimeVoicePublicConfig, realtimeVoiceAudioDurationMs, registerRealtimeVoiceSelection, resolveConfiguredRealtimeVoiceProvider, resolveRealtimeVoiceAgentConsultTools, resolveRealtimeVoiceBargeIn, resolveRealtimeVoiceInterruptResponseOnInputAudio, resolveRealtimeVoiceMinBargeInAudioEndMs, resolveRealtimeVoiceSessionPolicy } from "openclaw/plugin-sdk/realtime-voice";
|
|
12
|
-
import { PassThrough, pipeline } from "node:stream";
|
|
13
14
|
import { assertSecretOwnerAvailable, isSecretOwnerAvailable } from "openclaw/plugin-sdk/channel-secret-owner-runtime";
|
|
15
|
+
//#region extensions/discord/src/voice/realtime-player.ts
|
|
16
|
+
/** Room-level policy stays on main; the worker owns the physical player and FIFO. */
|
|
17
|
+
var DiscordRealtimePlayer = class {
|
|
18
|
+
constructor(audio) {
|
|
19
|
+
this.audio = audio;
|
|
20
|
+
this.lanes = /* @__PURE__ */ new Set();
|
|
21
|
+
this.outputs = /* @__PURE__ */ new Map();
|
|
22
|
+
this.closed = false;
|
|
23
|
+
this.onEvent = (event) => {
|
|
24
|
+
if (event.type === "output-start" || event.type === "continuous-start") this.current = event.id;
|
|
25
|
+
if ((event.type === "output-close" || event.type === "continuous-idle") && this.current === event.id) this.current = void 0;
|
|
26
|
+
};
|
|
27
|
+
audio.on("event", this.onEvent);
|
|
28
|
+
}
|
|
29
|
+
registerLane(lane) {
|
|
30
|
+
this.lanes.add(lane);
|
|
31
|
+
return () => this.lanes.delete(lane);
|
|
32
|
+
}
|
|
33
|
+
registerOutput(id, onBargeIn) {
|
|
34
|
+
this.outputs.set(id, onBargeIn);
|
|
35
|
+
return () => {
|
|
36
|
+
this.outputs.delete(id);
|
|
37
|
+
if (this.current === id) this.current = void 0;
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
handleBargeIn(reason = "barge-in") {
|
|
41
|
+
const current = this.current === void 0 ? void 0 : this.outputs.get(this.current);
|
|
42
|
+
if (current) return current(reason);
|
|
43
|
+
let interrupted = false;
|
|
44
|
+
for (const lane of [...this.lanes].filter((candidate) => candidate.hasOutput())) interrupted = lane.onBargeIn(reason) || interrupted;
|
|
45
|
+
return interrupted;
|
|
46
|
+
}
|
|
47
|
+
isActive() {
|
|
48
|
+
return this.current !== void 0 || [...this.lanes].some((lane) => lane.hasOutput());
|
|
49
|
+
}
|
|
50
|
+
cancelForControl() {
|
|
51
|
+
this.transition(() => {
|
|
52
|
+
for (const lane of this.lanes) lane.cancelForControl();
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
transition(action) {
|
|
56
|
+
this.audio.send({
|
|
57
|
+
type: "output-hold",
|
|
58
|
+
hold: true
|
|
59
|
+
});
|
|
60
|
+
try {
|
|
61
|
+
action();
|
|
62
|
+
} finally {
|
|
63
|
+
this.audio.send({
|
|
64
|
+
type: "output-hold",
|
|
65
|
+
hold: false
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
close() {
|
|
70
|
+
if (this.closed) return;
|
|
71
|
+
this.closed = true;
|
|
72
|
+
this.lanes.clear();
|
|
73
|
+
this.outputs.clear();
|
|
74
|
+
this.current = void 0;
|
|
75
|
+
this.audio.off("event", this.onEvent);
|
|
76
|
+
this.audio.send({ type: "output-shutdown" });
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
//#endregion
|
|
14
80
|
//#region extensions/discord/src/voice/realtime-transcript.ts
|
|
15
81
|
const PARTIAL_TRANSCRIPT_MAX_CHARS = 240;
|
|
16
82
|
function mergeRealtimePartialTranscript(previous, next) {
|
|
@@ -21,7 +87,7 @@ function mergeRealtimePartialTranscript(previous, next) {
|
|
|
21
87
|
}
|
|
22
88
|
//#endregion
|
|
23
89
|
//#region extensions/discord/src/voice/realtime-turns.ts
|
|
24
|
-
const logger$
|
|
90
|
+
const logger$4 = createSubsystemLogger("discord/voice");
|
|
25
91
|
const DISCORD_REALTIME_WAKE_NAME_FOLLOWUP_TTL_MS = 1e4;
|
|
26
92
|
const REALTIME_PCM16_BYTES_PER_SAMPLE = 2;
|
|
27
93
|
const DISCORD_REALTIME_TRAILING_SILENCE_MIN_MS = 700;
|
|
@@ -100,11 +166,11 @@ var DiscordRealtimeTurns = class {
|
|
|
100
166
|
const pendingWakeNameFollowup = this.consumePendingWakeNameFollowup();
|
|
101
167
|
if (!pendingWakeNameFollowup) {
|
|
102
168
|
this.consumePendingSpeakerContext();
|
|
103
|
-
logger$
|
|
169
|
+
logger$4.info(`discord voice: realtime wake-name gate ignored transcript chars=${trimmed.length} humanParticipants=${humanParticipantCount} voiceSession=${this.params.entry.voiceSessionKey} agent=${this.params.entry.route.agentId} wakeNames=${this.params.wakeNames().join(",") || "none"}`);
|
|
104
170
|
return;
|
|
105
171
|
}
|
|
106
172
|
forcedSpeakerContext = pendingWakeNameFollowup;
|
|
107
|
-
logger$
|
|
173
|
+
logger$4.info(`discord voice: realtime wake-name follow-up accepted chars=${trimmed.length} speaker=${forcedSpeakerContext.speakerLabel} voiceSession=${this.params.entry.voiceSessionKey} agent=${this.params.entry.route.agentId}`);
|
|
108
174
|
}
|
|
109
175
|
const acceptedText = wakeNameResult.allowed ? wakeNameResult.text || trimmed : trimmed;
|
|
110
176
|
if (wakeNameResult.allowed && !wakeNameResult.text.trim()) {
|
|
@@ -157,11 +223,11 @@ var DiscordRealtimeTurns = class {
|
|
|
157
223
|
this.registerSpeakerTurnAudioStarted(turn);
|
|
158
224
|
turn.inputRealtimeBytes += realtimePcm.length;
|
|
159
225
|
turn.inputChunks += 1;
|
|
160
|
-
if (turn.inputChunks === 1) logger$
|
|
226
|
+
if (turn.inputChunks === 1) logger$4.info(`discord voice: realtime input audio started guild=${this.params.entry.guildId} channel=${this.params.entry.channelId} user=${turn.context.userId} speaker=${turn.context.speakerLabel} discordBytes=${discordPcm48kStereo.length} realtimeBytes=${realtimePcm.length} outputAudioMs=${this.params.playback.outputAudioMs()} outputActive=${this.params.playback.isOutputAudioActive()}`);
|
|
161
227
|
if (!turn.interruptedPlayback && isRealtimeVoiceAudioAudible(discordPcm48kStereo, REALTIME_VOICE_AUDIO_FORMAT_PCM16_24KHZ) && isRealtimeVoiceAudioAudible(realtimePcm, REALTIME_VOICE_AUDIO_FORMAT_PCM16_24KHZ) && this.params.interruptRoomPlayback()) {
|
|
162
228
|
turn.interruptedPlayback = true;
|
|
163
229
|
logVoiceVerbose(`realtime barge-in from active speaker audio: guild ${this.params.entry.guildId} channel ${this.params.entry.channelId} user ${turn.context.userId}`);
|
|
164
|
-
logger$
|
|
230
|
+
logger$4.info(`discord voice: realtime barge-in detected source=active-speaker-audio guild=${this.params.entry.guildId} channel=${this.params.entry.channelId} user=${turn.context.userId} speaker=${turn.context.speakerLabel} discordBytes=${discordPcm48kStereo.length} realtimeBytes=${realtimePcm.length}`);
|
|
165
231
|
}
|
|
166
232
|
if (this.params.recordInputAudio(realtimePcm) && this.isTurnProviderCurrent(turn)) bridge.sendAudio(realtimePcm);
|
|
167
233
|
}
|
|
@@ -175,13 +241,13 @@ var DiscordRealtimeTurns = class {
|
|
|
175
241
|
turn.lastAudioAt = Date.now();
|
|
176
242
|
if (turn.hasAudio) return;
|
|
177
243
|
turn.hasAudio = true;
|
|
178
|
-
logger$
|
|
244
|
+
logger$4.info(`discord voice: realtime speaker turn opened guild=${this.params.entry.guildId} channel=${this.params.entry.channelId} user=${turn.context.userId} speaker=${turn.context.speakerLabel} owner=${turn.context.senderIsOwner}`);
|
|
179
245
|
}
|
|
180
246
|
logSpeakerTurnClosed(turn) {
|
|
181
247
|
if (turn.closed || !turn.hasAudio) return;
|
|
182
248
|
const elapsedMs = Date.now() - turn.startedAt;
|
|
183
249
|
const sinceLastAudioMs = turn.lastAudioAt ? Date.now() - turn.lastAudioAt : void 0;
|
|
184
|
-
logger$
|
|
250
|
+
logger$4.info(`discord voice: realtime speaker turn closed guild=${this.params.entry.guildId} channel=${this.params.entry.channelId} user=${turn.context.userId} speaker=${turn.context.speakerLabel} owner=${turn.context.senderIsOwner} hasAudio=${turn.hasAudio} chunks=${turn.inputChunks} discordBytes=${turn.inputDiscordBytes} realtimeBytes=${turn.inputRealtimeBytes} elapsedMs=${elapsedMs}${sinceLastAudioMs === void 0 ? "" : ` sinceLastAudioMs=${sinceLastAudioMs}`} interruptedPlayback=${turn.interruptedPlayback}`);
|
|
185
251
|
}
|
|
186
252
|
sendRealtimeTrailingSilenceForTurn(turn) {
|
|
187
253
|
const bridge = turn.bridge;
|
|
@@ -192,7 +258,7 @@ var DiscordRealtimeTurns = class {
|
|
|
192
258
|
const silenceBytes = Math.ceil(24e3 * silenceMs / 1e3) * REALTIME_PCM16_BYTES_PER_SAMPLE;
|
|
193
259
|
const silence = Buffer.alloc(silenceBytes);
|
|
194
260
|
bridge.sendAudio(silence);
|
|
195
|
-
logger$
|
|
261
|
+
logger$4.info(`discord voice: realtime trailing silence sent guild=${this.params.entry.guildId} channel=${this.params.entry.channelId} user=${turn.context.userId} speaker=${turn.context.speakerLabel} silenceMs=${silenceMs} realtimeBytes=${silence.length}`);
|
|
196
262
|
}
|
|
197
263
|
resolveWakeNameTranscript(text, requireWakeName) {
|
|
198
264
|
if (!requireWakeName) return {
|
|
@@ -205,7 +271,7 @@ var DiscordRealtimeTurns = class {
|
|
|
205
271
|
};
|
|
206
272
|
const wakeNameResult = matchRealtimeVoiceActivationName(text, this.params.wakeNames());
|
|
207
273
|
if (wakeNameResult) {
|
|
208
|
-
logger$
|
|
274
|
+
logger$4.info(`discord voice: realtime wake-name gate matched canonical=${wakeNameResult.activationName} heard=${wakeNameResult.heardName} match=${wakeNameResult.match} voiceSession=${this.params.entry.voiceSessionKey} agent=${this.params.entry.route.agentId}`);
|
|
209
275
|
return wakeNameResult;
|
|
210
276
|
}
|
|
211
277
|
return {
|
|
@@ -219,7 +285,7 @@ var DiscordRealtimeTurns = class {
|
|
|
219
285
|
armWakeNameFollowup() {
|
|
220
286
|
const context = this.consumePendingSpeakerContext();
|
|
221
287
|
if (!context) {
|
|
222
|
-
logger$
|
|
288
|
+
logger$4.warn(`discord voice: realtime wake-name follow-up has no speaker context voiceSession=${this.params.entry.voiceSessionKey} agent=${this.params.entry.route.agentId}`);
|
|
223
289
|
return;
|
|
224
290
|
}
|
|
225
291
|
const expiresAt = resolveExpiresAtMsFromDurationMs(DISCORD_REALTIME_WAKE_NAME_FOLLOWUP_TTL_MS);
|
|
@@ -228,7 +294,7 @@ var DiscordRealtimeTurns = class {
|
|
|
228
294
|
context,
|
|
229
295
|
expiresAt
|
|
230
296
|
};
|
|
231
|
-
logger$
|
|
297
|
+
logger$4.info(`discord voice: realtime wake-name follow-up armed speaker=${context.speakerLabel} voiceSession=${this.params.entry.voiceSessionKey} agent=${this.params.entry.route.agentId}`);
|
|
232
298
|
}
|
|
233
299
|
consumePendingWakeNameFollowup() {
|
|
234
300
|
const pending = this.pendingWakeNameFollowup;
|
|
@@ -245,7 +311,7 @@ function isDiscordRealtimeSpeakerContext(value) {
|
|
|
245
311
|
}
|
|
246
312
|
//#endregion
|
|
247
313
|
//#region extensions/discord/src/voice/realtime-consults.ts
|
|
248
|
-
const logger$
|
|
314
|
+
const logger$3 = createSubsystemLogger("discord/voice");
|
|
249
315
|
const DISCORD_REALTIME_TALKBACK_DEBOUNCE_MS = 350;
|
|
250
316
|
const DISCORD_REALTIME_FALLBACK_TEXT = "I hit an error while checking that. Please try again.";
|
|
251
317
|
const DISCORD_REALTIME_FORCED_CONSULT_FALLBACK_DELAY_MS = 200;
|
|
@@ -318,16 +384,16 @@ var DiscordRealtimeConsults = class {
|
|
|
318
384
|
const outcome = classifyRealtimeVoiceConsultToolCall(event.args, { retainedExactSpeechTexts: this.params.playback.retainedExactSpeechTexts() });
|
|
319
385
|
switch (outcome.kind) {
|
|
320
386
|
case "exact-speech-echo":
|
|
321
|
-
logger$
|
|
387
|
+
logger$3.info(`discord voice: realtime exact speech consult bypassed call=${callId || "unknown"} answerChars=${outcome.text.length}`);
|
|
322
388
|
await session.submitToolResult(callId, { text: outcome.text });
|
|
323
389
|
return;
|
|
324
390
|
case "malformed":
|
|
325
|
-
logger$
|
|
391
|
+
logger$3.warn(`discord voice: realtime consult rejected malformed args call=${callId || "unknown"}: ${outcome.error}`);
|
|
326
392
|
await session.submitToolResult(callId, { error: outcome.error });
|
|
327
393
|
return;
|
|
328
394
|
}
|
|
329
395
|
const consultMessage = outcome.message;
|
|
330
|
-
logger$
|
|
396
|
+
logger$3.info(`discord voice: realtime consult requested call=${callId || "unknown"} voiceSession=${this.params.entry.voiceSessionKey} supervisorSession=${this.params.entry.route.sessionKey} agent=${this.params.entry.route.agentId} question=${formatVoiceLogPreview(consultMessage)}`);
|
|
331
397
|
const nativeConsult = this.params.harness.forcedConsults.recordNativeConsult(event.args, callId);
|
|
332
398
|
if (nativeConsult.kind === "already_delivered" && this.params.harness.forcedConsults.isCancelled(nativeConsult.handle)) {
|
|
333
399
|
await this.submitTerminalRealtimeToolResult(callId, session, CANCELLED_CONSULT_RESULT);
|
|
@@ -342,7 +408,7 @@ var DiscordRealtimeConsults = class {
|
|
|
342
408
|
if (recentConsult) {
|
|
343
409
|
const recentSpeaker = recentConsult.context?.speaker;
|
|
344
410
|
if (this.params.turns.hasPendingSpeakerAudioContext()) {
|
|
345
|
-
logger$
|
|
411
|
+
logger$3.info(`discord voice: realtime consult matched recent agent result but newer speaker audio is pending call=${callId} speaker=${recentSpeaker?.speakerLabel ?? "unknown"} owner=${recentSpeaker?.senderIsOwner ?? false}`);
|
|
346
412
|
await session.submitToolResult(callId, { error: "Discord speaker context changed before this realtime consult completed" });
|
|
347
413
|
return;
|
|
348
414
|
}
|
|
@@ -358,7 +424,7 @@ var DiscordRealtimeConsults = class {
|
|
|
358
424
|
}
|
|
359
425
|
const state = recent?.context;
|
|
360
426
|
if (!context || !state) {
|
|
361
|
-
logger$
|
|
427
|
+
logger$3.warn(`discord voice: realtime consult has no speaker context call=${callId || "unknown"}`);
|
|
362
428
|
await session.submitToolResult(callId, { error: "No Discord speaker context available" });
|
|
363
429
|
return;
|
|
364
430
|
}
|
|
@@ -371,8 +437,8 @@ var DiscordRealtimeConsults = class {
|
|
|
371
437
|
deliveryOwner: "consult"
|
|
372
438
|
}));
|
|
373
439
|
if (this.params.stopped() || providerEpoch !== this.params.providerEpoch()) return;
|
|
374
|
-
if ("text" in result) logger$
|
|
375
|
-
else if ("error" in result) logger$
|
|
440
|
+
if ("text" in result) logger$3.info(`discord voice: realtime consult answer (${result.text.length} chars) voiceSession=${this.params.entry.voiceSessionKey} supervisorSession=${this.params.entry.route.sessionKey} agent=${this.params.entry.route.agentId} speaker=${context.speakerLabel} owner=${context.senderIsOwner}: ${formatVoiceLogPreview(result.text)}`);
|
|
441
|
+
else if ("error" in result) logger$3.warn(`discord voice: realtime consult failed call=${callId}: ${result.error}`);
|
|
376
442
|
delivery.submissionStarted = true;
|
|
377
443
|
await this.submitAgentProxyConsultResult(callId, session, result);
|
|
378
444
|
if (state.delivery === "provider-pending") state.delivery = "provider";
|
|
@@ -394,10 +460,10 @@ var DiscordRealtimeConsults = class {
|
|
|
394
460
|
if (this.params.stopped() || providerEpoch !== this.params.providerEpoch()) return;
|
|
395
461
|
if (readErrorName(error) === "AbortError") {
|
|
396
462
|
if (pendingForcedConsult) this.params.harness.forcedConsults.remove(pendingForcedConsult);
|
|
397
|
-
logger$
|
|
463
|
+
logger$3.warn(`discord voice: realtime transcript cancelled: ${formatErrorMessage$1(error)}`);
|
|
398
464
|
return;
|
|
399
465
|
}
|
|
400
|
-
logger$
|
|
466
|
+
logger$3.warn(`discord voice: realtime active-run control failed; falling back to normal transcript handling: ${formatErrorMessage$1(error)}`);
|
|
401
467
|
control = void 0;
|
|
402
468
|
}
|
|
403
469
|
if (this.params.stopped() || providerEpoch !== this.params.providerEpoch()) return;
|
|
@@ -419,7 +485,7 @@ var DiscordRealtimeConsults = class {
|
|
|
419
485
|
return createRealtimeVoiceAgentTalkbackQueue({
|
|
420
486
|
debounceMs: this.params.debounceMs() ?? DISCORD_REALTIME_TALKBACK_DEBOUNCE_MS,
|
|
421
487
|
isStopped: () => this.params.stopped() || providerEpoch !== this.params.providerEpoch(),
|
|
422
|
-
logger: logger$
|
|
488
|
+
logger: logger$3,
|
|
423
489
|
logPrefix: "[discord] realtime agent",
|
|
424
490
|
responseStyle: "Brief, natural spoken answer for a Discord voice channel.",
|
|
425
491
|
fallbackText: DISCORD_REALTIME_FALLBACK_TEXT,
|
|
@@ -468,7 +534,7 @@ var DiscordRealtimeConsults = class {
|
|
|
468
534
|
const skipReason = classifySkippableRealtimeVoiceConsultTranscript(question);
|
|
469
535
|
if (skipReason) {
|
|
470
536
|
const context = this.params.turns.consumePendingSpeakerContext();
|
|
471
|
-
logger$
|
|
537
|
+
logger$3.info(`discord voice: realtime forced agent consult skipped reason=${skipReason} chars=${question.length} speaker=${context?.speakerLabel ?? "unknown"} transcript=${formatVoiceLogPreview(question)}`);
|
|
472
538
|
return;
|
|
473
539
|
}
|
|
474
540
|
const context = speakerContext ?? this.params.turns.consumePendingSpeakerContext();
|
|
@@ -478,7 +544,7 @@ var DiscordRealtimeConsults = class {
|
|
|
478
544
|
logVoiceVerbose(`realtime forced agent consult skipped (already delegated): guild ${this.params.entry.guildId} channel ${this.params.entry.channelId} speaker ${recent.context?.speaker.userId ?? "unknown"}`);
|
|
479
545
|
return;
|
|
480
546
|
}
|
|
481
|
-
logger$
|
|
547
|
+
logger$3.warn("discord voice: realtime forced agent consult has no speaker context");
|
|
482
548
|
return;
|
|
483
549
|
}
|
|
484
550
|
return this.params.harness.forcedConsults.prepare(question, { context: {
|
|
@@ -504,9 +570,9 @@ var DiscordRealtimeConsults = class {
|
|
|
504
570
|
return;
|
|
505
571
|
}
|
|
506
572
|
const startedAt = Date.now();
|
|
507
|
-
logger$
|
|
508
|
-
logger$
|
|
509
|
-
if (this.params.playback.hasInterruptibleOutputAudio()) logger$
|
|
573
|
+
logger$3.info(`discord voice: realtime forced agent consult starting chars=${question.length} voiceSession=${this.params.entry.voiceSessionKey} supervisorSession=${this.params.entry.route.sessionKey} agent=${this.params.entry.route.agentId} speaker=${context.speakerLabel} owner=${context.senderIsOwner}`);
|
|
574
|
+
logger$3.debug(`discord voice: realtime forced agent consult reason=${DISCORD_REALTIME_FORCED_CONSULT_REASON} consultPolicy=${this.params.consultPolicy()} wakeNamePolicy=${this.params.wakeNamePolicy()} requireWakeName=${this.params.isWakeNameRequired()} voiceSession=${this.params.entry.voiceSessionKey} supervisorSession=${this.params.entry.route.sessionKey} agent=${this.params.entry.route.agentId} speaker=${context.speakerLabel}`);
|
|
575
|
+
if (this.params.playback.hasInterruptibleOutputAudio()) logger$3.info(`discord voice: realtime forced agent consult preserving active playback guild=${this.params.entry.guildId} channel=${this.params.entry.channelId} outputAudioMs=${this.params.playback.outputAudioMs()} outputActive=${this.params.playback.isOutputAudioActive()} playbackChunks=${this.params.harness.outputActivity.snapshot().chunks}`);
|
|
510
576
|
state.delivery = "forced-pending";
|
|
511
577
|
const result = await this.trackAgentProxyConsult(pending, this.runAgentTurn({
|
|
512
578
|
context,
|
|
@@ -516,8 +582,8 @@ var DiscordRealtimeConsults = class {
|
|
|
516
582
|
const deliveries = this.providerDeliveries.get(state);
|
|
517
583
|
await Promise.all(Array.from(deliveries ?? [], (delivery) => delivery.promise));
|
|
518
584
|
if (state.providerEpoch !== this.params.providerEpoch() || "status" in result) return;
|
|
519
|
-
if ("text" in result) logger$
|
|
520
|
-
else logger$
|
|
585
|
+
if ("text" in result) logger$3.info(`discord voice: realtime forced agent consult answer (${result.text.length} chars) elapsedMs=${Date.now() - startedAt} voiceSession=${this.params.entry.voiceSessionKey} supervisorSession=${this.params.entry.route.sessionKey} agent=${this.params.entry.route.agentId}: ${formatVoiceLogPreview(result.text)}`);
|
|
586
|
+
else logger$3.warn(`discord voice: realtime forced agent consult failed elapsedMs=${Date.now() - startedAt}: ${result.error}`);
|
|
521
587
|
const text = "text" in result ? result.text : DISCORD_REALTIME_FALLBACK_TEXT;
|
|
522
588
|
if (text.trim() && state.delivery === "forced-pending") {
|
|
523
589
|
state.delivery = "playback";
|
|
@@ -569,7 +635,7 @@ var DiscordRealtimeConsults = class {
|
|
|
569
635
|
const pendingResult = state.result ?? state.promise;
|
|
570
636
|
if (!pendingResult) return false;
|
|
571
637
|
const providerDelivery = state.delivery === "provider-pending" || state.delivery === "forced-pending" && !state.result && session.bridge.supportsToolResultSuppression === false ? this.beginProviderDelivery(state) : void 0;
|
|
572
|
-
logger$
|
|
638
|
+
logger$3.info(`discord voice: realtime consult ${state.result ? "reused recent" : "joined in-flight"} agent result call=${callId} speaker=${state.speaker.speakerLabel} owner=${state.speaker.senderIsOwner}`);
|
|
573
639
|
try {
|
|
574
640
|
const result = await pendingResult;
|
|
575
641
|
if (this.params.stopped() || state.providerEpoch !== this.params.providerEpoch() || state.delivery === "detached" || state.delivery === "retired") return true;
|
|
@@ -629,286 +695,156 @@ var DiscordRealtimeConsults = class {
|
|
|
629
695
|
};
|
|
630
696
|
//#endregion
|
|
631
697
|
//#region extensions/discord/src/voice/realtime-output.ts
|
|
632
|
-
|
|
633
|
-
const DISCORD_RAW_PCM_FRAME_BYTES = 3840;
|
|
634
|
-
const DISCORD_RAW_PCM_BYTES_PER_MS = 192;
|
|
635
|
-
const DISCORD_REALTIME_OUTPUT_PREROLL_FRAMES = 25;
|
|
636
|
-
const DISCORD_CONTINUOUS_PREROLL_FRAMES = 6;
|
|
637
|
-
const DISCORD_CONTINUOUS_START_DEADLINE_MS = 120;
|
|
638
|
-
const DISCORD_REALTIME_OUTPUT_PLAYBACK_WATCHDOG_MARGIN_MS = 3e3;
|
|
639
|
-
/** One output stream retains ownership through queued and audible playback. */
|
|
698
|
+
/** Main retains provider item identity; physical output state belongs to the worker. */
|
|
640
699
|
var DiscordRealtimeOutput = class {
|
|
700
|
+
get activity() {
|
|
701
|
+
if (Atomics.load(this.clock, 2) !== 0n && !this.activityTracker.snapshot().playbackStarted) this.activityTracker.markPlaybackStarted();
|
|
702
|
+
return this.activityTracker;
|
|
703
|
+
}
|
|
641
704
|
constructor(params) {
|
|
642
705
|
this.params = params;
|
|
643
|
-
this.
|
|
644
|
-
this.
|
|
645
|
-
this.
|
|
646
|
-
this.
|
|
647
|
-
this.playbackMarks = [];
|
|
648
|
-
this.playedPcmBytes = 0;
|
|
649
|
-
this.lastAudiblePcmEndBytes = 0;
|
|
650
|
-
this.reportedPlaybackMs = 0;
|
|
651
|
-
this.audioSpans = [];
|
|
652
|
-
this.buffers = [];
|
|
653
|
-
this.bufferedBytes = 0;
|
|
706
|
+
this.activityTracker = createRealtimeVoiceOutputActivityTracker();
|
|
707
|
+
this.clock = new BigInt64Array(new SharedArrayBuffer(24));
|
|
708
|
+
this.marks = /* @__PURE__ */ new Map();
|
|
709
|
+
this.nextMark = 0;
|
|
654
710
|
this.closed = false;
|
|
655
|
-
this.
|
|
656
|
-
this.
|
|
657
|
-
|
|
711
|
+
this.reportedPlaybackMs = 0;
|
|
712
|
+
this.spans = [];
|
|
713
|
+
this.onEvent = (event) => {
|
|
714
|
+
if (!("id" in event) || event.id !== this.id || this.closed) return;
|
|
715
|
+
switch (event.type) {
|
|
716
|
+
case "output-start":
|
|
717
|
+
this.activity.markPlaybackStarted();
|
|
718
|
+
this.params.onStart();
|
|
719
|
+
break;
|
|
720
|
+
case "output-close":
|
|
721
|
+
this.retire(event.reason);
|
|
722
|
+
break;
|
|
723
|
+
case "output-error":
|
|
724
|
+
this.params.onError(restoreDiscordAudioError(event.error));
|
|
725
|
+
break;
|
|
726
|
+
case "output-mark": {
|
|
727
|
+
const acknowledge = this.marks.get(event.markId);
|
|
728
|
+
this.marks.delete(event.markId);
|
|
729
|
+
try {
|
|
730
|
+
acknowledge?.();
|
|
731
|
+
} catch (error) {
|
|
732
|
+
this.params.onError(error);
|
|
733
|
+
}
|
|
734
|
+
break;
|
|
735
|
+
}
|
|
736
|
+
}
|
|
737
|
+
};
|
|
738
|
+
this.onStopped = () => {
|
|
739
|
+
if (!this.closed) {
|
|
740
|
+
this.params.onError(/* @__PURE__ */ new Error("Discord audio worker stopped during playback."));
|
|
741
|
+
this.retire("worker-stopped");
|
|
742
|
+
}
|
|
743
|
+
};
|
|
744
|
+
this.id = params.player.audio.allocateId();
|
|
745
|
+
this.unregister = params.player.registerOutput(this.id, params.onBargeIn);
|
|
746
|
+
params.player.audio.on("event", this.onEvent);
|
|
747
|
+
params.player.audio.on("stopped", this.onStopped);
|
|
748
|
+
params.player.audio.send({
|
|
749
|
+
type: "output-create",
|
|
750
|
+
id: this.id,
|
|
751
|
+
continuous: params.continuous,
|
|
752
|
+
clock: this.clock.buffer
|
|
658
753
|
});
|
|
659
754
|
}
|
|
755
|
+
playedBytes() {
|
|
756
|
+
return Number(Atomics.load(this.clock, 0));
|
|
757
|
+
}
|
|
660
758
|
pendingBytes() {
|
|
661
|
-
return this.closed ? 0 : Math.max(0, this.activity.snapshot().sourceAudioBytes * 4 - this.
|
|
759
|
+
return this.closed ? 0 : Math.max(0, this.activity.snapshot().sourceAudioBytes * 4 - this.playedBytes());
|
|
662
760
|
}
|
|
663
761
|
isAcceptingAudio() {
|
|
664
|
-
return !this.closed && !this.activity.snapshot().streamEnding && (
|
|
665
|
-
}
|
|
666
|
-
hasUnplayedAudibleAudio() {
|
|
667
|
-
return !this.closed && this.playedPcmBytes < this.lastAudiblePcmEndBytes;
|
|
762
|
+
return !this.closed && !this.activity.snapshot().streamEnding && getDiscordAudioOutputStatus(this.clock) < DiscordAudioOutputStatus.Retiring;
|
|
668
763
|
}
|
|
669
764
|
playbackItems() {
|
|
670
|
-
const playedMs = Math.min(this.
|
|
671
|
-
for (const span of this.
|
|
765
|
+
const playedMs = Math.min(this.playedBytes() / 192, this.activity.snapshot().audioMs);
|
|
766
|
+
for (const span of this.spans) span.item.audioEndMs += Math.max(0, Math.min(playedMs, span.endMs) - Math.max(this.reportedPlaybackMs, span.startMs));
|
|
672
767
|
this.reportedPlaybackMs = playedMs;
|
|
673
|
-
return this.
|
|
768
|
+
return this.spans.filter(({ endMs }) => endMs > playedMs).map(({ item }) => item);
|
|
674
769
|
}
|
|
675
770
|
markPlayback(acknowledge) {
|
|
676
|
-
if (
|
|
677
|
-
|
|
678
|
-
|
|
771
|
+
if (this.closed) return;
|
|
772
|
+
const markId = ++this.nextMark;
|
|
773
|
+
this.marks.set(markId, acknowledge);
|
|
774
|
+
this.params.player.audio.send({
|
|
775
|
+
type: "output-mark",
|
|
776
|
+
id: this.id,
|
|
777
|
+
markId
|
|
679
778
|
});
|
|
680
779
|
}
|
|
681
|
-
append(
|
|
682
|
-
if (this.closed) return;
|
|
780
|
+
append(audio, audible, item, onAccepted) {
|
|
781
|
+
if (this.closed || this.activity.snapshot().streamEnding || !admitDiscordAudioInput(this.clock)) return false;
|
|
782
|
+
try {
|
|
783
|
+
onAccepted();
|
|
784
|
+
} catch (error) {
|
|
785
|
+
releaseDiscordAudioInput(this.clock);
|
|
786
|
+
throw error;
|
|
787
|
+
}
|
|
788
|
+
if (this.closed) {
|
|
789
|
+
releaseDiscordAudioInput(this.clock);
|
|
790
|
+
return true;
|
|
791
|
+
}
|
|
683
792
|
const previous = this.activity.snapshot();
|
|
684
|
-
const sinkBytes = Math.floor((previous.sourceAudioBytes +
|
|
685
|
-
const audioMs = (sinkBytes - previous.sinkAudioBytes) /
|
|
686
|
-
const startMs = previous.audioMs;
|
|
793
|
+
const sinkBytes = Math.floor((previous.sourceAudioBytes + audio.length) / 2) * 8;
|
|
794
|
+
const audioMs = (sinkBytes - previous.sinkAudioBytes) / 192;
|
|
687
795
|
if (item) {
|
|
688
|
-
const
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
else this.audioSpans.push({
|
|
796
|
+
const last = this.spans.at(-1);
|
|
797
|
+
if (last?.item === item && last.endMs === previous.audioMs) last.endMs += audioMs;
|
|
798
|
+
else this.spans.push({
|
|
692
799
|
item,
|
|
693
|
-
startMs,
|
|
694
|
-
endMs
|
|
800
|
+
startMs: previous.audioMs,
|
|
801
|
+
endMs: previous.audioMs + audioMs
|
|
695
802
|
});
|
|
696
803
|
}
|
|
697
804
|
this.activity.markAudio({
|
|
698
805
|
audioMs,
|
|
699
|
-
sourceAudioBytes:
|
|
806
|
+
sourceAudioBytes: audio.length,
|
|
700
807
|
sinkAudioBytes: sinkBytes - previous.sinkAudioBytes
|
|
701
808
|
});
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
this.
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
if (this.params.continuous) this.enqueuePlayback();
|
|
710
|
-
const prerollFrames = this.params.continuous ? DISCORD_CONTINUOUS_PREROLL_FRAMES : DISCORD_REALTIME_OUTPUT_PREROLL_FRAMES;
|
|
711
|
-
if (this.activity.snapshot().sinkAudioBytes >= DISCORD_RAW_PCM_FRAME_BYTES * prerollFrames) this.startPlayback();
|
|
712
|
-
else if (this.params.continuous && !this.ready && !this.startupTimer) {
|
|
713
|
-
this.startupTimer = setTimeout(() => {
|
|
714
|
-
this.startupTimer = void 0;
|
|
715
|
-
this.startPlayback();
|
|
716
|
-
}, DISCORD_CONTINUOUS_START_DEADLINE_MS);
|
|
717
|
-
this.startupTimer.unref?.();
|
|
718
|
-
}
|
|
719
|
-
}
|
|
720
|
-
writeConverted(pcm) {
|
|
721
|
-
if (pcm.length === 0 || this.closed) return;
|
|
722
|
-
if (this.activity.snapshot().playbackStarted && !this.drainHandler) {
|
|
723
|
-
if (!this.stream.write(pcm)) this.waitForDrain();
|
|
724
|
-
return;
|
|
725
|
-
}
|
|
726
|
-
this.buffers.push(pcm);
|
|
727
|
-
this.bufferedBytes += pcm.length;
|
|
809
|
+
this.params.player.audio.send({
|
|
810
|
+
type: "output-audio",
|
|
811
|
+
id: this.id,
|
|
812
|
+
audio,
|
|
813
|
+
audible
|
|
814
|
+
});
|
|
815
|
+
return true;
|
|
728
816
|
}
|
|
729
817
|
finish(reason, playBuffered) {
|
|
730
818
|
if (this.closed) return;
|
|
731
|
-
this.clearSilenceTimer();
|
|
732
|
-
if (playBuffered) this.writeConverted(this.converter.flush());
|
|
733
819
|
this.activity.markStreamEnding();
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
this.
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
if (this.
|
|
742
|
-
this.scheduleWatchdog(reason);
|
|
743
|
-
if (!this.drainHandler) this.stream.end();
|
|
744
|
-
}
|
|
820
|
+
if (!playBuffered) setDiscordAudioOutputStatus(this.clock, DiscordAudioOutputStatus.Closed);
|
|
821
|
+
this.params.player.audio.send({
|
|
822
|
+
type: "output-finish",
|
|
823
|
+
id: this.id,
|
|
824
|
+
reason,
|
|
825
|
+
playBuffered
|
|
826
|
+
});
|
|
827
|
+
if (!playBuffered) this.retire(reason);
|
|
745
828
|
}
|
|
746
829
|
close(reason) {
|
|
747
830
|
if (this.closed) return;
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
clearTimeout(this.startupTimer);
|
|
754
|
-
this.startupTimer = void 0;
|
|
755
|
-
this.playbackMarks = [];
|
|
756
|
-
this.playbackItems();
|
|
757
|
-
this.clearWatchdog();
|
|
758
|
-
const activity = this.activity.snapshot();
|
|
759
|
-
logger$3.info(`discord voice: realtime audio playback stopped reason=${reason} ${this.params.logContext} audioMs=${Math.floor(activity.audioMs)} elapsedMs=${this.activity.elapsedPlaybackMs()} chunks=${activity.chunks} discordBytes=${activity.sinkAudioBytes} realtimeBytes=${activity.sourceAudioBytes}`);
|
|
760
|
-
this.buffers = [];
|
|
761
|
-
this.bufferedBytes = 0;
|
|
762
|
-
if (this.drainHandler) {
|
|
763
|
-
this.stream.off("drain", this.drainHandler);
|
|
764
|
-
this.drainHandler = void 0;
|
|
765
|
-
}
|
|
766
|
-
this.stream.end();
|
|
767
|
-
this.stream.destroy();
|
|
768
|
-
if (lostPlaybackMarks) this.params.onError(/* @__PURE__ */ new Error(`Discord realtime audio stopped before playback completed: ${reason}`));
|
|
769
|
-
this.params.onClose(this, reason);
|
|
770
|
-
if (this.request) {
|
|
771
|
-
this.params.player.cancel(this.request);
|
|
772
|
-
this.request = void 0;
|
|
773
|
-
}
|
|
774
|
-
try {
|
|
775
|
-
for (const mark of heardMarks) mark.acknowledge();
|
|
776
|
-
} catch (error) {
|
|
777
|
-
this.params.onError(error);
|
|
778
|
-
}
|
|
779
|
-
}
|
|
780
|
-
startPlayback() {
|
|
781
|
-
if (this.closed || this.ready) return;
|
|
782
|
-
clearTimeout(this.startupTimer);
|
|
783
|
-
this.startupTimer = void 0;
|
|
784
|
-
if (this.bufferedBytes < DISCORD_RAW_PCM_FRAME_BYTES) this.writeConverted(this.converter.drain());
|
|
785
|
-
this.ready = true;
|
|
786
|
-
this.enqueuePlayback();
|
|
787
|
-
}
|
|
788
|
-
enqueuePlayback() {
|
|
789
|
-
this.request ??= {
|
|
790
|
-
isReady: () => this.ready,
|
|
791
|
-
createResource: () => this.createResource(),
|
|
792
|
-
onStart: () => {
|
|
793
|
-
this.activity.markPlaybackStarted();
|
|
794
|
-
this.params.onStart();
|
|
795
|
-
if (this.activity.snapshot().streamEnding) {
|
|
796
|
-
this.scheduleWatchdog("player-start");
|
|
797
|
-
if (!this.drainHandler) this.stream.end();
|
|
798
|
-
}
|
|
799
|
-
},
|
|
800
|
-
onIdle: () => this.close(this.failed ? "output-pipeline-error" : "player-idle"),
|
|
801
|
-
onBargeIn: this.params.onBargeIn,
|
|
802
|
-
onError: this.params.onError
|
|
803
|
-
};
|
|
804
|
-
this.params.player.enqueue(this.request);
|
|
805
|
-
}
|
|
806
|
-
createResource() {
|
|
807
|
-
const voiceSdk = loadDiscordVoiceSdk();
|
|
808
|
-
const opusStream = createDiscordOpusEncodeStream();
|
|
809
|
-
opusStream.once("error", () => {
|
|
810
|
-
this.failed = true;
|
|
811
|
-
});
|
|
812
|
-
pipeline(this.stream, opusStream, (error) => {
|
|
813
|
-
if (!error || this.closed) return;
|
|
814
|
-
logger$3.warn(`discord voice: realtime output pipeline failed ${this.params.logContext}: ${formatErrorMessage(error)}`);
|
|
815
|
-
this.close("output-pipeline-error");
|
|
816
|
-
});
|
|
817
|
-
const buffered = Buffer.concat(this.buffers, this.bufferedBytes);
|
|
818
|
-
this.buffers = [];
|
|
819
|
-
this.bufferedBytes = 0;
|
|
820
|
-
if (buffered.length > 0 && !this.stream.write(buffered)) this.waitForDrain();
|
|
821
|
-
if (this.params.continuous && buffered.length > 0 && buffered.length < DISCORD_RAW_PCM_FRAME_BYTES) opusStream.flushPartialFrameWhenReady();
|
|
822
|
-
const resource = voiceSdk.createAudioResource(opusStream, { inputType: voiceSdk.StreamType.Opus });
|
|
823
|
-
const read = resource.read.bind(resource);
|
|
824
|
-
resource.read = () => {
|
|
825
|
-
let packet;
|
|
826
|
-
try {
|
|
827
|
-
packet = read();
|
|
828
|
-
if (!packet && opusStream.flushPartialFrame()) packet = read();
|
|
829
|
-
if (packet) {
|
|
830
|
-
this.playedPcmBytes += opusStream.takePcmBytes(packet);
|
|
831
|
-
const remaining = this.activity.snapshot().sinkAudioBytes - this.playedPcmBytes;
|
|
832
|
-
if (remaining > 0 && remaining <= DISCORD_RAW_PCM_FRAME_BYTES) this.writeConverted(this.converter.drain());
|
|
833
|
-
this.scheduleSilenceRetirement();
|
|
834
|
-
}
|
|
835
|
-
} catch (error) {
|
|
836
|
-
opusStream.destroy(error instanceof Error ? error : new Error(formatErrorMessage(error)));
|
|
837
|
-
return null;
|
|
838
|
-
}
|
|
839
|
-
if (this.playbackMarks.length > 0) queueMicrotask(() => this.acknowledgePlayedMarks());
|
|
840
|
-
return packet;
|
|
841
|
-
};
|
|
842
|
-
return resource;
|
|
843
|
-
}
|
|
844
|
-
acknowledgePlayedMarks() {
|
|
845
|
-
try {
|
|
846
|
-
while (!this.closed) {
|
|
847
|
-
const mark = this.playbackMarks[0];
|
|
848
|
-
if (!mark || mark.endBytes > this.playedPcmBytes) return;
|
|
849
|
-
this.playbackMarks.shift();
|
|
850
|
-
mark.acknowledge();
|
|
851
|
-
}
|
|
852
|
-
} catch (error) {
|
|
853
|
-
this.params.onError(error);
|
|
854
|
-
}
|
|
855
|
-
}
|
|
856
|
-
scheduleSilenceRetirement() {
|
|
857
|
-
const activity = this.activity.snapshot();
|
|
858
|
-
if (!this.params.continuous || this.closed || activity.streamEnding || !activity.playbackStarted || this.hasUnplayedAudibleAudio()) return;
|
|
859
|
-
this.silentSince ??= performance.now();
|
|
860
|
-
if (activity.sinkAudioBytes <= this.lastAudiblePcmEndBytes || this.silenceTimer) return;
|
|
861
|
-
this.silenceTimer = setTimeout(() => {
|
|
862
|
-
this.silenceTimer = void 0;
|
|
863
|
-
if (!this.closed && !this.activity.snapshot().streamEnding && !this.hasUnplayedAudibleAudio()) this.finish("continuous-idle", true);
|
|
864
|
-
}, Math.max(0, DISCORD_REALTIME_PLAYBACK_IDLE_MS - (performance.now() - this.silentSince)));
|
|
865
|
-
this.silenceTimer.unref?.();
|
|
866
|
-
}
|
|
867
|
-
clearSilenceTimer() {
|
|
868
|
-
clearTimeout(this.silenceTimer);
|
|
869
|
-
this.silenceTimer = void 0;
|
|
870
|
-
}
|
|
871
|
-
waitForDrain() {
|
|
872
|
-
if (this.drainHandler || this.closed) return;
|
|
873
|
-
logger$3.info(`discord voice: realtime audio playback buffering ${this.params.logContext} bufferedBytes=${this.stream.writableLength + this.stream.readableLength}`);
|
|
874
|
-
this.drainHandler = () => {
|
|
875
|
-
this.drainHandler = void 0;
|
|
876
|
-
if (this.closed) return;
|
|
877
|
-
let refreshWatchdog = this.activity.snapshot().streamEnding;
|
|
878
|
-
while (this.buffers.length > 0) {
|
|
879
|
-
const buffered = this.buffers.shift();
|
|
880
|
-
if (!buffered) break;
|
|
881
|
-
this.bufferedBytes -= buffered.length;
|
|
882
|
-
const writable = this.stream.write(buffered);
|
|
883
|
-
if (refreshWatchdog) {
|
|
884
|
-
this.scheduleWatchdog("output-drain");
|
|
885
|
-
refreshWatchdog = false;
|
|
886
|
-
}
|
|
887
|
-
if (!writable) {
|
|
888
|
-
this.waitForDrain();
|
|
889
|
-
return;
|
|
890
|
-
}
|
|
891
|
-
}
|
|
892
|
-
if (this.activity.snapshot().streamEnding) this.stream.end();
|
|
893
|
-
};
|
|
894
|
-
this.stream.once("drain", this.drainHandler);
|
|
895
|
-
}
|
|
896
|
-
scheduleWatchdog(reason) {
|
|
897
|
-
this.clearWatchdog();
|
|
898
|
-
const timeoutMs = this.activity.playbackWatchdogDelayMs({
|
|
899
|
-
marginMs: DISCORD_REALTIME_OUTPUT_PLAYBACK_WATCHDOG_MARGIN_MS,
|
|
900
|
-
minMs: DISCORD_REALTIME_OUTPUT_PLAYBACK_WATCHDOG_MARGIN_MS
|
|
831
|
+
setDiscordAudioOutputStatus(this.clock, DiscordAudioOutputStatus.Closed);
|
|
832
|
+
this.params.player.audio.send({
|
|
833
|
+
type: "output-close",
|
|
834
|
+
id: this.id,
|
|
835
|
+
reason
|
|
901
836
|
});
|
|
902
|
-
|
|
903
|
-
this.watchdog = setTimeout(() => {
|
|
904
|
-
this.watchdog = void 0;
|
|
905
|
-
logger$3.warn(`discord voice: realtime audio playback watchdog fired reason=${reason} ${this.params.logContext} audioMs=${Math.floor(this.activity.snapshot().audioMs)} elapsedMs=${this.activity.elapsedPlaybackMs()}`);
|
|
906
|
-
this.close("playback-watchdog");
|
|
907
|
-
}, timeoutMs);
|
|
837
|
+
this.retire(reason);
|
|
908
838
|
}
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
this.
|
|
839
|
+
retire(reason) {
|
|
840
|
+
if (this.closed) return;
|
|
841
|
+
this.playbackItems();
|
|
842
|
+
this.closed = true;
|
|
843
|
+
this.marks.clear();
|
|
844
|
+
this.params.player.audio.off("event", this.onEvent);
|
|
845
|
+
this.params.player.audio.off("stopped", this.onStopped);
|
|
846
|
+
this.unregister();
|
|
847
|
+
this.params.onClose(this, reason);
|
|
912
848
|
}
|
|
913
849
|
};
|
|
914
850
|
//#endregion
|
|
@@ -930,12 +866,14 @@ function normalizeControlSpeechText(text) {
|
|
|
930
866
|
var DiscordRealtimePlayback = class {
|
|
931
867
|
constructor(params) {
|
|
932
868
|
this.params = params;
|
|
869
|
+
this.outputClearGeneration = 0;
|
|
933
870
|
this.outputs = /* @__PURE__ */ new Set();
|
|
934
871
|
this.generatingItems = /* @__PURE__ */ new Map();
|
|
935
872
|
this.responseAudio = "completed";
|
|
936
873
|
this.queuedExactSpeechMessages = [];
|
|
937
874
|
this.retainedSpeechClosed = false;
|
|
938
875
|
this.exactSpeechState = { status: "idle" };
|
|
876
|
+
this.nextExactSpeechEpoch = 0n;
|
|
939
877
|
this.wakeNameAckIndex = 0;
|
|
940
878
|
this.unregisterPlayerLane = this.params.player.registerLane({
|
|
941
879
|
hasOutput: () => this.isOutputAudioActive(),
|
|
@@ -943,16 +881,77 @@ var DiscordRealtimePlayback = class {
|
|
|
943
881
|
cancelForControl: () => this.cancelForControl()
|
|
944
882
|
});
|
|
945
883
|
}
|
|
884
|
+
/** Only continuous provider media uses this generation-scoped, PCM24k mono port. */
|
|
885
|
+
createOutputAudioPort(enabled = true) {
|
|
886
|
+
this.directOutput?.close();
|
|
887
|
+
const { port1, port2 } = new MessageChannel();
|
|
888
|
+
const id = this.params.entry.audio.allocateId();
|
|
889
|
+
const state = new Int32Array(new SharedArrayBuffer(4));
|
|
890
|
+
const clock = new BigInt64Array(new SharedArrayBuffer(24));
|
|
891
|
+
const unregister = this.params.player.registerOutput(id, (reason) => this.handleBargeIn(reason));
|
|
892
|
+
const onEvent = (event) => {
|
|
893
|
+
if (!("id" in event) || event.id !== id || this.directOutput?.id !== id) return;
|
|
894
|
+
if ((event.type === "continuous-start" || event.type === "continuous-idle") && this.exactSpeechState.status === "active" && this.exactSpeechState.direct && event.speechEpoch !== this.exactSpeechState.direct.epoch) return;
|
|
895
|
+
if (event.type === "continuous-error") this.stopAfterPlaybackFailure("direct-output-error", restoreDiscordAudioError(event.error));
|
|
896
|
+
if (event.type === "continuous-start") this.params.harness.outputActivity.markPlaybackStarted();
|
|
897
|
+
if (event.type === "continuous-flushed" && event.marker === this.pendingDirectCompletion) {
|
|
898
|
+
this.pendingDirectCompletion = void 0;
|
|
899
|
+
this.responseAudio = "completed";
|
|
900
|
+
this.completeExactSpeechResponse("provider-completed");
|
|
901
|
+
}
|
|
902
|
+
if (event.type === "continuous-idle") {
|
|
903
|
+
this.responseAudio = "completed";
|
|
904
|
+
this.params.harness.finishOutputAudio("player-idle");
|
|
905
|
+
this.params.harness.outputActivity.reset();
|
|
906
|
+
this.completeExactSpeechResponse("player-idle");
|
|
907
|
+
}
|
|
908
|
+
};
|
|
909
|
+
const close = () => {
|
|
910
|
+
Atomics.store(state, 0, 1);
|
|
911
|
+
this.params.entry.audio.off("event", onEvent);
|
|
912
|
+
unregister();
|
|
913
|
+
this.params.entry.audio.send({
|
|
914
|
+
type: "continuous-close",
|
|
915
|
+
id
|
|
916
|
+
});
|
|
917
|
+
if (this.directOutput?.id === id) this.directOutput = void 0;
|
|
918
|
+
};
|
|
919
|
+
this.directOutput = {
|
|
920
|
+
id,
|
|
921
|
+
clock,
|
|
922
|
+
close
|
|
923
|
+
};
|
|
924
|
+
this.params.entry.audio.on("event", onEvent);
|
|
925
|
+
this.params.entry.audio.send({
|
|
926
|
+
type: "continuous-port",
|
|
927
|
+
id,
|
|
928
|
+
enabled,
|
|
929
|
+
port: port1,
|
|
930
|
+
state: state.buffer,
|
|
931
|
+
clock: clock.buffer
|
|
932
|
+
}, [port1]);
|
|
933
|
+
return {
|
|
934
|
+
port: port2,
|
|
935
|
+
state: state.buffer
|
|
936
|
+
};
|
|
937
|
+
}
|
|
938
|
+
activateOutputAudioPort() {
|
|
939
|
+
if (this.directOutput) this.params.entry.audio.send({
|
|
940
|
+
type: "continuous-activate",
|
|
941
|
+
id: this.directOutput.id
|
|
942
|
+
});
|
|
943
|
+
}
|
|
946
944
|
close(preserveUnplayedSpeech = false) {
|
|
947
945
|
this.unregisterPlayerLane();
|
|
948
|
-
if (preserveUnplayedSpeech) this.
|
|
946
|
+
if (preserveUnplayedSpeech) this.retireExactSpeech(true);
|
|
949
947
|
else {
|
|
950
948
|
this.retainedSpeechClosed = true;
|
|
951
949
|
this.speechSuccessor = void 0;
|
|
952
950
|
this.queuedExactSpeechMessages = [];
|
|
953
|
-
this.
|
|
951
|
+
this.retireExactSpeech();
|
|
954
952
|
}
|
|
955
953
|
this.clearOutputAudio("session-close");
|
|
954
|
+
this.directOutput?.close();
|
|
956
955
|
}
|
|
957
956
|
transferPendingSpeechTo(target) {
|
|
958
957
|
this.speechSuccessor = target;
|
|
@@ -970,13 +969,14 @@ var DiscordRealtimePlayback = class {
|
|
|
970
969
|
return false;
|
|
971
970
|
}
|
|
972
971
|
logger$2.info(`discord voice: realtime barge-in requested reason=${reason} guild=${this.params.entry.guildId} channel=${this.params.entry.channelId} outputAudioMs=${this.outputAudioMs()} outputActive=${this.isOutputAudioActive()} playbackChunks=${this.params.harness.outputActivity.snapshot().chunks}`);
|
|
972
|
+
const clearGeneration = this.outputClearGeneration;
|
|
973
973
|
const bridge = this.params.bridge();
|
|
974
974
|
const outputs = Array.from(this.outputs);
|
|
975
975
|
const items = Array.from(this.generatingItems.values());
|
|
976
976
|
this.params.harness.handleBargeIn({ audioPlaybackActive: true }, () => {
|
|
977
977
|
if (!bridge?.bridge.handleBargeIn) this.clearOutputAudio(reason);
|
|
978
978
|
});
|
|
979
|
-
return outputs.some((output) => !this.outputs.has(output)) || items.some((item) => this.generatingItems.get(item.itemId) !== item);
|
|
979
|
+
return clearGeneration !== this.outputClearGeneration || outputs.some((output) => !this.outputs.has(output)) || items.some((item) => this.generatingItems.get(item.itemId) !== item);
|
|
980
980
|
}
|
|
981
981
|
isBargeInEnabled() {
|
|
982
982
|
if (this.params.wakeNameRequired()) return false;
|
|
@@ -1043,10 +1043,15 @@ var DiscordRealtimePlayback = class {
|
|
|
1043
1043
|
this.generatingItems.set(metadata.itemId, item);
|
|
1044
1044
|
}
|
|
1045
1045
|
}
|
|
1046
|
-
this.params.harness.recordOutputAudio(realtimePcm24kMono, activity);
|
|
1047
|
-
output.append(realtimePcm24kMono, audible, item)
|
|
1046
|
+
const onAccepted = () => this.params.harness.recordOutputAudio(realtimePcm24kMono, activity);
|
|
1047
|
+
if (!output.append(realtimePcm24kMono, audible, item, onAccepted)) {
|
|
1048
|
+
this.generatingOutput = void 0;
|
|
1049
|
+
this.sendOutputAudio(realtimePcm24kMono, metadata);
|
|
1050
|
+
}
|
|
1048
1051
|
}
|
|
1049
1052
|
clearOutputAudio(reason = "clear") {
|
|
1053
|
+
this.outputClearGeneration += 1;
|
|
1054
|
+
this.retireExactSpeech();
|
|
1050
1055
|
if (this.isContinuousOutput()) this.responseAudio = "completed";
|
|
1051
1056
|
else if (this.responseAudio === "accepting") this.responseAudio = "discarding";
|
|
1052
1057
|
this.generatingOutput = void 0;
|
|
@@ -1055,9 +1060,26 @@ var DiscordRealtimePlayback = class {
|
|
|
1055
1060
|
this.outputs.clear();
|
|
1056
1061
|
for (const output of outputs.toReversed()) output.close(reason);
|
|
1057
1062
|
this.params.harness.outputActivity.reset();
|
|
1063
|
+
if (this.directOutput) {
|
|
1064
|
+
if (reason === "session-close" || this.params.stopped()) this.directOutput.close();
|
|
1065
|
+
else this.params.entry.audio.send({
|
|
1066
|
+
type: "continuous-clear",
|
|
1067
|
+
id: this.directOutput.id
|
|
1068
|
+
});
|
|
1069
|
+
}
|
|
1058
1070
|
this.completeExactSpeechResponse(reason);
|
|
1059
1071
|
}
|
|
1060
1072
|
handleResponseDone(outcome) {
|
|
1073
|
+
if (this.directOutput && outcome.status === "completed") {
|
|
1074
|
+
const marker = this.params.entry.audio.allocateId();
|
|
1075
|
+
this.pendingDirectCompletion = marker;
|
|
1076
|
+
this.params.entry.audio.send({
|
|
1077
|
+
type: "continuous-flush",
|
|
1078
|
+
id: this.directOutput.id,
|
|
1079
|
+
marker
|
|
1080
|
+
});
|
|
1081
|
+
return;
|
|
1082
|
+
}
|
|
1061
1083
|
const output = this.generatingOutput;
|
|
1062
1084
|
this.generatingOutput = void 0;
|
|
1063
1085
|
this.generatingItems.clear();
|
|
@@ -1122,8 +1144,12 @@ var DiscordRealtimePlayback = class {
|
|
|
1122
1144
|
}
|
|
1123
1145
|
cancelForControl() {
|
|
1124
1146
|
this.queuedExactSpeechMessages = [];
|
|
1125
|
-
this.
|
|
1126
|
-
if (this.responseAudio === "completed" && this.
|
|
1147
|
+
this.retireExactSpeech();
|
|
1148
|
+
if (this.responseAudio === "completed" && !this.isOutputAudioActive()) return;
|
|
1149
|
+
if (this.isContinuousOutput()) {
|
|
1150
|
+
this.params.harness.flushOutput(() => this.clearOutputAudio("active-run-control"));
|
|
1151
|
+
return;
|
|
1152
|
+
}
|
|
1127
1153
|
this.params.harness.handleBargeIn({
|
|
1128
1154
|
audioPlaybackActive: true,
|
|
1129
1155
|
force: true
|
|
@@ -1147,22 +1173,25 @@ var DiscordRealtimePlayback = class {
|
|
|
1147
1173
|
}
|
|
1148
1174
|
resetProviderContinuity(reason) {
|
|
1149
1175
|
this.lastControlSpeech = void 0;
|
|
1150
|
-
this.
|
|
1176
|
+
this.retireExactSpeech(true);
|
|
1151
1177
|
this.responseAudio = "discarding";
|
|
1152
1178
|
this.params.harness.flushOutput(() => this.clearOutputAudio(reason));
|
|
1153
1179
|
this.responseAudio = "completed";
|
|
1154
1180
|
this.params.harness.finishOutputAudio(reason);
|
|
1155
1181
|
}
|
|
1156
|
-
|
|
1157
|
-
|
|
1182
|
+
retireExactSpeech(preserveUnplayed = false) {
|
|
1183
|
+
this.pendingDirectCompletion = void 0;
|
|
1184
|
+
const speech = this.exactSpeechState;
|
|
1158
1185
|
this.exactSpeechState = { status: "idle" };
|
|
1159
|
-
if (
|
|
1186
|
+
if (speech.status !== "active") return;
|
|
1187
|
+
const directStarted = speech.direct && Atomics.exchange(speech.direct.clock, 2, 0n) === -speech.direct.epoch;
|
|
1188
|
+
if (preserveUnplayed && !directStarted && !speech.output?.activity.snapshot().playbackStarted) this.queuedExactSpeechMessages.unshift(speech.message);
|
|
1160
1189
|
}
|
|
1161
1190
|
outputAudioMs() {
|
|
1162
|
-
return Math.floor(this.params.harness.outputActivity.snapshot().audioMs);
|
|
1191
|
+
return this.directOutput ? Math.floor(Number(Atomics.load(this.directOutput.clock, 1)) / 48) : Math.floor(this.params.harness.outputActivity.snapshot().audioMs);
|
|
1163
1192
|
}
|
|
1164
1193
|
isOutputAudioActive() {
|
|
1165
|
-
return this.outputs.size > 0 || this.generatingItems.size > 0;
|
|
1194
|
+
return this.outputs.size > 0 || this.generatingItems.size > 0 || this.directOutput !== void 0 && Atomics.load(this.directOutput.clock, 0) > 0n;
|
|
1166
1195
|
}
|
|
1167
1196
|
isContinuousOutput() {
|
|
1168
1197
|
return this.params.bridge()?.bridge.outputAudioMode === "continuous";
|
|
@@ -1172,7 +1201,7 @@ var DiscordRealtimePlayback = class {
|
|
|
1172
1201
|
this.speechSuccessor = void 0;
|
|
1173
1202
|
this.params.stopTerminally();
|
|
1174
1203
|
this.queuedExactSpeechMessages = [];
|
|
1175
|
-
this.
|
|
1204
|
+
this.retireExactSpeech();
|
|
1176
1205
|
this.clearOutputAudio(reason);
|
|
1177
1206
|
this.params.onTerminalError(error);
|
|
1178
1207
|
}
|
|
@@ -1214,16 +1243,22 @@ var DiscordRealtimePlayback = class {
|
|
|
1214
1243
|
}
|
|
1215
1244
|
sendExactSpeechMessage(text) {
|
|
1216
1245
|
if (this.params.stopped() || !text.trim()) return;
|
|
1246
|
+
const direct = this.directOutput ? {
|
|
1247
|
+
clock: this.directOutput.clock,
|
|
1248
|
+
epoch: ++this.nextExactSpeechEpoch
|
|
1249
|
+
} : void 0;
|
|
1217
1250
|
this.exactSpeechState = {
|
|
1218
1251
|
status: "active",
|
|
1219
|
-
message: text
|
|
1252
|
+
message: text,
|
|
1253
|
+
direct
|
|
1220
1254
|
};
|
|
1255
|
+
if (direct) Atomics.store(direct.clock, 2, direct.epoch);
|
|
1221
1256
|
this.beginResponse();
|
|
1222
1257
|
this.params.bridge()?.sendUserMessage(this.params.buildSpeakExactMessage(text));
|
|
1223
1258
|
}
|
|
1224
1259
|
completeExactSpeechResponse(reason) {
|
|
1225
|
-
if (this.responseAudio !== "completed" || this.
|
|
1226
|
-
this.
|
|
1260
|
+
if (this.pendingDirectCompletion !== void 0 || this.responseAudio !== "completed" || this.isOutputAudioActive()) return;
|
|
1261
|
+
this.retireExactSpeech();
|
|
1227
1262
|
this.drainQueuedExactSpeechMessages(reason);
|
|
1228
1263
|
}
|
|
1229
1264
|
};
|
|
@@ -1548,6 +1583,7 @@ var DiscordRealtimeSpeakerSession = class {
|
|
|
1548
1583
|
}
|
|
1549
1584
|
const humanParticipantCount = this.humanParticipantCount();
|
|
1550
1585
|
logger$1.info(`discord voice: realtime bridge starting mode=${this.params.mode} provider=${resolved.provider.id} model=${resolvedModel ?? "default"} voice=${resolvedVoice ?? "default"} consultPolicy=${consultPolicy} toolPolicy=${toolPolicy} autoRespond=${autoRespondToAudio} wakeNamePolicy=${this.wakeNamePolicy} requireWakeName=${this.isWakeNameRequired(humanParticipantCount)} humanParticipants=${humanParticipantCount} wakeNames=${this.wakeNames.join(",") || "none"} interruptResponse=${interruptResponseOnInputAudio} bargeIn=${bargeIn} minBargeInAudioEndMs=${minBargeInAudioEndMs}`);
|
|
1586
|
+
this.attachOutputAudioPort();
|
|
1551
1587
|
await this.bridge.connect();
|
|
1552
1588
|
if (!this.markLifecycleReady(lifecycleGeneration)) {
|
|
1553
1589
|
await this.close();
|
|
@@ -1671,6 +1707,11 @@ var DiscordRealtimeSpeakerSession = class {
|
|
|
1671
1707
|
activateOutput() {
|
|
1672
1708
|
this.readVoiceSelection();
|
|
1673
1709
|
this.outputEnabled = true;
|
|
1710
|
+
this.playback.activateOutputAudioPort();
|
|
1711
|
+
}
|
|
1712
|
+
attachOutputAudioPort() {
|
|
1713
|
+
const provider = this.bridge?.bridge;
|
|
1714
|
+
if (this.wakeNamePolicy === "never" && provider?.outputAudioMode === "continuous" && provider.setAudioOutputPort) provider.setAudioOutputPort(this.playback.createOutputAudioPort(this.outputEnabled));
|
|
1674
1715
|
}
|
|
1675
1716
|
hasActiveInput() {
|
|
1676
1717
|
return this.captures.size > 0;
|
|
@@ -1795,7 +1836,7 @@ var DiscordRealtimeVoiceSession = class {
|
|
|
1795
1836
|
this.changingVoice = false;
|
|
1796
1837
|
this.callAbort = new AbortController();
|
|
1797
1838
|
this.candidates = /* @__PURE__ */ new Set();
|
|
1798
|
-
this.player = new DiscordRealtimePlayer(params.entry.
|
|
1839
|
+
this.player = new DiscordRealtimePlayer(params.entry.audio);
|
|
1799
1840
|
}
|
|
1800
1841
|
async connect() {
|
|
1801
1842
|
if (this.closed) throw new Error("Discord realtime voice session is closed");
|