@openclaw/discord 2026.9.5 → 2026.9.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (517) hide show
  1. package/assets/icon.png +0 -0
  2. package/dist/.setup/{account-inspect-BwQj24ht.mjs → account-inspect-De8hOUxG.mjs} +1 -1
  3. package/dist/.setup/{accounts-CwJQoLjM.mjs → accounts-ChaMcixG.mjs} +1 -4
  4. package/dist/.setup/{activities-api-DBwRt5ES.mjs → activities-api-tvbsU2e3.mjs} +38 -66
  5. package/dist/.setup/{api-CBK9zcq5.mjs → api-DVbJwZVt.mjs} +10 -2
  6. package/dist/.setup/{approval-handler.runtime-Du3n5ypX.mjs → approval-handler.runtime-DxCK2Rux.mjs} +49 -125
  7. package/dist/.setup/{approval-message-updates-BN7JtScm.mjs → approval-message-updates-BKFqavHZ.mjs} +2 -2
  8. package/dist/.setup/{audit-C8uaKoa9.mjs → audit-CLg9I71N.mjs} +5 -5
  9. package/dist/.setup/{channel-ChKdlBgH.mjs → channel-DxlUVU9t.mjs} +125 -228
  10. package/dist/.setup/{channel-type-DKnjV1XW.mjs → channel-type-DRCrEMss.mjs} +22 -22
  11. package/dist/.setup/{channel.setup-BlC3-Kzz.mjs → channel.setup-CRo1GjV7.mjs} +6 -9
  12. package/dist/.setup/{components-MqMWUWnE.mjs → components-Cq1PvIpN.mjs} +42 -71
  13. package/dist/.setup/{config-schema-CiZz-mtA.mjs → config-schema-oxELUSDx.mjs} +19 -44
  14. package/dist/.setup/{conversation-binding-route-_rz33QHO.mjs → conversation-binding-route-Caz_XuFH.mjs} +14 -6
  15. package/dist/.setup/{directory-config-BytTftz-.mjs → directory-config-esqNn0Eo.mjs} +6 -9
  16. package/dist/.setup/{directory-live--EGTH0DC.mjs → directory-live-DtKRHuGV.mjs} +6 -12
  17. package/dist/.setup/{discord-BXpHW-cu.mjs → discord-0xJYfdDD.mjs} +82 -386
  18. package/dist/.setup/{doctor-DxcdkXzz.mjs → doctor-BCl1H5tl.mjs} +21 -36
  19. package/dist/.setup/{doctor-contract-Co5vRCZ6.mjs → doctor-contract-CvvgwrrG.mjs} +41 -50
  20. package/dist/.setup/{channel-actions.runtime-CJmiFfps.mjs → handle-action-CUvQWnE7.mjs} +74 -105
  21. package/dist/.setup/{handle-action.guild-admin-DAFyh_yV.mjs → handle-action.guild-admin-Df-8gVle.mjs} +63 -121
  22. package/dist/.setup/{live-policy-config-eKQ-PLdy.mjs → live-policy-config-8Pv20CHc.mjs} +2 -3
  23. package/dist/.setup/{message-handler-DnUrDpaU.mjs → message-handler-B-Jk4oDk.mjs} +18 -93
  24. package/dist/.setup/message-handler.preflight-pluralkit-CWLUBVcx.mjs +141 -0
  25. package/dist/.setup/{message-handler.preflight-CtqaF_fb.mjs → message-handler.preflight-v-__NSDq.mjs} +73 -287
  26. package/dist/.setup/{message-handler.process-Dz1xvuQU.mjs → message-handler.process-BNFFuChn.mjs} +423 -374
  27. package/dist/.setup/{outbound-adapter-C8v79z9Z.mjs → outbound-adapter-BobT-kse.mjs} +105 -19
  28. package/dist/.setup/{outbound-session-route-CqWbuMOm.mjs → outbound-session-route-zVGxxceg.mjs} +142 -109
  29. package/dist/.setup/{pluralkit-CdAt1G0P.mjs → pluralkit-a6_NLfH9.mjs} +1 -1
  30. package/dist/.setup/{preflight-audio-DrnqFA8U.mjs → preflight-audio-DHGIHEpv.mjs} +2 -1
  31. package/dist/.setup/{presence-cache-dYSHPWMx.mjs → presence-cache-Di3H3DIU.mjs} +0 -4
  32. package/dist/.setup/{probe-CupW4we4.mjs → probe-LYrIHlBF.mjs} +13 -4
  33. package/dist/.setup/{provider-72zIvN-i.mjs → provider-B_G5hASF.mjs} +1112 -1668
  34. package/dist/.setup/provider-session.runtime-BYlTBFD2.mjs +6 -0
  35. package/dist/.setup/provider.runtime-CUE3UxER.mjs +2 -0
  36. package/dist/.setup/{realtime-session.runtime-DTccTgTM.mjs → realtime-session.runtime-oUd9DOcz.mjs} +372 -345
  37. package/dist/.setup/receive-recovery-CHPOsnLc.mjs +514 -0
  38. package/dist/.setup/{resolve-allowlist-common-CwMBzbx9.mjs → resolve-allowlist-common-DPdRggu5.mjs} +4 -7
  39. package/dist/.setup/{resolve-channels-BbvsLQOZ.mjs → resolve-channels-BFPNRmVv.mjs} +21 -40
  40. package/dist/.setup/{resolve-users-ByFlR7LQ.mjs → resolve-users-0-aBuCy3.mjs} +4 -4
  41. package/dist/.setup/{retry-DBfcEgmO.mjs → retry-pz_cSha2.mjs} +81 -16
  42. package/dist/.setup/rolldown-runtime-B4FMCO8f.mjs +28 -0
  43. package/dist/.setup/{runtime-SchNfUsQ.mjs → runtime-FN000lxA.mjs} +83 -166
  44. package/dist/.setup/runtime-doctor-migrations-CshUGl36.mjs +159 -0
  45. package/dist/.setup/{runtime-BVoa7hhx.mjs → runtime-sUksZ--Q.mjs} +2 -5
  46. package/dist/.setup/{secret-config-contract-DFu9hfU8.mjs → secret-config-contract-uOE2J7yM.mjs} +15 -85
  47. package/dist/.setup/{security-audit-s5w50-Ly.mjs → security-audit-Cdaegq7C.mjs} +3 -1
  48. package/dist/.setup/{send-CKDczUNL.mjs → send-CrfEI6Bs.mjs} +73 -114
  49. package/dist/.setup/{send.components-DWQjXhPV.mjs → send.components-DxQAMfES.mjs} +62 -107
  50. package/dist/.setup/{send.outbound-D0hQ7s50.mjs → send.outbound-BISKnb-a.mjs} +79 -154
  51. package/dist/.setup/{send.shared-Zwx6BxQ5.mjs → send.shared-DGFkbkQR.mjs} +10 -25
  52. package/dist/.setup/{sender-identity-0Ymgvmaj.mjs → sender-identity-B9X5Vb9R.mjs} +2 -3
  53. package/dist/.setup/setup-plugin-api-BQUBxbhe.mjs +3 -0
  54. package/dist/.setup/{shared-CaA3Vv4n.mjs → shared-B3wZ4hN-.mjs} +25 -32
  55. package/dist/.setup/{subagent-hooks-Bired9q6.mjs → subagent-hooks-nlUE9ow7.mjs} +5 -6
  56. package/dist/.setup/system-events-CdeZnvPV.mjs +33 -0
  57. package/dist/.setup/{target-resolver-B6MrxbYv.mjs → target-resolver-BuLapkhy.mjs} +9 -12
  58. package/dist/.setup/targets-0KUcEIYx.mjs +3 -0
  59. package/dist/.setup/{thread-bindings-CK5272V3.mjs → thread-bindings-D7TfgjR_.mjs} +33 -35
  60. package/dist/.setup/thread-bindings.manager-DN-NissX.mjs +819 -0
  61. package/dist/.setup/thread-bindings.session-updates-CshfKghV.mjs +359 -0
  62. package/dist/.setup/{thread-bindings.state-BThFQEga.mjs → thread-bindings.state-g6v9zAym.mjs} +21 -62
  63. package/dist/.setup/{transcripts-source-CuWYgayu.mjs → transcripts-source-p8EV179h.mjs} +133 -238
  64. package/dist/.setup/{typing-BKZL5fGj.mjs → typing-BiHCzBRu.mjs} +2 -1
  65. package/dist/.setup/{voice-runtime-DHVQ2mFz.mjs → voice-runtime-B46rcwrG.mjs} +633 -1085
  66. package/dist/account-inspect-api.js +1 -1
  67. package/dist/action-runtime-api.js +1 -1
  68. package/dist/activities-api.js +1 -1
  69. package/dist/api.js +18 -18
  70. package/dist/channel-config-api.js +1 -1
  71. package/dist/channel-plugin-api.js +1 -1
  72. package/dist/directory-contract-api.js +1 -1
  73. package/dist/doctor-contract-api.js +4 -4
  74. package/dist/index.js +1 -1
  75. package/dist/runtime-api.js +20 -20
  76. package/dist/secret-contract-api.js +1 -1
  77. package/dist/security-audit-contract-api.js +1 -1
  78. package/dist/setup-entry.js +1 -1
  79. package/dist/setup-plugin-api.js +1 -1
  80. package/dist/src/voice/audio-worker.runtime.js +1056 -0
  81. package/dist/subagent-hooks-api.js +3 -4
  82. package/dist/transcripts-source-api.js +1 -1
  83. package/node_modules/@napi-rs/wasm-runtime/dist/emnapi-plugins.cjs +8 -4
  84. package/node_modules/@napi-rs/wasm-runtime/dist/emnapi-plugins.js +8 -4
  85. package/node_modules/@napi-rs/wasm-runtime/dist/fs-proxy.cjs +1 -1
  86. package/node_modules/@napi-rs/wasm-runtime/dist/fs.js +770 -695
  87. package/node_modules/@napi-rs/wasm-runtime/fs-proxy.js +3 -2
  88. package/node_modules/@napi-rs/wasm-runtime/package.json +1 -1
  89. package/node_modules/@tybys/wasm-util/LICENSE +21 -0
  90. package/node_modules/@tybys/wasm-util/package.json +1 -1
  91. package/node_modules/@types/node/README.md +2 -2
  92. package/node_modules/@types/node/child_process.d.ts +1 -1
  93. package/node_modules/@types/node/crypto.d.ts +20 -8
  94. package/node_modules/@types/node/ffi.d.ts +14 -0
  95. package/node_modules/@types/node/http2.d.ts +3 -2
  96. package/node_modules/@types/node/net.d.ts +16 -4
  97. package/node_modules/@types/node/package.json +2 -17
  98. package/node_modules/@types/node/process.d.ts +1 -0
  99. package/node_modules/@types/node/quic.d.ts +39 -1
  100. package/node_modules/@types/node/stream/iter.d.ts +9 -12
  101. package/node_modules/@types/node/test/reporters.d.ts +1 -0
  102. package/node_modules/@types/node/test.d.ts +72 -0
  103. package/node_modules/@types/node/tls.d.ts +14 -10
  104. package/node_modules/@types/node/vm.d.ts +2 -1
  105. package/node_modules/@types/node/web-globals/streams.d.ts +4 -0
  106. package/node_modules/@types/node/worker_threads.d.ts +4 -1
  107. package/node_modules/typebox/build/compile/code.mjs +1 -2
  108. package/node_modules/typebox/build/compile/validator.mjs +5 -1
  109. package/node_modules/typebox/build/format/iri.mjs +16 -9
  110. package/node_modules/typebox/build/guard/emit.mjs +2 -2
  111. package/node_modules/typebox/build/guard/guard.d.mts +7 -5
  112. package/node_modules/typebox/build/guard/guard.mjs +14 -9
  113. package/node_modules/typebox/build/guard/index.mjs +6 -0
  114. package/node_modules/typebox/build/guard/unicode/unicode.d.mts +6 -0
  115. package/node_modules/typebox/build/guard/unicode/unicode.mjs +35 -0
  116. package/node_modules/typebox/build/guard/{string.mjs → unicode/unicode_segment.mjs} +16 -19
  117. package/node_modules/typebox/build/schema/build.mjs +2 -3
  118. package/node_modules/typebox/build/schema/engine/_pathing.d.mts +1 -0
  119. package/node_modules/typebox/build/schema/engine/_pathing.mjs +11 -0
  120. package/node_modules/typebox/build/schema/engine/_refine.mjs +13 -5
  121. package/node_modules/typebox/build/schema/engine/additionalProperties.mjs +2 -1
  122. package/node_modules/typebox/build/schema/engine/dependencies.mjs +2 -1
  123. package/node_modules/typebox/build/schema/engine/dependentSchemas.mjs +2 -1
  124. package/node_modules/typebox/build/schema/engine/dynamicRef.d.mts +1 -1
  125. package/node_modules/typebox/build/schema/engine/dynamicRef.mjs +2 -2
  126. package/node_modules/typebox/build/schema/engine/format.mjs +9 -2
  127. package/node_modules/typebox/build/schema/engine/patternProperties.mjs +3 -2
  128. package/node_modules/typebox/build/schema/engine/properties.mjs +3 -2
  129. package/node_modules/typebox/build/schema/engine/propertyNames.mjs +2 -1
  130. package/node_modules/typebox/build/schema/engine/recursiveRef.d.mts +1 -1
  131. package/node_modules/typebox/build/schema/engine/recursiveRef.mjs +2 -2
  132. package/node_modules/typebox/build/schema/engine/ref.d.mts +1 -1
  133. package/node_modules/typebox/build/schema/engine/ref.mjs +2 -2
  134. package/node_modules/typebox/build/schema/engine/schema.mjs +24 -24
  135. package/node_modules/typebox/build/schema/parse.mjs +3 -0
  136. package/node_modules/typebox/build/schema/pointer/pointer.d.mts +1 -6
  137. package/node_modules/typebox/build/schema/pointer/pointer.mjs +47 -64
  138. package/node_modules/typebox/build/system/settings/internal.d.mts +2 -0
  139. package/node_modules/typebox/build/system/settings/internal.mjs +20 -0
  140. package/node_modules/typebox/build/system/settings/settings.d.mts +11 -0
  141. package/node_modules/typebox/build/system/settings/settings.mjs +14 -0
  142. package/node_modules/typebox/build/type/extends/inference.d.mts +1 -1
  143. package/node_modules/typebox/build/type/extends/inference.mjs +15 -2
  144. package/node_modules/typebox/build/type/extends/tuple.d.mts +2 -1
  145. package/node_modules/typebox/build/type/extends/tuple.mjs +21 -1
  146. package/node_modules/typebox/build/value/parse/parse.mjs +10 -4
  147. package/node_modules/typebox/package.json +1 -1
  148. package/node_modules/typebox/readme.md +3 -1
  149. package/node_modules/zod/README.md +2 -2
  150. package/node_modules/zod/compile.cjs +19 -0
  151. package/node_modules/zod/index.cjs +19 -0
  152. package/node_modules/zod/locales/index.cjs +19 -0
  153. package/node_modules/zod/mini/index.cjs +19 -0
  154. package/node_modules/zod/package.json +8 -7
  155. package/node_modules/zod/src/v3/helpers/errorUtil.ts +1 -1
  156. package/node_modules/zod/src/v4/classic/external.ts +2 -0
  157. package/node_modules/zod/src/v4/classic/from-json-schema.ts +248 -25
  158. package/node_modules/zod/src/v4/classic/schemas.ts +243 -168
  159. package/node_modules/zod/src/v4/classic/tests/assignability.test.ts +60 -9
  160. package/node_modules/zod/src/v4/classic/tests/bigint.test.ts +6 -0
  161. package/node_modules/zod/src/v4/classic/tests/continuability.test.ts +2 -2
  162. package/node_modules/zod/src/v4/classic/tests/cyclic-data.test.ts +265 -0
  163. package/node_modules/zod/src/v4/classic/tests/discriminated-unions.test.ts +112 -6
  164. package/node_modules/zod/src/v4/classic/tests/enum.test.ts +9 -0
  165. package/node_modules/zod/src/v4/classic/tests/error.test.ts +130 -1
  166. package/node_modules/zod/src/v4/classic/tests/from-json-schema.test.ts +157 -0
  167. package/node_modules/zod/src/v4/classic/tests/iban.test.ts +81 -0
  168. package/node_modules/zod/src/v4/classic/tests/instance-footprint.test.ts +40 -2
  169. package/node_modules/zod/src/v4/classic/tests/instanceof.test.ts +27 -7
  170. package/node_modules/zod/src/v4/classic/tests/issue-schema.test.ts +88 -56
  171. package/node_modules/zod/src/v4/classic/tests/number.test.ts +39 -0
  172. package/node_modules/zod/src/v4/classic/tests/object.test.ts +56 -0
  173. package/node_modules/zod/src/v4/classic/tests/optin-ladder.test.ts +3 -2
  174. package/node_modules/zod/src/v4/classic/tests/prefault.test.ts +70 -0
  175. package/node_modules/zod/src/v4/classic/tests/properties.test.ts +141 -0
  176. package/node_modules/zod/src/v4/classic/tests/recursive-types.test.ts +46 -1
  177. package/node_modules/zod/src/v4/classic/tests/standard-schema.test.ts +19 -0
  178. package/node_modules/zod/src/v4/classic/tests/string.test.ts +95 -1
  179. package/node_modules/zod/src/v4/classic/tests/template-literal.test.ts +33 -1
  180. package/node_modules/zod/src/v4/classic/tests/to-json-schema.test.ts +234 -38
  181. package/node_modules/zod/src/v4/classic/tests/validate.test.ts +569 -0
  182. package/node_modules/zod/src/v4/core/api.ts +44 -28
  183. package/node_modules/zod/src/v4/core/checks.ts +62 -102
  184. package/node_modules/zod/src/v4/core/compile.ts +218 -93
  185. package/node_modules/zod/src/v4/core/core.ts +1 -3
  186. package/node_modules/zod/src/v4/core/doc.ts +6 -2
  187. package/node_modules/zod/src/v4/core/errors.ts +3 -6
  188. package/node_modules/zod/src/v4/core/json-schema-generator.ts +2 -2
  189. package/node_modules/zod/src/v4/core/json-schema-processors.ts +185 -81
  190. package/node_modules/zod/src/v4/core/memoizer.ts +75 -28
  191. package/node_modules/zod/src/v4/core/parse.ts +37 -16
  192. package/node_modules/zod/src/v4/core/regexes.ts +14 -4
  193. package/node_modules/zod/src/v4/core/schemas.ts +296 -132
  194. package/node_modules/zod/src/v4/core/tests/cached.test.ts +54 -0
  195. package/node_modules/zod/src/v4/core/tests/compile-differential.test.ts +35 -0
  196. package/node_modules/zod/src/v4/core/tests/compile-generative.test.ts +445 -0
  197. package/node_modules/zod/src/v4/core/tests/compile.test.ts +399 -2
  198. package/node_modules/zod/src/v4/core/tests/email-regex.test.ts +140 -0
  199. package/node_modules/zod/src/v4/core/tests/locales/tg.test.ts +85 -0
  200. package/node_modules/zod/src/v4/core/tests/polyfill-collision.test.ts +46 -0
  201. package/node_modules/zod/src/v4/core/tests/url-no-canparse.test.ts +118 -16
  202. package/node_modules/zod/src/v4/core/to-json-schema.ts +9 -7
  203. package/node_modules/zod/src/v4/core/util.ts +218 -147
  204. package/node_modules/zod/src/v4/core/versions.ts +2 -2
  205. package/node_modules/zod/src/v4/locales/ar.ts +2 -0
  206. package/node_modules/zod/src/v4/locales/az.ts +2 -0
  207. package/node_modules/zod/src/v4/locales/be.ts +2 -0
  208. package/node_modules/zod/src/v4/locales/bg.ts +2 -0
  209. package/node_modules/zod/src/v4/locales/bn.ts +2 -0
  210. package/node_modules/zod/src/v4/locales/ca.ts +2 -0
  211. package/node_modules/zod/src/v4/locales/ckb.ts +2 -0
  212. package/node_modules/zod/src/v4/locales/cs.ts +2 -0
  213. package/node_modules/zod/src/v4/locales/da.ts +2 -0
  214. package/node_modules/zod/src/v4/locales/de.ts +2 -0
  215. package/node_modules/zod/src/v4/locales/el.ts +2 -0
  216. package/node_modules/zod/src/v4/locales/en.ts +2 -0
  217. package/node_modules/zod/src/v4/locales/eo.ts +2 -0
  218. package/node_modules/zod/src/v4/locales/es.ts +2 -0
  219. package/node_modules/zod/src/v4/locales/fa.ts +2 -0
  220. package/node_modules/zod/src/v4/locales/fi.ts +2 -0
  221. package/node_modules/zod/src/v4/locales/fr-CA.ts +2 -0
  222. package/node_modules/zod/src/v4/locales/fr.ts +2 -0
  223. package/node_modules/zod/src/v4/locales/gu.ts +2 -0
  224. package/node_modules/zod/src/v4/locales/he.ts +2 -0
  225. package/node_modules/zod/src/v4/locales/hi.ts +2 -0
  226. package/node_modules/zod/src/v4/locales/hr.ts +2 -0
  227. package/node_modules/zod/src/v4/locales/hu.ts +2 -0
  228. package/node_modules/zod/src/v4/locales/hy.ts +2 -0
  229. package/node_modules/zod/src/v4/locales/id.ts +2 -0
  230. package/node_modules/zod/src/v4/locales/index.ts +1 -0
  231. package/node_modules/zod/src/v4/locales/is.ts +2 -0
  232. package/node_modules/zod/src/v4/locales/it.ts +2 -0
  233. package/node_modules/zod/src/v4/locales/ja.ts +2 -0
  234. package/node_modules/zod/src/v4/locales/ka.ts +2 -0
  235. package/node_modules/zod/src/v4/locales/km.ts +2 -0
  236. package/node_modules/zod/src/v4/locales/kn.ts +2 -0
  237. package/node_modules/zod/src/v4/locales/ko.ts +2 -0
  238. package/node_modules/zod/src/v4/locales/lt.ts +2 -0
  239. package/node_modules/zod/src/v4/locales/mk.ts +2 -0
  240. package/node_modules/zod/src/v4/locales/ms.ts +2 -0
  241. package/node_modules/zod/src/v4/locales/ne.ts +2 -0
  242. package/node_modules/zod/src/v4/locales/nl.ts +2 -0
  243. package/node_modules/zod/src/v4/locales/nn.ts +2 -0
  244. package/node_modules/zod/src/v4/locales/no.ts +2 -0
  245. package/node_modules/zod/src/v4/locales/ota.ts +2 -0
  246. package/node_modules/zod/src/v4/locales/pl.ts +2 -0
  247. package/node_modules/zod/src/v4/locales/ps.ts +2 -0
  248. package/node_modules/zod/src/v4/locales/pt-BR.ts +2 -0
  249. package/node_modules/zod/src/v4/locales/pt.ts +2 -0
  250. package/node_modules/zod/src/v4/locales/ro.ts +2 -0
  251. package/node_modules/zod/src/v4/locales/ru.ts +2 -0
  252. package/node_modules/zod/src/v4/locales/sk.ts +2 -0
  253. package/node_modules/zod/src/v4/locales/sl.ts +2 -0
  254. package/node_modules/zod/src/v4/locales/sv.ts +2 -0
  255. package/node_modules/zod/src/v4/locales/ta.ts +2 -0
  256. package/node_modules/zod/src/v4/locales/tg.ts +135 -0
  257. package/node_modules/zod/src/v4/locales/th.ts +2 -0
  258. package/node_modules/zod/src/v4/locales/tk.ts +2 -0
  259. package/node_modules/zod/src/v4/locales/tr.ts +2 -0
  260. package/node_modules/zod/src/v4/locales/uk.ts +2 -0
  261. package/node_modules/zod/src/v4/locales/ur.ts +2 -0
  262. package/node_modules/zod/src/v4/locales/uz.ts +2 -0
  263. package/node_modules/zod/src/v4/locales/vi.ts +2 -0
  264. package/node_modules/zod/src/v4/locales/yo.ts +2 -0
  265. package/node_modules/zod/src/v4/locales/zh-CN.ts +2 -0
  266. package/node_modules/zod/src/v4/locales/zh-TW.ts +2 -0
  267. package/node_modules/zod/src/v4/mini/external.ts +2 -0
  268. package/node_modules/zod/src/v4/mini/schemas.ts +32 -7
  269. package/node_modules/zod/src/v4/mini/tests/checks.test.ts +1 -1
  270. package/node_modules/zod/src/v4/mini/tests/computed.test.ts +11 -17
  271. package/node_modules/zod/src/v4/mini/tests/index.test.ts +86 -0
  272. package/node_modules/zod/src/v4/mini/tests/recursive-types.test.ts +16 -0
  273. package/node_modules/zod/src/v4/mini/tests/string.test.ts +23 -0
  274. package/node_modules/zod/v3/ZodError.cjs +19 -0
  275. package/node_modules/zod/v3/errors.cjs +19 -0
  276. package/node_modules/zod/v3/external.cjs +19 -0
  277. package/node_modules/zod/v3/helpers/enumUtil.cjs +19 -0
  278. package/node_modules/zod/v3/helpers/errorUtil.cjs +20 -1
  279. package/node_modules/zod/v3/helpers/errorUtil.js +1 -1
  280. package/node_modules/zod/v3/helpers/parseUtil.cjs +19 -0
  281. package/node_modules/zod/v3/helpers/partialUtil.cjs +19 -0
  282. package/node_modules/zod/v3/helpers/typeAliases.cjs +19 -0
  283. package/node_modules/zod/v3/helpers/util.cjs +19 -0
  284. package/node_modules/zod/v3/index.cjs +19 -0
  285. package/node_modules/zod/v3/standard-schema.cjs +19 -0
  286. package/node_modules/zod/v3/types.cjs +19 -0
  287. package/node_modules/zod/v4/classic/checks.cjs +19 -0
  288. package/node_modules/zod/v4/classic/coerce.cjs +19 -0
  289. package/node_modules/zod/v4/classic/compat.cjs +19 -0
  290. package/node_modules/zod/v4/classic/deep-partial.cjs +19 -0
  291. package/node_modules/zod/v4/classic/errors.cjs +19 -0
  292. package/node_modules/zod/v4/classic/external.cjs +22 -1
  293. package/node_modules/zod/v4/classic/external.d.cts +1 -1
  294. package/node_modules/zod/v4/classic/external.d.ts +1 -1
  295. package/node_modules/zod/v4/classic/external.js +1 -1
  296. package/node_modules/zod/v4/classic/from-json-schema.cjs +264 -24
  297. package/node_modules/zod/v4/classic/from-json-schema.js +245 -24
  298. package/node_modules/zod/v4/classic/in-out.cjs +19 -0
  299. package/node_modules/zod/v4/classic/index.cjs +19 -0
  300. package/node_modules/zod/v4/classic/iso.cjs +19 -0
  301. package/node_modules/zod/v4/classic/parse.cjs +19 -0
  302. package/node_modules/zod/v4/classic/schemas.cjs +100 -35
  303. package/node_modules/zod/v4/classic/schemas.d.cts +15 -1
  304. package/node_modules/zod/v4/classic/schemas.d.ts +15 -1
  305. package/node_modules/zod/v4/classic/schemas.js +77 -33
  306. package/node_modules/zod/v4/core/api.cjs +45 -22
  307. package/node_modules/zod/v4/core/api.d.cts +12 -6
  308. package/node_modules/zod/v4/core/api.d.ts +12 -6
  309. package/node_modules/zod/v4/core/api.js +25 -22
  310. package/node_modules/zod/v4/core/checks.cjs +51 -97
  311. package/node_modules/zod/v4/core/checks.d.cts +17 -1
  312. package/node_modules/zod/v4/core/checks.d.ts +17 -1
  313. package/node_modules/zod/v4/core/checks.js +31 -96
  314. package/node_modules/zod/v4/core/compile.cjs +173 -78
  315. package/node_modules/zod/v4/core/compile.d.cts +18 -4
  316. package/node_modules/zod/v4/core/compile.d.ts +18 -4
  317. package/node_modules/zod/v4/core/compile.js +154 -79
  318. package/node_modules/zod/v4/core/core.cjs +20 -1
  319. package/node_modules/zod/v4/core/core.js +1 -1
  320. package/node_modules/zod/v4/core/doc.cjs +26 -2
  321. package/node_modules/zod/v4/core/doc.js +7 -2
  322. package/node_modules/zod/v4/core/errors.cjs +21 -5
  323. package/node_modules/zod/v4/core/errors.js +2 -5
  324. package/node_modules/zod/v4/core/index.cjs +19 -0
  325. package/node_modules/zod/v4/core/json-schema-generator.cjs +20 -1
  326. package/node_modules/zod/v4/core/json-schema-generator.js +2 -2
  327. package/node_modules/zod/v4/core/json-schema-processors.cjs +188 -72
  328. package/node_modules/zod/v4/core/json-schema-processors.d.cts +16 -0
  329. package/node_modules/zod/v4/core/json-schema-processors.d.ts +16 -0
  330. package/node_modules/zod/v4/core/json-schema-processors.js +170 -74
  331. package/node_modules/zod/v4/core/json-schema.cjs +19 -0
  332. package/node_modules/zod/v4/core/memoizer.cjs +111 -23
  333. package/node_modules/zod/v4/core/memoizer.js +69 -23
  334. package/node_modules/zod/v4/core/parse.cjs +56 -16
  335. package/node_modules/zod/v4/core/parse.js +37 -16
  336. package/node_modules/zod/v4/core/regexes.cjs +31 -6
  337. package/node_modules/zod/v4/core/regexes.d.cts +3 -0
  338. package/node_modules/zod/v4/core/regexes.d.ts +3 -0
  339. package/node_modules/zod/v4/core/regexes.js +10 -4
  340. package/node_modules/zod/v4/core/registries.cjs +19 -0
  341. package/node_modules/zod/v4/core/schemas.cjs +302 -114
  342. package/node_modules/zod/v4/core/schemas.d.cts +28 -8
  343. package/node_modules/zod/v4/core/schemas.d.ts +28 -8
  344. package/node_modules/zod/v4/core/schemas.js +279 -113
  345. package/node_modules/zod/v4/core/standard-schema.cjs +19 -0
  346. package/node_modules/zod/v4/core/to-json-schema.cjs +28 -7
  347. package/node_modules/zod/v4/core/to-json-schema.d.cts +4 -3
  348. package/node_modules/zod/v4/core/to-json-schema.d.ts +4 -3
  349. package/node_modules/zod/v4/core/to-json-schema.js +7 -6
  350. package/node_modules/zod/v4/core/util.cjs +177 -143
  351. package/node_modules/zod/v4/core/util.d.cts +25 -4
  352. package/node_modules/zod/v4/core/util.d.ts +25 -4
  353. package/node_modules/zod/v4/core/util.js +156 -143
  354. package/node_modules/zod/v4/core/versions.cjs +21 -2
  355. package/node_modules/zod/v4/core/versions.d.cts +1 -1
  356. package/node_modules/zod/v4/core/versions.d.ts +1 -1
  357. package/node_modules/zod/v4/core/versions.js +2 -2
  358. package/node_modules/zod/v4/core/visit.cjs +19 -0
  359. package/node_modules/zod/v4/index.cjs +19 -0
  360. package/node_modules/zod/v4/locales/ar.cjs +2 -0
  361. package/node_modules/zod/v4/locales/ar.js +2 -0
  362. package/node_modules/zod/v4/locales/az.cjs +2 -0
  363. package/node_modules/zod/v4/locales/az.js +2 -0
  364. package/node_modules/zod/v4/locales/be.cjs +2 -0
  365. package/node_modules/zod/v4/locales/be.js +2 -0
  366. package/node_modules/zod/v4/locales/bg.cjs +2 -0
  367. package/node_modules/zod/v4/locales/bg.js +2 -0
  368. package/node_modules/zod/v4/locales/bn.cjs +2 -0
  369. package/node_modules/zod/v4/locales/bn.js +2 -0
  370. package/node_modules/zod/v4/locales/ca.cjs +2 -0
  371. package/node_modules/zod/v4/locales/ca.js +2 -0
  372. package/node_modules/zod/v4/locales/ckb.cjs +2 -0
  373. package/node_modules/zod/v4/locales/ckb.js +2 -0
  374. package/node_modules/zod/v4/locales/cs.cjs +2 -0
  375. package/node_modules/zod/v4/locales/cs.js +2 -0
  376. package/node_modules/zod/v4/locales/da.cjs +2 -0
  377. package/node_modules/zod/v4/locales/da.js +2 -0
  378. package/node_modules/zod/v4/locales/de.cjs +2 -0
  379. package/node_modules/zod/v4/locales/de.js +2 -0
  380. package/node_modules/zod/v4/locales/el.cjs +2 -0
  381. package/node_modules/zod/v4/locales/el.js +2 -0
  382. package/node_modules/zod/v4/locales/en.cjs +2 -0
  383. package/node_modules/zod/v4/locales/en.js +2 -0
  384. package/node_modules/zod/v4/locales/eo.cjs +2 -0
  385. package/node_modules/zod/v4/locales/eo.js +2 -0
  386. package/node_modules/zod/v4/locales/es.cjs +2 -0
  387. package/node_modules/zod/v4/locales/es.js +2 -0
  388. package/node_modules/zod/v4/locales/fa.cjs +2 -0
  389. package/node_modules/zod/v4/locales/fa.js +2 -0
  390. package/node_modules/zod/v4/locales/fi.cjs +2 -0
  391. package/node_modules/zod/v4/locales/fi.js +2 -0
  392. package/node_modules/zod/v4/locales/fr-CA.cjs +2 -0
  393. package/node_modules/zod/v4/locales/fr-CA.js +2 -0
  394. package/node_modules/zod/v4/locales/fr.cjs +2 -0
  395. package/node_modules/zod/v4/locales/fr.js +2 -0
  396. package/node_modules/zod/v4/locales/gu.cjs +2 -0
  397. package/node_modules/zod/v4/locales/gu.js +2 -0
  398. package/node_modules/zod/v4/locales/he.cjs +2 -0
  399. package/node_modules/zod/v4/locales/he.js +2 -0
  400. package/node_modules/zod/v4/locales/hi.cjs +2 -0
  401. package/node_modules/zod/v4/locales/hi.js +2 -0
  402. package/node_modules/zod/v4/locales/hr.cjs +2 -0
  403. package/node_modules/zod/v4/locales/hr.js +2 -0
  404. package/node_modules/zod/v4/locales/hu.cjs +2 -0
  405. package/node_modules/zod/v4/locales/hu.js +2 -0
  406. package/node_modules/zod/v4/locales/hy.cjs +2 -0
  407. package/node_modules/zod/v4/locales/hy.js +2 -0
  408. package/node_modules/zod/v4/locales/id.cjs +2 -0
  409. package/node_modules/zod/v4/locales/id.js +2 -0
  410. package/node_modules/zod/v4/locales/index.cjs +22 -1
  411. package/node_modules/zod/v4/locales/index.d.cts +1 -0
  412. package/node_modules/zod/v4/locales/index.d.ts +1 -0
  413. package/node_modules/zod/v4/locales/index.js +1 -0
  414. package/node_modules/zod/v4/locales/is.cjs +2 -0
  415. package/node_modules/zod/v4/locales/is.js +2 -0
  416. package/node_modules/zod/v4/locales/it.cjs +2 -0
  417. package/node_modules/zod/v4/locales/it.js +2 -0
  418. package/node_modules/zod/v4/locales/ja.cjs +2 -0
  419. package/node_modules/zod/v4/locales/ja.js +2 -0
  420. package/node_modules/zod/v4/locales/ka.cjs +2 -0
  421. package/node_modules/zod/v4/locales/ka.js +2 -0
  422. package/node_modules/zod/v4/locales/km.cjs +2 -0
  423. package/node_modules/zod/v4/locales/km.js +2 -0
  424. package/node_modules/zod/v4/locales/kn.cjs +2 -0
  425. package/node_modules/zod/v4/locales/kn.js +2 -0
  426. package/node_modules/zod/v4/locales/ko.cjs +2 -0
  427. package/node_modules/zod/v4/locales/ko.js +2 -0
  428. package/node_modules/zod/v4/locales/lt.cjs +2 -0
  429. package/node_modules/zod/v4/locales/lt.js +2 -0
  430. package/node_modules/zod/v4/locales/mk.cjs +2 -0
  431. package/node_modules/zod/v4/locales/mk.js +2 -0
  432. package/node_modules/zod/v4/locales/ms.cjs +2 -0
  433. package/node_modules/zod/v4/locales/ms.js +2 -0
  434. package/node_modules/zod/v4/locales/ne.cjs +2 -0
  435. package/node_modules/zod/v4/locales/ne.js +2 -0
  436. package/node_modules/zod/v4/locales/nl.cjs +2 -0
  437. package/node_modules/zod/v4/locales/nl.js +2 -0
  438. package/node_modules/zod/v4/locales/nn.cjs +2 -0
  439. package/node_modules/zod/v4/locales/nn.js +2 -0
  440. package/node_modules/zod/v4/locales/no.cjs +2 -0
  441. package/node_modules/zod/v4/locales/no.js +2 -0
  442. package/node_modules/zod/v4/locales/ota.cjs +2 -0
  443. package/node_modules/zod/v4/locales/ota.js +2 -0
  444. package/node_modules/zod/v4/locales/pl.cjs +2 -0
  445. package/node_modules/zod/v4/locales/pl.js +2 -0
  446. package/node_modules/zod/v4/locales/ps.cjs +2 -0
  447. package/node_modules/zod/v4/locales/ps.js +2 -0
  448. package/node_modules/zod/v4/locales/pt-BR.cjs +2 -0
  449. package/node_modules/zod/v4/locales/pt-BR.js +2 -0
  450. package/node_modules/zod/v4/locales/pt.cjs +2 -0
  451. package/node_modules/zod/v4/locales/pt.js +2 -0
  452. package/node_modules/zod/v4/locales/ro.cjs +2 -0
  453. package/node_modules/zod/v4/locales/ro.js +2 -0
  454. package/node_modules/zod/v4/locales/ru.cjs +2 -0
  455. package/node_modules/zod/v4/locales/ru.js +2 -0
  456. package/node_modules/zod/v4/locales/sk.cjs +2 -0
  457. package/node_modules/zod/v4/locales/sk.js +2 -0
  458. package/node_modules/zod/v4/locales/sl.cjs +2 -0
  459. package/node_modules/zod/v4/locales/sl.js +2 -0
  460. package/node_modules/zod/v4/locales/sv.cjs +2 -0
  461. package/node_modules/zod/v4/locales/sv.js +2 -0
  462. package/node_modules/zod/v4/locales/ta.cjs +2 -0
  463. package/node_modules/zod/v4/locales/ta.js +2 -0
  464. package/node_modules/zod/v4/locales/tg.cjs +144 -0
  465. package/node_modules/zod/v4/locales/tg.d.cts +5 -0
  466. package/node_modules/zod/v4/locales/tg.d.ts +4 -0
  467. package/node_modules/zod/v4/locales/tg.js +117 -0
  468. package/node_modules/zod/v4/locales/th.cjs +2 -0
  469. package/node_modules/zod/v4/locales/th.js +2 -0
  470. package/node_modules/zod/v4/locales/tk.cjs +2 -0
  471. package/node_modules/zod/v4/locales/tk.js +2 -0
  472. package/node_modules/zod/v4/locales/tr.cjs +2 -0
  473. package/node_modules/zod/v4/locales/tr.js +2 -0
  474. package/node_modules/zod/v4/locales/uk.cjs +2 -0
  475. package/node_modules/zod/v4/locales/uk.js +2 -0
  476. package/node_modules/zod/v4/locales/ur.cjs +2 -0
  477. package/node_modules/zod/v4/locales/ur.js +2 -0
  478. package/node_modules/zod/v4/locales/uz.cjs +2 -0
  479. package/node_modules/zod/v4/locales/uz.js +2 -0
  480. package/node_modules/zod/v4/locales/vi.cjs +2 -0
  481. package/node_modules/zod/v4/locales/vi.js +2 -0
  482. package/node_modules/zod/v4/locales/yo.cjs +2 -0
  483. package/node_modules/zod/v4/locales/yo.js +2 -0
  484. package/node_modules/zod/v4/locales/zh-CN.cjs +2 -0
  485. package/node_modules/zod/v4/locales/zh-CN.js +2 -0
  486. package/node_modules/zod/v4/locales/zh-TW.cjs +2 -0
  487. package/node_modules/zod/v4/locales/zh-TW.js +2 -0
  488. package/node_modules/zod/v4/mini/checks.cjs +19 -0
  489. package/node_modules/zod/v4/mini/coerce.cjs +19 -0
  490. package/node_modules/zod/v4/mini/deep-partial.cjs +19 -0
  491. package/node_modules/zod/v4/mini/external.cjs +22 -1
  492. package/node_modules/zod/v4/mini/external.d.cts +1 -1
  493. package/node_modules/zod/v4/mini/external.d.ts +1 -1
  494. package/node_modules/zod/v4/mini/external.js +1 -1
  495. package/node_modules/zod/v4/mini/in-out.cjs +19 -0
  496. package/node_modules/zod/v4/mini/index.cjs +19 -0
  497. package/node_modules/zod/v4/mini/iso.cjs +19 -0
  498. package/node_modules/zod/v4/mini/parse.cjs +19 -0
  499. package/node_modules/zod/v4/mini/schemas.cjs +44 -8
  500. package/node_modules/zod/v4/mini/schemas.d.cts +6 -1
  501. package/node_modules/zod/v4/mini/schemas.d.ts +6 -1
  502. package/node_modules/zod/v4/mini/schemas.js +21 -6
  503. package/node_modules/zod/v4-mini/index.cjs +19 -0
  504. package/openclaw.plugin.json +21 -1
  505. package/package.json +9 -6
  506. package/dist/.setup/agent-components.runtime-CEPrf2SY.mjs +0 -4
  507. package/dist/.setup/message-handler.history-CJOsN9w5.mjs +0 -28
  508. package/dist/.setup/probe.runtime-DBQ_AGPe.mjs +0 -2
  509. package/dist/.setup/provider-session.runtime-BW7QrF5C.mjs +0 -6
  510. package/dist/.setup/provider.runtime-DuhmKdDU.mjs +0 -2
  511. package/dist/.setup/security-audit.runtime-DHtYenx9.mjs +0 -2
  512. package/dist/.setup/setup-plugin-api-CINIEBLa.mjs +0 -3
  513. package/dist/.setup/system-events-B2YEEMbS.mjs +0 -34
  514. package/dist/.setup/targets-D1mAB5yO.mjs +0 -3
  515. package/dist/.setup/thread-bindings.manager-eexkKyrG.mjs +0 -678
  516. package/dist/.setup/thread-bindings.session-updates-DCQq1WZ5.mjs +0 -55
  517. /package/node_modules/typebox/build/guard/{string.d.mts → unicode/unicode_segment.d.mts} +0 -0
@@ -1,16 +1,83 @@
1
- import { a as buildProviderConfigs, i as buildProviderConfigOverrides } from "./transcripts-source-CuWYgayu.mjs";
2
- import { n as discordRealtimeVoiceSecretOwnerId } from "./secret-config-contract-DFu9hfU8.mjs";
3
- import { _ as loadDiscordVoiceSdk, a as createDiscordPcmToRealtimeConverter, c as handleDiscordVoiceAgentControlToolCall, d as formatRealtimeInterruptionLog, f as formatRealtimeLifecycleLog, g as DiscordRealtimePlayer, h as DISCORD_REALTIME_PLAYBACK_IDLE_MS, i as createDiscordOpusEncodeStream, l as logDiscordVoiceAgentControlResult, m as shouldLogRealtimeVerboseEvent, n as DiscordRealtimeRecording, o as createRealtimePcmToDiscordConverter, p as formatVoiceLogPreview, r as logVoiceVerbose, s as formatVoiceIngressPrompt, u as maybeControlDiscordVoiceAgentRun } from "./voice-runtime-DHVQ2mFz.mjs";
1
+ import { _ as releaseDiscordAudioInput, g as getDiscordAudioOutputStatus, h as admitDiscordAudioInput, m as DiscordAudioOutputStatus, u as createDiscordPcmToRealtimeConverter, v as restoreDiscordAudioError, x as setDiscordAudioOutputStatus } from "./receive-recovery-CHPOsnLc.mjs";
2
+ import { n as discordRealtimeVoiceSecretOwnerId } from "./secret-config-contract-uOE2J7yM.mjs";
3
+ import { g as logVoiceVerbose } from "./provider-B_G5hASF.mjs";
4
+ import { a as logDiscordVoiceAgentControlResult, c as formatRealtimeLifecycleLog, i as handleDiscordVoiceAgentControlToolCall, l as formatVoiceLogPreview, n as DiscordRealtimeRecording, o as maybeControlDiscordVoiceAgentRun, r as formatVoiceIngressPrompt, s as formatRealtimeInterruptionLog, u as shouldLogRealtimeVerboseEvent } from "./voice-runtime-B46rcwrG.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";
9
+ import { normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
8
10
  import { createSubsystemLogger } from "openclaw/plugin-sdk/runtime-env";
9
11
  import { sliceUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
12
+ import { MessageChannel } from "node:worker_threads";
10
13
  import { createDeferred } from "openclaw/plugin-sdk/extension-shared";
11
14
  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
15
  import { assertSecretOwnerAvailable, isSecretOwnerAvailable } from "openclaw/plugin-sdk/channel-secret-owner-runtime";
16
+ //#region extensions/discord/src/voice/realtime-player.ts
17
+ /** Room-level policy stays on main; the worker owns the physical player and FIFO. */
18
+ var DiscordRealtimePlayer = class {
19
+ constructor(audio) {
20
+ this.audio = audio;
21
+ this.lanes = /* @__PURE__ */ new Set();
22
+ this.outputs = /* @__PURE__ */ new Map();
23
+ this.closed = false;
24
+ this.onEvent = (event) => {
25
+ if (event.type === "output-start" || event.type === "continuous-start") this.current = event.id;
26
+ if ((event.type === "output-close" || event.type === "continuous-idle") && this.current === event.id) this.current = void 0;
27
+ };
28
+ audio.on("event", this.onEvent);
29
+ }
30
+ registerLane(lane) {
31
+ this.lanes.add(lane);
32
+ return () => this.lanes.delete(lane);
33
+ }
34
+ registerOutput(id, onBargeIn) {
35
+ this.outputs.set(id, onBargeIn);
36
+ return () => {
37
+ this.outputs.delete(id);
38
+ if (this.current === id) this.current = void 0;
39
+ };
40
+ }
41
+ handleBargeIn(reason = "barge-in") {
42
+ const current = this.current === void 0 ? void 0 : this.outputs.get(this.current);
43
+ if (current) return current(reason);
44
+ let interrupted = false;
45
+ for (const lane of [...this.lanes].filter((candidate) => candidate.hasOutput())) interrupted = lane.onBargeIn(reason) || interrupted;
46
+ return interrupted;
47
+ }
48
+ isActive() {
49
+ return this.current !== void 0 || [...this.lanes].some((lane) => lane.hasOutput());
50
+ }
51
+ cancelForControl() {
52
+ this.transition(() => {
53
+ for (const lane of this.lanes) lane.cancelForControl();
54
+ });
55
+ }
56
+ transition(action) {
57
+ this.audio.send({
58
+ type: "output-hold",
59
+ hold: true
60
+ });
61
+ try {
62
+ action();
63
+ } finally {
64
+ this.audio.send({
65
+ type: "output-hold",
66
+ hold: false
67
+ });
68
+ }
69
+ }
70
+ close() {
71
+ if (this.closed) return;
72
+ this.closed = true;
73
+ this.lanes.clear();
74
+ this.outputs.clear();
75
+ this.current = void 0;
76
+ this.audio.off("event", this.onEvent);
77
+ this.audio.send({ type: "output-shutdown" });
78
+ }
79
+ };
80
+ //#endregion
14
81
  //#region extensions/discord/src/voice/realtime-transcript.ts
15
82
  const PARTIAL_TRANSCRIPT_MAX_CHARS = 240;
16
83
  function mergeRealtimePartialTranscript(previous, next) {
@@ -21,7 +88,7 @@ function mergeRealtimePartialTranscript(previous, next) {
21
88
  }
22
89
  //#endregion
23
90
  //#region extensions/discord/src/voice/realtime-turns.ts
24
- const logger$5 = createSubsystemLogger("discord/voice");
91
+ const logger$4 = createSubsystemLogger("discord/voice");
25
92
  const DISCORD_REALTIME_WAKE_NAME_FOLLOWUP_TTL_MS = 1e4;
26
93
  const REALTIME_PCM16_BYTES_PER_SAMPLE = 2;
27
94
  const DISCORD_REALTIME_TRAILING_SILENCE_MIN_MS = 700;
@@ -100,11 +167,11 @@ var DiscordRealtimeTurns = class {
100
167
  const pendingWakeNameFollowup = this.consumePendingWakeNameFollowup();
101
168
  if (!pendingWakeNameFollowup) {
102
169
  this.consumePendingSpeakerContext();
103
- logger$5.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"}`);
170
+ 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
171
  return;
105
172
  }
106
173
  forcedSpeakerContext = pendingWakeNameFollowup;
107
- logger$5.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}`);
174
+ 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
175
  }
109
176
  const acceptedText = wakeNameResult.allowed ? wakeNameResult.text || trimmed : trimmed;
110
177
  if (wakeNameResult.allowed && !wakeNameResult.text.trim()) {
@@ -157,11 +224,11 @@ var DiscordRealtimeTurns = class {
157
224
  this.registerSpeakerTurnAudioStarted(turn);
158
225
  turn.inputRealtimeBytes += realtimePcm.length;
159
226
  turn.inputChunks += 1;
160
- if (turn.inputChunks === 1) logger$5.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()}`);
227
+ 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
228
  if (!turn.interruptedPlayback && isRealtimeVoiceAudioAudible(discordPcm48kStereo, REALTIME_VOICE_AUDIO_FORMAT_PCM16_24KHZ) && isRealtimeVoiceAudioAudible(realtimePcm, REALTIME_VOICE_AUDIO_FORMAT_PCM16_24KHZ) && this.params.interruptRoomPlayback()) {
162
229
  turn.interruptedPlayback = true;
163
230
  logVoiceVerbose(`realtime barge-in from active speaker audio: guild ${this.params.entry.guildId} channel ${this.params.entry.channelId} user ${turn.context.userId}`);
164
- logger$5.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}`);
231
+ 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
232
  }
166
233
  if (this.params.recordInputAudio(realtimePcm) && this.isTurnProviderCurrent(turn)) bridge.sendAudio(realtimePcm);
167
234
  }
@@ -175,13 +242,13 @@ var DiscordRealtimeTurns = class {
175
242
  turn.lastAudioAt = Date.now();
176
243
  if (turn.hasAudio) return;
177
244
  turn.hasAudio = true;
178
- logger$5.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}`);
245
+ 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
246
  }
180
247
  logSpeakerTurnClosed(turn) {
181
248
  if (turn.closed || !turn.hasAudio) return;
182
249
  const elapsedMs = Date.now() - turn.startedAt;
183
250
  const sinceLastAudioMs = turn.lastAudioAt ? Date.now() - turn.lastAudioAt : void 0;
184
- logger$5.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}`);
251
+ 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
252
  }
186
253
  sendRealtimeTrailingSilenceForTurn(turn) {
187
254
  const bridge = turn.bridge;
@@ -192,7 +259,7 @@ var DiscordRealtimeTurns = class {
192
259
  const silenceBytes = Math.ceil(24e3 * silenceMs / 1e3) * REALTIME_PCM16_BYTES_PER_SAMPLE;
193
260
  const silence = Buffer.alloc(silenceBytes);
194
261
  bridge.sendAudio(silence);
195
- logger$5.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}`);
262
+ 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
263
  }
197
264
  resolveWakeNameTranscript(text, requireWakeName) {
198
265
  if (!requireWakeName) return {
@@ -205,7 +272,7 @@ var DiscordRealtimeTurns = class {
205
272
  };
206
273
  const wakeNameResult = matchRealtimeVoiceActivationName(text, this.params.wakeNames());
207
274
  if (wakeNameResult) {
208
- logger$5.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}`);
275
+ 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
276
  return wakeNameResult;
210
277
  }
211
278
  return {
@@ -219,7 +286,7 @@ var DiscordRealtimeTurns = class {
219
286
  armWakeNameFollowup() {
220
287
  const context = this.consumePendingSpeakerContext();
221
288
  if (!context) {
222
- logger$5.warn(`discord voice: realtime wake-name follow-up has no speaker context voiceSession=${this.params.entry.voiceSessionKey} agent=${this.params.entry.route.agentId}`);
289
+ 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
290
  return;
224
291
  }
225
292
  const expiresAt = resolveExpiresAtMsFromDurationMs(DISCORD_REALTIME_WAKE_NAME_FOLLOWUP_TTL_MS);
@@ -228,7 +295,7 @@ var DiscordRealtimeTurns = class {
228
295
  context,
229
296
  expiresAt
230
297
  };
231
- logger$5.info(`discord voice: realtime wake-name follow-up armed speaker=${context.speakerLabel} voiceSession=${this.params.entry.voiceSessionKey} agent=${this.params.entry.route.agentId}`);
298
+ 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
299
  }
233
300
  consumePendingWakeNameFollowup() {
234
301
  const pending = this.pendingWakeNameFollowup;
@@ -245,7 +312,7 @@ function isDiscordRealtimeSpeakerContext(value) {
245
312
  }
246
313
  //#endregion
247
314
  //#region extensions/discord/src/voice/realtime-consults.ts
248
- const logger$4 = createSubsystemLogger("discord/voice");
315
+ const logger$3 = createSubsystemLogger("discord/voice");
249
316
  const DISCORD_REALTIME_TALKBACK_DEBOUNCE_MS = 350;
250
317
  const DISCORD_REALTIME_FALLBACK_TEXT = "I hit an error while checking that. Please try again.";
251
318
  const DISCORD_REALTIME_FORCED_CONSULT_FALLBACK_DELAY_MS = 200;
@@ -318,16 +385,16 @@ var DiscordRealtimeConsults = class {
318
385
  const outcome = classifyRealtimeVoiceConsultToolCall(event.args, { retainedExactSpeechTexts: this.params.playback.retainedExactSpeechTexts() });
319
386
  switch (outcome.kind) {
320
387
  case "exact-speech-echo":
321
- logger$4.info(`discord voice: realtime exact speech consult bypassed call=${callId || "unknown"} answerChars=${outcome.text.length}`);
388
+ logger$3.info(`discord voice: realtime exact speech consult bypassed call=${callId} answerChars=${outcome.text.length}`);
322
389
  await session.submitToolResult(callId, { text: outcome.text });
323
390
  return;
324
391
  case "malformed":
325
- logger$4.warn(`discord voice: realtime consult rejected malformed args call=${callId || "unknown"}: ${outcome.error}`);
392
+ logger$3.warn(`discord voice: realtime consult rejected malformed args call=${callId}: ${outcome.error}`);
326
393
  await session.submitToolResult(callId, { error: outcome.error });
327
394
  return;
328
395
  }
329
396
  const consultMessage = outcome.message;
330
- logger$4.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)}`);
397
+ logger$3.info(`discord voice: realtime consult requested call=${callId} voiceSession=${this.params.entry.voiceSessionKey} supervisorSession=${this.params.entry.route.sessionKey} agent=${this.params.entry.route.agentId} question=${formatVoiceLogPreview(consultMessage)}`);
331
398
  const nativeConsult = this.params.harness.forcedConsults.recordNativeConsult(event.args, callId);
332
399
  if (nativeConsult.kind === "already_delivered" && this.params.harness.forcedConsults.isCancelled(nativeConsult.handle)) {
333
400
  await this.submitTerminalRealtimeToolResult(callId, session, CANCELLED_CONSULT_RESULT);
@@ -342,7 +409,7 @@ var DiscordRealtimeConsults = class {
342
409
  if (recentConsult) {
343
410
  const recentSpeaker = recentConsult.context?.speaker;
344
411
  if (this.params.turns.hasPendingSpeakerAudioContext()) {
345
- logger$4.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}`);
412
+ 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
413
  await session.submitToolResult(callId, { error: "Discord speaker context changed before this realtime consult completed" });
347
414
  return;
348
415
  }
@@ -351,14 +418,22 @@ var DiscordRealtimeConsults = class {
351
418
  }
352
419
  if (!context) {
353
420
  context = this.params.turns.consumePendingSpeakerContext();
354
- if (context) recent = this.rememberRecentAgentProxyConsultContext(consultMessage, context, {
355
- ...callId === "unknown" ? {} : { id: `native-consult:${callId}` },
356
- started: true
357
- });
421
+ if (context) {
422
+ recent = this.params.harness.forcedConsults.prepare(consultMessage, {
423
+ context: {
424
+ speaker: context,
425
+ providerEpoch: this.params.providerEpoch(),
426
+ delivery: "provider"
427
+ },
428
+ ...callId === "unknown" ? {} : { id: `native-consult:${callId}` }
429
+ });
430
+ if (!recent) throw new Error("Discord realtime consult context requires a non-empty question");
431
+ this.params.harness.forcedConsults.markStarted(recent);
432
+ }
358
433
  }
359
434
  const state = recent?.context;
360
435
  if (!context || !state) {
361
- logger$4.warn(`discord voice: realtime consult has no speaker context call=${callId || "unknown"}`);
436
+ logger$3.warn(`discord voice: realtime consult has no speaker context call=${callId}`);
362
437
  await session.submitToolResult(callId, { error: "No Discord speaker context available" });
363
438
  return;
364
439
  }
@@ -371,8 +446,8 @@ var DiscordRealtimeConsults = class {
371
446
  deliveryOwner: "consult"
372
447
  }));
373
448
  if (this.params.stopped() || providerEpoch !== this.params.providerEpoch()) return;
374
- if ("text" in result) logger$4.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)}`);
375
- else if ("error" in result) logger$4.warn(`discord voice: realtime consult failed call=${callId}: ${result.error}`);
449
+ 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)}`);
450
+ else if ("error" in result) logger$3.warn(`discord voice: realtime consult failed call=${callId}: ${result.error}`);
376
451
  delivery.submissionStarted = true;
377
452
  await this.submitAgentProxyConsultResult(callId, session, result);
378
453
  if (state.delivery === "provider-pending") state.delivery = "provider";
@@ -394,10 +469,10 @@ var DiscordRealtimeConsults = class {
394
469
  if (this.params.stopped() || providerEpoch !== this.params.providerEpoch()) return;
395
470
  if (readErrorName(error) === "AbortError") {
396
471
  if (pendingForcedConsult) this.params.harness.forcedConsults.remove(pendingForcedConsult);
397
- logger$4.warn(`discord voice: realtime transcript cancelled: ${formatErrorMessage$1(error)}`);
472
+ logger$3.warn(`discord voice: realtime transcript cancelled: ${formatErrorMessage$1(error)}`);
398
473
  return;
399
474
  }
400
- logger$4.warn(`discord voice: realtime active-run control failed; falling back to normal transcript handling: ${formatErrorMessage$1(error)}`);
475
+ logger$3.warn(`discord voice: realtime active-run control failed; falling back to normal transcript handling: ${formatErrorMessage$1(error)}`);
401
476
  control = void 0;
402
477
  }
403
478
  if (this.params.stopped() || providerEpoch !== this.params.providerEpoch()) return;
@@ -409,7 +484,7 @@ var DiscordRealtimeConsults = class {
409
484
  }
410
485
  if (!this.params.isAgentProxy()) return;
411
486
  if (usesRealtimeAgentHandoff) {
412
- if (pendingForcedConsult) this.schedulePreparedForcedAgentProxyConsult(pendingForcedConsult);
487
+ if (pendingForcedConsult) this.params.harness.forcedConsults.schedule(pendingForcedConsult, DISCORD_REALTIME_FORCED_CONSULT_FALLBACK_DELAY_MS, (handle) => void this.runForcedAgentProxyConsult(handle));
413
488
  return;
414
489
  }
415
490
  this.talkback.enqueue(acceptedText, fallbackSpeakerContext);
@@ -419,7 +494,7 @@ var DiscordRealtimeConsults = class {
419
494
  return createRealtimeVoiceAgentTalkbackQueue({
420
495
  debounceMs: this.params.debounceMs() ?? DISCORD_REALTIME_TALKBACK_DEBOUNCE_MS,
421
496
  isStopped: () => this.params.stopped() || providerEpoch !== this.params.providerEpoch(),
422
- logger: logger$4,
497
+ logger: logger$3,
423
498
  logPrefix: "[discord] realtime agent",
424
499
  responseStyle: "Brief, natural spoken answer for a Discord voice channel.",
425
500
  fallbackText: DISCORD_REALTIME_FALLBACK_TEXT,
@@ -468,7 +543,7 @@ var DiscordRealtimeConsults = class {
468
543
  const skipReason = classifySkippableRealtimeVoiceConsultTranscript(question);
469
544
  if (skipReason) {
470
545
  const context = this.params.turns.consumePendingSpeakerContext();
471
- logger$4.info(`discord voice: realtime forced agent consult skipped reason=${skipReason} chars=${question.length} speaker=${context?.speakerLabel ?? "unknown"} transcript=${formatVoiceLogPreview(question)}`);
546
+ logger$3.info(`discord voice: realtime forced agent consult skipped reason=${skipReason} chars=${question.length} speaker=${context?.speakerLabel ?? "unknown"} transcript=${formatVoiceLogPreview(question)}`);
472
547
  return;
473
548
  }
474
549
  const context = speakerContext ?? this.params.turns.consumePendingSpeakerContext();
@@ -478,7 +553,7 @@ var DiscordRealtimeConsults = class {
478
553
  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
554
  return;
480
555
  }
481
- logger$4.warn("discord voice: realtime forced agent consult has no speaker context");
556
+ logger$3.warn("discord voice: realtime forced agent consult has no speaker context");
482
557
  return;
483
558
  }
484
559
  return this.params.harness.forcedConsults.prepare(question, { context: {
@@ -487,9 +562,6 @@ var DiscordRealtimeConsults = class {
487
562
  delivery: "provider"
488
563
  } });
489
564
  }
490
- schedulePreparedForcedAgentProxyConsult(pending) {
491
- this.params.harness.forcedConsults.schedule(pending, DISCORD_REALTIME_FORCED_CONSULT_FALLBACK_DELAY_MS, (handle) => void this.runForcedAgentProxyConsult(handle));
492
- }
493
565
  async runForcedAgentProxyConsult(pending) {
494
566
  this.params.harness.forcedConsults.markStarted(pending);
495
567
  const state = pending.context;
@@ -504,9 +576,9 @@ var DiscordRealtimeConsults = class {
504
576
  return;
505
577
  }
506
578
  const startedAt = Date.now();
507
- logger$4.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}`);
508
- logger$4.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}`);
509
- if (this.params.playback.hasInterruptibleOutputAudio()) logger$4.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}`);
579
+ 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}`);
580
+ 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}`);
581
+ 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
582
  state.delivery = "forced-pending";
511
583
  const result = await this.trackAgentProxyConsult(pending, this.runAgentTurn({
512
584
  context,
@@ -516,27 +588,14 @@ var DiscordRealtimeConsults = class {
516
588
  const deliveries = this.providerDeliveries.get(state);
517
589
  await Promise.all(Array.from(deliveries ?? [], (delivery) => delivery.promise));
518
590
  if (state.providerEpoch !== this.params.providerEpoch() || "status" in result) return;
519
- if ("text" in result) logger$4.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)}`);
520
- else logger$4.warn(`discord voice: realtime forced agent consult failed elapsedMs=${Date.now() - startedAt}: ${result.error}`);
591
+ 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)}`);
592
+ else logger$3.warn(`discord voice: realtime forced agent consult failed elapsedMs=${Date.now() - startedAt}: ${result.error}`);
521
593
  const text = "text" in result ? result.text : DISCORD_REALTIME_FALLBACK_TEXT;
522
594
  if (text.trim() && state.delivery === "forced-pending") {
523
595
  state.delivery = "playback";
524
596
  this.params.playback.enqueueExactSpeechMessage(text);
525
597
  }
526
598
  }
527
- rememberRecentAgentProxyConsultContext(question, context, options = {}) {
528
- const handle = this.params.harness.forcedConsults.prepare(question, {
529
- context: {
530
- speaker: context,
531
- providerEpoch: this.params.providerEpoch(),
532
- delivery: "provider"
533
- },
534
- ...options.id ? { id: options.id } : {}
535
- });
536
- if (!handle) throw new Error("Discord realtime consult context requires a non-empty question");
537
- if (options.started) this.params.harness.forcedConsults.markStarted(handle);
538
- return handle;
539
- }
540
599
  trackAgentProxyConsult(recent, promise) {
541
600
  const state = recent?.context;
542
601
  if (recent) this.params.harness.forcedConsults.markStarted(recent);
@@ -569,7 +628,7 @@ var DiscordRealtimeConsults = class {
569
628
  const pendingResult = state.result ?? state.promise;
570
629
  if (!pendingResult) return false;
571
630
  const providerDelivery = state.delivery === "provider-pending" || state.delivery === "forced-pending" && !state.result && session.bridge.supportsToolResultSuppression === false ? this.beginProviderDelivery(state) : void 0;
572
- logger$4.info(`discord voice: realtime consult ${state.result ? "reused recent" : "joined in-flight"} agent result call=${callId} speaker=${state.speaker.speakerLabel} owner=${state.speaker.senderIsOwner}`);
631
+ 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
632
  try {
574
633
  const result = await pendingResult;
575
634
  if (this.params.stopped() || state.providerEpoch !== this.params.providerEpoch() || state.delivery === "detached" || state.delivery === "retired") return true;
@@ -629,286 +688,156 @@ var DiscordRealtimeConsults = class {
629
688
  };
630
689
  //#endregion
631
690
  //#region extensions/discord/src/voice/realtime-output.ts
632
- const logger$3 = createSubsystemLogger("discord/voice");
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. */
691
+ /** Main retains provider item identity; physical output state belongs to the worker. */
640
692
  var DiscordRealtimeOutput = class {
693
+ get activity() {
694
+ if (Atomics.load(this.clock, 2) !== 0n && !this.activityTracker.snapshot().playbackStarted) this.activityTracker.markPlaybackStarted();
695
+ return this.activityTracker;
696
+ }
641
697
  constructor(params) {
642
698
  this.params = params;
643
- this.activity = createRealtimeVoiceOutputActivityTracker();
644
- this.converter = createRealtimePcmToDiscordConverter();
645
- this.stream = new PassThrough({ highWaterMark: DISCORD_RAW_PCM_FRAME_BYTES * 128 });
646
- this.ready = false;
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;
699
+ this.activityTracker = createRealtimeVoiceOutputActivityTracker();
700
+ this.clock = new BigInt64Array(new SharedArrayBuffer(24));
701
+ this.marks = /* @__PURE__ */ new Map();
702
+ this.nextMark = 0;
654
703
  this.closed = false;
655
- this.failed = false;
656
- this.stream.once("close", () => {
657
- if (!this.activity.snapshot().playbackStarted) this.close("stream-close");
704
+ this.reportedPlaybackMs = 0;
705
+ this.spans = [];
706
+ this.onEvent = (event) => {
707
+ if (!("id" in event) || event.id !== this.id || this.closed) return;
708
+ switch (event.type) {
709
+ case "output-start":
710
+ this.activity.markPlaybackStarted();
711
+ this.params.onStart();
712
+ break;
713
+ case "output-close":
714
+ this.retire(event.reason);
715
+ break;
716
+ case "output-error":
717
+ this.params.onError(restoreDiscordAudioError(event.error));
718
+ break;
719
+ case "output-mark": {
720
+ const acknowledge = this.marks.get(event.markId);
721
+ this.marks.delete(event.markId);
722
+ try {
723
+ acknowledge?.();
724
+ } catch (error) {
725
+ this.params.onError(error);
726
+ }
727
+ break;
728
+ }
729
+ }
730
+ };
731
+ this.onStopped = () => {
732
+ if (!this.closed) {
733
+ this.params.onError(/* @__PURE__ */ new Error("Discord audio worker stopped during playback."));
734
+ this.retire("worker-stopped");
735
+ }
736
+ };
737
+ this.id = params.player.audio.allocateId();
738
+ this.unregister = params.player.registerOutput(this.id, params.onBargeIn);
739
+ params.player.audio.on("event", this.onEvent);
740
+ params.player.audio.on("stopped", this.onStopped);
741
+ params.player.audio.send({
742
+ type: "output-create",
743
+ id: this.id,
744
+ continuous: params.continuous,
745
+ clock: this.clock.buffer
658
746
  });
659
747
  }
748
+ playedBytes() {
749
+ return Number(Atomics.load(this.clock, 0));
750
+ }
660
751
  pendingBytes() {
661
- return this.closed ? 0 : Math.max(0, this.activity.snapshot().sourceAudioBytes * 4 - this.playedPcmBytes);
752
+ return this.closed ? 0 : Math.max(0, this.activity.snapshot().sourceAudioBytes * 4 - this.playedBytes());
662
753
  }
663
754
  isAcceptingAudio() {
664
- return !this.closed && !this.activity.snapshot().streamEnding && (!this.request || !this.params.player.isRetiring(this.request));
665
- }
666
- hasUnplayedAudibleAudio() {
667
- return !this.closed && this.playedPcmBytes < this.lastAudiblePcmEndBytes;
755
+ return !this.closed && !this.activity.snapshot().streamEnding && getDiscordAudioOutputStatus(this.clock) < DiscordAudioOutputStatus.Retiring;
668
756
  }
669
757
  playbackItems() {
670
- const playedMs = Math.min(this.playedPcmBytes / DISCORD_RAW_PCM_BYTES_PER_MS, this.activity.snapshot().audioMs);
671
- for (const span of this.audioSpans) span.item.audioEndMs += Math.max(0, Math.min(playedMs, span.endMs) - Math.max(this.reportedPlaybackMs, span.startMs));
758
+ const playedMs = Math.min(this.playedBytes() / 192, this.activity.snapshot().audioMs);
759
+ for (const span of this.spans) span.item.audioEndMs += Math.max(0, Math.min(playedMs, span.endMs) - Math.max(this.reportedPlaybackMs, span.startMs));
672
760
  this.reportedPlaybackMs = playedMs;
673
- return this.audioSpans.filter(({ endMs }) => endMs > playedMs).map(({ item }) => item);
761
+ return this.spans.filter(({ endMs }) => endMs > playedMs).map(({ item }) => item);
674
762
  }
675
763
  markPlayback(acknowledge) {
676
- if (!this.closed) this.playbackMarks.push({
677
- endBytes: this.activity.snapshot().sinkAudioBytes,
678
- acknowledge
764
+ if (this.closed) return;
765
+ const markId = ++this.nextMark;
766
+ this.marks.set(markId, acknowledge);
767
+ this.params.player.audio.send({
768
+ type: "output-mark",
769
+ id: this.id,
770
+ markId
679
771
  });
680
772
  }
681
- append(sourcePcm, audible, item) {
682
- if (this.closed) return;
773
+ append(audio, audible, item, onAccepted) {
774
+ if (this.closed || this.activity.snapshot().streamEnding || !admitDiscordAudioInput(this.clock)) return false;
775
+ try {
776
+ onAccepted();
777
+ } catch (error) {
778
+ releaseDiscordAudioInput(this.clock);
779
+ throw error;
780
+ }
781
+ if (this.closed) {
782
+ releaseDiscordAudioInput(this.clock);
783
+ return true;
784
+ }
683
785
  const previous = this.activity.snapshot();
684
- const sinkBytes = Math.floor((previous.sourceAudioBytes + sourcePcm.length) / 2) * 8;
685
- const audioMs = (sinkBytes - previous.sinkAudioBytes) / DISCORD_RAW_PCM_BYTES_PER_MS;
686
- const startMs = previous.audioMs;
786
+ const sinkBytes = Math.floor((previous.sourceAudioBytes + audio.length) / 2) * 8;
787
+ const audioMs = (sinkBytes - previous.sinkAudioBytes) / 192;
687
788
  if (item) {
688
- const previousSpan = this.audioSpans.at(-1);
689
- const endMs = startMs + audioMs;
690
- if (previousSpan?.item === item && previousSpan.endMs === startMs) previousSpan.endMs = endMs;
691
- else this.audioSpans.push({
789
+ const last = this.spans.at(-1);
790
+ if (last?.item === item && last.endMs === previous.audioMs) last.endMs += audioMs;
791
+ else this.spans.push({
692
792
  item,
693
- startMs,
694
- endMs
793
+ startMs: previous.audioMs,
794
+ endMs: previous.audioMs + audioMs
695
795
  });
696
796
  }
697
797
  this.activity.markAudio({
698
798
  audioMs,
699
- sourceAudioBytes: sourcePcm.length,
799
+ sourceAudioBytes: audio.length,
700
800
  sinkAudioBytes: sinkBytes - previous.sinkAudioBytes
701
801
  });
702
- if (audible) {
703
- this.clearSilenceTimer();
704
- this.silentSince = void 0;
705
- this.lastAudiblePcmEndBytes = this.activity.snapshot().sinkAudioBytes;
706
- }
707
- this.writeConverted(this.converter.process(sourcePcm));
708
- this.scheduleSilenceRetirement();
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;
802
+ this.params.player.audio.send({
803
+ type: "output-audio",
804
+ id: this.id,
805
+ audio,
806
+ audible
807
+ });
808
+ return true;
728
809
  }
729
810
  finish(reason, playBuffered) {
730
811
  if (this.closed) return;
731
- this.clearSilenceTimer();
732
- if (playBuffered) this.writeConverted(this.converter.flush());
733
812
  this.activity.markStreamEnding();
734
- const activity = this.activity.snapshot();
735
- logger$3.info(`discord voice: realtime audio playback finishing reason=${reason} ${this.params.logContext} audioMs=${Math.floor(activity.audioMs)} chunks=${activity.chunks}`);
736
- if (!playBuffered) {
737
- this.close(reason);
738
- return;
739
- }
740
- this.startPlayback();
741
- if (this.activity.snapshot().playbackStarted) {
742
- this.scheduleWatchdog(reason);
743
- if (!this.drainHandler) this.stream.end();
744
- }
813
+ if (!playBuffered) setDiscordAudioOutputStatus(this.clock, DiscordAudioOutputStatus.Closed);
814
+ this.params.player.audio.send({
815
+ type: "output-finish",
816
+ id: this.id,
817
+ reason,
818
+ playBuffered
819
+ });
820
+ if (!playBuffered) this.retire(reason);
745
821
  }
746
822
  close(reason) {
747
823
  if (this.closed) return;
748
- const playbackRetirement = reason === "player-idle" || reason === "output-pipeline-error" || reason === "playback-watchdog";
749
- const heardMarks = playbackRetirement ? this.playbackMarks.filter((mark) => mark.endBytes <= this.playedPcmBytes) : [];
750
- const lostPlaybackMarks = playbackRetirement && this.playbackMarks.some((mark) => mark.endBytes > this.playedPcmBytes);
751
- this.closed = true;
752
- this.clearSilenceTimer();
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;
824
+ setDiscordAudioOutputStatus(this.clock, DiscordAudioOutputStatus.Closed);
825
+ this.params.player.audio.send({
826
+ type: "output-close",
827
+ id: this.id,
828
+ reason
811
829
  });
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;
830
+ this.retire(reason);
843
831
  }
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
901
- });
902
- if (timeoutMs === void 0) return;
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);
908
- }
909
- clearWatchdog() {
910
- clearTimeout(this.watchdog);
911
- this.watchdog = void 0;
832
+ retire(reason) {
833
+ if (this.closed) return;
834
+ this.playbackItems();
835
+ this.closed = true;
836
+ this.marks.clear();
837
+ this.params.player.audio.off("event", this.onEvent);
838
+ this.params.player.audio.off("stopped", this.onStopped);
839
+ this.unregister();
840
+ this.params.onClose(this, reason);
912
841
  }
913
842
  };
914
843
  //#endregion
@@ -930,12 +859,14 @@ function normalizeControlSpeechText(text) {
930
859
  var DiscordRealtimePlayback = class {
931
860
  constructor(params) {
932
861
  this.params = params;
862
+ this.outputClearGeneration = 0;
933
863
  this.outputs = /* @__PURE__ */ new Set();
934
864
  this.generatingItems = /* @__PURE__ */ new Map();
935
865
  this.responseAudio = "completed";
936
866
  this.queuedExactSpeechMessages = [];
937
867
  this.retainedSpeechClosed = false;
938
868
  this.exactSpeechState = { status: "idle" };
869
+ this.nextExactSpeechEpoch = 0n;
939
870
  this.wakeNameAckIndex = 0;
940
871
  this.unregisterPlayerLane = this.params.player.registerLane({
941
872
  hasOutput: () => this.isOutputAudioActive(),
@@ -943,16 +874,77 @@ var DiscordRealtimePlayback = class {
943
874
  cancelForControl: () => this.cancelForControl()
944
875
  });
945
876
  }
877
+ /** Only continuous provider media uses this generation-scoped, PCM24k mono port. */
878
+ createOutputAudioPort(enabled = true) {
879
+ this.directOutput?.close();
880
+ const { port1, port2 } = new MessageChannel();
881
+ const id = this.params.entry.audio.allocateId();
882
+ const state = new Int32Array(new SharedArrayBuffer(4));
883
+ const clock = new BigInt64Array(new SharedArrayBuffer(24));
884
+ const unregister = this.params.player.registerOutput(id, (reason) => this.handleBargeIn(reason));
885
+ const onEvent = (event) => {
886
+ if (!("id" in event) || event.id !== id || this.directOutput?.id !== id) return;
887
+ if ((event.type === "continuous-start" || event.type === "continuous-idle") && this.exactSpeechState.status === "active" && this.exactSpeechState.direct && event.speechEpoch !== this.exactSpeechState.direct.epoch) return;
888
+ if (event.type === "continuous-error") this.stopAfterPlaybackFailure("direct-output-error", restoreDiscordAudioError(event.error));
889
+ if (event.type === "continuous-start") this.params.harness.outputActivity.markPlaybackStarted();
890
+ if (event.type === "continuous-flushed" && event.marker === this.pendingDirectCompletion) {
891
+ this.pendingDirectCompletion = void 0;
892
+ this.responseAudio = "completed";
893
+ this.completeExactSpeechResponse("provider-completed");
894
+ }
895
+ if (event.type === "continuous-idle") {
896
+ this.responseAudio = "completed";
897
+ this.params.harness.finishOutputAudio("player-idle");
898
+ this.params.harness.outputActivity.reset();
899
+ this.completeExactSpeechResponse("player-idle");
900
+ }
901
+ };
902
+ const close = () => {
903
+ Atomics.store(state, 0, 1);
904
+ this.params.entry.audio.off("event", onEvent);
905
+ unregister();
906
+ this.params.entry.audio.send({
907
+ type: "continuous-close",
908
+ id
909
+ });
910
+ if (this.directOutput?.id === id) this.directOutput = void 0;
911
+ };
912
+ this.directOutput = {
913
+ id,
914
+ clock,
915
+ close
916
+ };
917
+ this.params.entry.audio.on("event", onEvent);
918
+ this.params.entry.audio.send({
919
+ type: "continuous-port",
920
+ id,
921
+ enabled,
922
+ port: port1,
923
+ state: state.buffer,
924
+ clock: clock.buffer
925
+ }, [port1]);
926
+ return {
927
+ port: port2,
928
+ state: state.buffer
929
+ };
930
+ }
931
+ activateOutputAudioPort() {
932
+ if (this.directOutput) this.params.entry.audio.send({
933
+ type: "continuous-activate",
934
+ id: this.directOutput.id
935
+ });
936
+ }
946
937
  close(preserveUnplayedSpeech = false) {
947
938
  this.unregisterPlayerLane();
948
- if (preserveUnplayedSpeech) this.requeueUnplayedExactSpeech();
939
+ if (preserveUnplayedSpeech) this.retireExactSpeech(true);
949
940
  else {
950
941
  this.retainedSpeechClosed = true;
951
942
  this.speechSuccessor = void 0;
952
943
  this.queuedExactSpeechMessages = [];
953
- this.exactSpeechState = { status: "idle" };
944
+ this.retireExactSpeech();
954
945
  }
955
946
  this.clearOutputAudio("session-close");
947
+ this.directOutput?.close();
956
948
  }
957
949
  transferPendingSpeechTo(target) {
958
950
  this.speechSuccessor = target;
@@ -970,13 +962,14 @@ var DiscordRealtimePlayback = class {
970
962
  return false;
971
963
  }
972
964
  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}`);
965
+ const clearGeneration = this.outputClearGeneration;
973
966
  const bridge = this.params.bridge();
974
967
  const outputs = Array.from(this.outputs);
975
968
  const items = Array.from(this.generatingItems.values());
976
969
  this.params.harness.handleBargeIn({ audioPlaybackActive: true }, () => {
977
970
  if (!bridge?.bridge.handleBargeIn) this.clearOutputAudio(reason);
978
971
  });
979
- return outputs.some((output) => !this.outputs.has(output)) || items.some((item) => this.generatingItems.get(item.itemId) !== item);
972
+ return clearGeneration !== this.outputClearGeneration || outputs.some((output) => !this.outputs.has(output)) || items.some((item) => this.generatingItems.get(item.itemId) !== item);
980
973
  }
981
974
  isBargeInEnabled() {
982
975
  if (this.params.wakeNameRequired()) return false;
@@ -1043,10 +1036,15 @@ var DiscordRealtimePlayback = class {
1043
1036
  this.generatingItems.set(metadata.itemId, item);
1044
1037
  }
1045
1038
  }
1046
- this.params.harness.recordOutputAudio(realtimePcm24kMono, activity);
1047
- output.append(realtimePcm24kMono, audible, item);
1039
+ const onAccepted = () => this.params.harness.recordOutputAudio(realtimePcm24kMono, activity);
1040
+ if (!output.append(realtimePcm24kMono, audible, item, onAccepted)) {
1041
+ this.generatingOutput = void 0;
1042
+ this.sendOutputAudio(realtimePcm24kMono, metadata);
1043
+ }
1048
1044
  }
1049
1045
  clearOutputAudio(reason = "clear") {
1046
+ this.outputClearGeneration += 1;
1047
+ this.retireExactSpeech();
1050
1048
  if (this.isContinuousOutput()) this.responseAudio = "completed";
1051
1049
  else if (this.responseAudio === "accepting") this.responseAudio = "discarding";
1052
1050
  this.generatingOutput = void 0;
@@ -1055,9 +1053,26 @@ var DiscordRealtimePlayback = class {
1055
1053
  this.outputs.clear();
1056
1054
  for (const output of outputs.toReversed()) output.close(reason);
1057
1055
  this.params.harness.outputActivity.reset();
1056
+ if (this.directOutput) {
1057
+ if (reason === "session-close" || this.params.stopped()) this.directOutput.close();
1058
+ else this.params.entry.audio.send({
1059
+ type: "continuous-clear",
1060
+ id: this.directOutput.id
1061
+ });
1062
+ }
1058
1063
  this.completeExactSpeechResponse(reason);
1059
1064
  }
1060
1065
  handleResponseDone(outcome) {
1066
+ if (this.directOutput && outcome.status === "completed") {
1067
+ const marker = this.params.entry.audio.allocateId();
1068
+ this.pendingDirectCompletion = marker;
1069
+ this.params.entry.audio.send({
1070
+ type: "continuous-flush",
1071
+ id: this.directOutput.id,
1072
+ marker
1073
+ });
1074
+ return;
1075
+ }
1061
1076
  const output = this.generatingOutput;
1062
1077
  this.generatingOutput = void 0;
1063
1078
  this.generatingItems.clear();
@@ -1077,8 +1092,9 @@ var DiscordRealtimePlayback = class {
1077
1092
  /** Accept completed consult ownership without starting provider work during transport cleanup. */
1078
1093
  retainExactSpeechMessage(text) {
1079
1094
  if (!text.trim()) return false;
1080
- const retainedMessages = this.queuedExactSpeechMessages.length + (this.exactSpeechState.status === "active" ? 1 : 0);
1081
- const retainedBytes = this.queuedExactSpeechMessages.reduce((total, message) => total + Buffer.byteLength(message, "utf8"), 0) + Buffer.byteLength(this.exactSpeechState.status === "active" ? this.exactSpeechState.message : "", "utf8");
1095
+ const retained = this.retainedExactSpeechTexts();
1096
+ const retainedMessages = retained.length;
1097
+ const retainedBytes = retained.reduce((total, message) => total + Buffer.byteLength(message, "utf8"), 0);
1082
1098
  const incomingBytes = Buffer.byteLength(text, "utf8");
1083
1099
  if (retainedMessages >= DISCORD_REALTIME_MAX_RETAINED_RESPONSES || retainedBytes + incomingBytes > DISCORD_REALTIME_MAX_RETAINED_EXACT_SPEECH_BYTES) {
1084
1100
  this.stopAfterPlaybackFailure("exact-speech-overflow", /* @__PURE__ */ new Error(`Discord realtime exact speech overflow: retained=${retainedMessages} retainedBytes=${retainedBytes} incomingBytes=${incomingBytes}`));
@@ -1122,8 +1138,12 @@ var DiscordRealtimePlayback = class {
1122
1138
  }
1123
1139
  cancelForControl() {
1124
1140
  this.queuedExactSpeechMessages = [];
1125
- this.exactSpeechState = { status: "idle" };
1126
- if (this.responseAudio === "completed" && this.outputs.size === 0) return;
1141
+ this.retireExactSpeech();
1142
+ if (this.responseAudio === "completed" && !this.isOutputAudioActive()) return;
1143
+ if (this.isContinuousOutput()) {
1144
+ this.params.harness.flushOutput(() => this.clearOutputAudio("active-run-control"));
1145
+ return;
1146
+ }
1127
1147
  this.params.harness.handleBargeIn({
1128
1148
  audioPlaybackActive: true,
1129
1149
  force: true
@@ -1147,22 +1167,25 @@ var DiscordRealtimePlayback = class {
1147
1167
  }
1148
1168
  resetProviderContinuity(reason) {
1149
1169
  this.lastControlSpeech = void 0;
1150
- this.requeueUnplayedExactSpeech();
1170
+ this.retireExactSpeech(true);
1151
1171
  this.responseAudio = "discarding";
1152
1172
  this.params.harness.flushOutput(() => this.clearOutputAudio(reason));
1153
1173
  this.responseAudio = "completed";
1154
1174
  this.params.harness.finishOutputAudio(reason);
1155
1175
  }
1156
- requeueUnplayedExactSpeech() {
1157
- const replayExactSpeech = this.exactSpeechState.status === "active" && !this.exactSpeechState.output?.activity.snapshot().playbackStarted ? this.exactSpeechState.message : void 0;
1176
+ retireExactSpeech(preserveUnplayed = false) {
1177
+ this.pendingDirectCompletion = void 0;
1178
+ const speech = this.exactSpeechState;
1158
1179
  this.exactSpeechState = { status: "idle" };
1159
- if (replayExactSpeech) this.queuedExactSpeechMessages.unshift(replayExactSpeech);
1180
+ if (speech.status !== "active") return;
1181
+ const directStarted = speech.direct && Atomics.exchange(speech.direct.clock, 2, 0n) === -speech.direct.epoch;
1182
+ if (preserveUnplayed && !directStarted && !speech.output?.activity.snapshot().playbackStarted) this.queuedExactSpeechMessages.unshift(speech.message);
1160
1183
  }
1161
1184
  outputAudioMs() {
1162
- return Math.floor(this.params.harness.outputActivity.snapshot().audioMs);
1185
+ return this.directOutput ? Math.floor(Number(Atomics.load(this.directOutput.clock, 1)) / 48) : Math.floor(this.params.harness.outputActivity.snapshot().audioMs);
1163
1186
  }
1164
1187
  isOutputAudioActive() {
1165
- return this.outputs.size > 0 || this.generatingItems.size > 0;
1188
+ return this.outputs.size > 0 || this.generatingItems.size > 0 || this.directOutput !== void 0 && Atomics.load(this.directOutput.clock, 0) > 0n;
1166
1189
  }
1167
1190
  isContinuousOutput() {
1168
1191
  return this.params.bridge()?.bridge.outputAudioMode === "continuous";
@@ -1172,7 +1195,7 @@ var DiscordRealtimePlayback = class {
1172
1195
  this.speechSuccessor = void 0;
1173
1196
  this.params.stopTerminally();
1174
1197
  this.queuedExactSpeechMessages = [];
1175
- this.exactSpeechState = { status: "idle" };
1198
+ this.retireExactSpeech();
1176
1199
  this.clearOutputAudio(reason);
1177
1200
  this.params.onTerminalError(error);
1178
1201
  }
@@ -1180,7 +1203,6 @@ var DiscordRealtimePlayback = class {
1180
1203
  const logContext = `guild=${this.params.entry.guildId} channel=${this.params.entry.channelId}`;
1181
1204
  const output = new DiscordRealtimeOutput({
1182
1205
  player: this.params.player,
1183
- logContext,
1184
1206
  continuous: this.isContinuousOutput(),
1185
1207
  onStart: () => {
1186
1208
  this.params.harness.outputActivity.markPlaybackStarted();
@@ -1214,25 +1236,27 @@ var DiscordRealtimePlayback = class {
1214
1236
  }
1215
1237
  sendExactSpeechMessage(text) {
1216
1238
  if (this.params.stopped() || !text.trim()) return;
1239
+ const direct = this.directOutput ? {
1240
+ clock: this.directOutput.clock,
1241
+ epoch: ++this.nextExactSpeechEpoch
1242
+ } : void 0;
1217
1243
  this.exactSpeechState = {
1218
1244
  status: "active",
1219
- message: text
1245
+ message: text,
1246
+ direct
1220
1247
  };
1248
+ if (direct) Atomics.store(direct.clock, 2, direct.epoch);
1221
1249
  this.beginResponse();
1222
1250
  this.params.bridge()?.sendUserMessage(this.params.buildSpeakExactMessage(text));
1223
1251
  }
1224
1252
  completeExactSpeechResponse(reason) {
1225
- if (this.responseAudio !== "completed" || this.outputs.size > 0) return;
1226
- this.exactSpeechState = { status: "idle" };
1253
+ if (this.pendingDirectCompletion !== void 0 || this.responseAudio !== "completed" || this.isOutputAudioActive()) return;
1254
+ this.retireExactSpeech();
1227
1255
  this.drainQueuedExactSpeechMessages(reason);
1228
1256
  }
1229
1257
  };
1230
1258
  //#endregion
1231
1259
  //#region extensions/discord/src/voice/realtime-speaker-config.ts
1232
- function readProviderConfigString(config, key) {
1233
- const value = config[key];
1234
- return typeof value === "string" && value.trim() ? value.trim() : void 0;
1235
- }
1236
1260
  /** Resolve the same provider, voice catalog, and policies for initial and replacement connections. */
1237
1261
  function resolveDiscordRealtimeSpeakerConfig(params) {
1238
1262
  const { realtimeConfig, isAgentProxy } = params;
@@ -1243,11 +1267,14 @@ function resolveDiscordRealtimeSpeakerConfig(params) {
1243
1267
  if (canonicalProviderId) ownerProviderIds.add(canonicalProviderId);
1244
1268
  for (const providerId of ownerProviderIds) assertSecretOwnerAvailable("capability", discordRealtimeVoiceSecretOwnerId(params.accountId, providerId));
1245
1269
  }
1270
+ const configuredVoice = realtimeConfig?.speakerVoice || realtimeConfig?.speakerVoiceId;
1246
1271
  const resolved = resolveConfiguredRealtimeVoiceProvider({
1247
1272
  configuredProviderId: realtimeConfig?.provider,
1248
- providerConfigs: buildProviderConfigs(realtimeConfig),
1273
+ providerConfigs: { ...realtimeConfig?.providers },
1249
1274
  providerConfigOverrides: {
1250
- ...buildProviderConfigOverrides(realtimeConfig),
1275
+ ...realtimeConfig?.model ? { model: realtimeConfig.model } : {},
1276
+ ...configuredVoice ? { voice: configuredVoice } : {},
1277
+ ...typeof realtimeConfig?.minBargeInAudioEndMs === "number" ? { minBargeInAudioEndMs: realtimeConfig.minBargeInAudioEndMs } : {},
1251
1278
  ...params.voiceOverride ? {
1252
1279
  voice: params.voiceOverride,
1253
1280
  speakerVoice: params.voiceOverride
@@ -1265,14 +1292,14 @@ function resolveDiscordRealtimeSpeakerConfig(params) {
1265
1292
  });
1266
1293
  assertSecretOwnerAvailable("capability", discordRealtimeVoiceSecretOwnerId(params.accountId, resolved.provider.id));
1267
1294
  const capabilities = resolved.capabilities;
1268
- const model = readProviderConfigString(resolved.providerConfig, "model") ?? resolved.provider.defaultModel;
1295
+ const model = normalizeOptionalString(resolved.providerConfig.model) ?? resolved.provider.defaultModel;
1269
1296
  const voices = [...capabilities?.voices ?? (model ? capabilities?.voicesByModel?.[model] : void 0) ?? resolved.provider.voices ?? []];
1270
1297
  const publicConfig = projectInternalRealtimeVoicePublicConfig({
1271
1298
  provider: resolved.provider,
1272
1299
  providerConfig: resolved.providerConfig,
1273
1300
  config: {
1274
1301
  model,
1275
- voice: readProviderConfigString(resolved.providerConfig, "speakerVoice") ?? readProviderConfigString(resolved.providerConfig, "voice")
1302
+ voice: normalizeOptionalString(resolved.providerConfig.speakerVoice) ?? normalizeOptionalString(resolved.providerConfig.voice)
1276
1303
  }
1277
1304
  });
1278
1305
  const selection = {
@@ -1323,7 +1350,7 @@ function resolveDiscordRealtimeSpeakerConfig(params) {
1323
1350
  bargeIn,
1324
1351
  minBargeInAudioEndMs,
1325
1352
  resolvedModel: model,
1326
- resolvedVoice: readProviderConfigString(resolved.providerConfig, "voice")
1353
+ resolvedVoice: normalizeOptionalString(resolved.providerConfig.voice)
1327
1354
  };
1328
1355
  }
1329
1356
  //#endregion
@@ -1331,9 +1358,6 @@ function resolveDiscordRealtimeSpeakerConfig(params) {
1331
1358
  const logger$1 = createSubsystemLogger("discord/voice");
1332
1359
  const DISCORD_REALTIME_DUPLICATE_ERROR_SUPPRESS_MS = 6e4;
1333
1360
  const discordRealtimeTalkPayload = () => ({});
1334
- function isDiscordAgentProxyVoiceMode(mode) {
1335
- return mode === "agent-proxy";
1336
- }
1337
1361
  var DiscordRealtimeSpeakerSession = class {
1338
1362
  constructor(params) {
1339
1363
  this.params = params;
@@ -1356,7 +1380,12 @@ var DiscordRealtimeSpeakerSession = class {
1356
1380
  this.inputIdleListeners = /* @__PURE__ */ new Set();
1357
1381
  this.lastActivityAt = Date.now();
1358
1382
  this.outputEnabled = !params.standby;
1359
- this.recording = this.createRecording();
1383
+ const recordingEpoch = this.providerContinuityEpoch;
1384
+ this.recording = new DiscordRealtimeRecording({
1385
+ entry: this.params.entry,
1386
+ isCurrent: () => this.lifecycle.status !== "stopped" && this.providerContinuityEpoch === recordingEpoch,
1387
+ warn: (message) => logger$1.warn(message)
1388
+ });
1360
1389
  this.harness = createRealtimeVoiceSessionHarness({
1361
1390
  talk: {
1362
1391
  sessionId: this.params.sessionId,
@@ -1427,7 +1456,7 @@ var DiscordRealtimeSpeakerSession = class {
1427
1456
  debounceMs: () => this.realtimeConfig?.debounceMs,
1428
1457
  entry: this.params.entry,
1429
1458
  harness: this.harness,
1430
- isAgentProxy: () => isDiscordAgentProxyVoiceMode(this.params.mode) && !this.handlesAgentConsult,
1459
+ isAgentProxy: () => this.params.mode === "agent-proxy" && !this.handlesAgentConsult,
1431
1460
  isWakeNameRequired: () => this.isWakeNameRequired(),
1432
1461
  playback: this.playback,
1433
1462
  providerEpoch: () => this.providerContinuityEpoch,
@@ -1450,7 +1479,7 @@ var DiscordRealtimeSpeakerSession = class {
1450
1479
  agentId: this.params.entry.route.agentId,
1451
1480
  cfg: this.params.cfg,
1452
1481
  realtimeConfig: this.realtimeConfig,
1453
- isAgentProxy: isDiscordAgentProxyVoiceMode(this.params.mode),
1482
+ isAgentProxy: this.params.mode === "agent-proxy",
1454
1483
  bootstrapContextInstructions: this.params.bootstrapContextInstructions,
1455
1484
  voiceOverride: this.params.voiceOverride,
1456
1485
  conversationHistory: this.params.conversationHistory
@@ -1548,6 +1577,7 @@ var DiscordRealtimeSpeakerSession = class {
1548
1577
  }
1549
1578
  const humanParticipantCount = this.humanParticipantCount();
1550
1579
  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}`);
1580
+ this.attachOutputAudioPort();
1551
1581
  await this.bridge.connect();
1552
1582
  if (!this.markLifecycleReady(lifecycleGeneration)) {
1553
1583
  await this.close();
@@ -1671,6 +1701,11 @@ var DiscordRealtimeSpeakerSession = class {
1671
1701
  activateOutput() {
1672
1702
  this.readVoiceSelection();
1673
1703
  this.outputEnabled = true;
1704
+ this.playback.activateOutputAudioPort();
1705
+ }
1706
+ attachOutputAudioPort() {
1707
+ const provider = this.bridge?.bridge;
1708
+ if (this.wakeNamePolicy === "never" && provider?.outputAudioMode === "continuous" && provider.setAudioOutputPort) provider.setAudioOutputPort(this.playback.createOutputAudioPort(this.outputEnabled));
1674
1709
  }
1675
1710
  hasActiveInput() {
1676
1711
  return this.captures.size > 0;
@@ -1750,14 +1785,6 @@ var DiscordRealtimeSpeakerSession = class {
1750
1785
  this.turns.resetProviderContinuity();
1751
1786
  this.playback.resetProviderContinuity(reason);
1752
1787
  }
1753
- createRecording() {
1754
- const epoch = this.providerContinuityEpoch;
1755
- return new DiscordRealtimeRecording({
1756
- entry: this.params.entry,
1757
- isCurrent: () => this.lifecycle.status !== "stopped" && this.providerContinuityEpoch === epoch,
1758
- warn: (message) => logger$1.warn(message)
1759
- });
1760
- }
1761
1788
  logRealtimeError(message) {
1762
1789
  const now = Date.now();
1763
1790
  if (this.lastRealtimeError?.message === message && now - this.lastRealtimeError.lastLoggedAt < DISCORD_REALTIME_DUPLICATE_ERROR_SUPPRESS_MS) {
@@ -1795,7 +1822,7 @@ var DiscordRealtimeVoiceSession = class {
1795
1822
  this.changingVoice = false;
1796
1823
  this.callAbort = new AbortController();
1797
1824
  this.candidates = /* @__PURE__ */ new Set();
1798
- this.player = new DiscordRealtimePlayer(params.entry.player);
1825
+ this.player = new DiscordRealtimePlayer(params.entry.audio);
1799
1826
  }
1800
1827
  async connect() {
1801
1828
  if (this.closed) throw new Error("Discord realtime voice session is closed");