@recombine-ai/platform 0.8.0-test.1 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/agent/experiment.d.ts +21 -0
- package/build/agent/experiment.d.ts.map +1 -0
- package/build/agent/experiment.js +29 -0
- package/build/agent/index.d.ts +6 -4
- package/build/agent/index.d.ts.map +1 -1
- package/build/agent/index.js +3 -2
- package/build/agent/text-agent.d.ts +2 -2
- package/build/agent/text-agent.d.ts.map +1 -1
- package/build/agent/text-agent.js +2 -2
- package/build/agent/voice-agent.d.ts +2 -2
- package/build/agent/voice-agent.d.ts.map +1 -1
- package/build/agent/voice-agent.js +2 -2
- package/build/bosun/index.d.ts +11 -10
- package/build/bosun/index.d.ts.map +1 -1
- package/build/bosun/index.js +7 -7
- package/build/bosun/interfaces/agent.d.ts +6 -5
- package/build/bosun/interfaces/agent.d.ts.map +1 -1
- package/build/bosun/interfaces/project.d.ts +25 -0
- package/build/bosun/interfaces/project.d.ts.map +1 -0
- package/build/bosun/interfaces/project.js +1 -0
- package/build/bosun/mock.d.ts +1 -1
- package/build/bosun/mock.d.ts.map +1 -1
- package/build/bosun/std-mocks/call-control.d.ts +2 -2
- package/build/bosun/std-mocks/call-control.d.ts.map +1 -1
- package/build/bosun/std-mocks/platform.d.ts +2 -2
- package/build/bosun/std-mocks/platform.d.ts.map +1 -1
- package/build/bosun/std-mocks/platform.js +6 -6
- package/build/bosun/test-agent.d.ts +2 -2
- package/build/bosun/test-agent.d.ts.map +1 -1
- package/build/bosun/test-agent.js +1 -1
- package/build/bosun/test-step-registry.d.ts +1 -1
- package/build/bosun/test-step-registry.d.ts.map +1 -1
- package/build/bosun-app/backend/server.js +252 -60
- package/build/bosun-app/backend/server.js.map +2 -2
- package/build/bosun-app/frontend/client/_app/immutable/chunks/{CR5IRTqC.js → AmpxVxY6.js} +1 -1
- package/build/bosun-app/frontend/client/_app/immutable/chunks/AmpxVxY6.js.br +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/chunks/AmpxVxY6.js.gz +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/chunks/{DjDpMqch.js → B-5g3xS8.js} +20 -20
- package/build/bosun-app/frontend/client/_app/immutable/chunks/B-5g3xS8.js.br +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/chunks/B-5g3xS8.js.gz +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/chunks/{BBk8_Xpk.js → B1MxGo6p.js} +1 -1
- package/build/bosun-app/frontend/client/_app/immutable/chunks/B1MxGo6p.js.br +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/chunks/B1MxGo6p.js.gz +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/chunks/{joiJcRPz.js → BqH4VDQz.js} +1 -1
- package/build/bosun-app/frontend/client/_app/immutable/chunks/BqH4VDQz.js.br +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/chunks/BqH4VDQz.js.gz +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/chunks/{B3KppP__.js → CQvDMTjY.js} +1 -1
- package/build/bosun-app/frontend/client/_app/immutable/chunks/CQvDMTjY.js.br +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/chunks/CQvDMTjY.js.gz +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/chunks/{C0rPkxmP.js → CVZT6n14.js} +1 -1
- package/build/bosun-app/frontend/client/_app/immutable/chunks/CVZT6n14.js.br +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/chunks/CVZT6n14.js.gz +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/chunks/{Csk7d6BP.js → CWPN78Jk.js} +1 -1
- package/build/bosun-app/frontend/client/_app/immutable/chunks/CWPN78Jk.js.br +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/chunks/CWPN78Jk.js.gz +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/chunks/{ouMvMh56.js → CkstLsmI.js} +1 -1
- package/build/bosun-app/frontend/client/_app/immutable/chunks/CkstLsmI.js.br +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/chunks/CkstLsmI.js.gz +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/chunks/{C3cROXCy.js → CuwQtXBl.js} +1 -1
- package/build/bosun-app/frontend/client/_app/immutable/chunks/CuwQtXBl.js.br +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/chunks/CuwQtXBl.js.gz +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/chunks/{BEdAvgYp.js → D9YsE4-8.js} +1 -1
- package/build/bosun-app/frontend/client/_app/immutable/chunks/D9YsE4-8.js.br +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/chunks/D9YsE4-8.js.gz +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/chunks/{CFHTd1Rp.js → DK7_9Rr4.js} +1 -1
- package/build/bosun-app/frontend/client/_app/immutable/chunks/DK7_9Rr4.js.br +3 -0
- package/build/bosun-app/frontend/client/_app/immutable/chunks/DK7_9Rr4.js.gz +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/chunks/{g-PBecQM.js → O3fJLrRA.js} +1 -1
- package/build/bosun-app/frontend/client/_app/immutable/chunks/O3fJLrRA.js.br +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/chunks/O3fJLrRA.js.gz +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/chunks/{DJnDF3d9.js → dL_jwANm.js} +1 -1
- package/build/bosun-app/frontend/client/_app/immutable/chunks/dL_jwANm.js.br +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/chunks/dL_jwANm.js.gz +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/chunks/w7_NKWP1.js +3 -0
- package/build/bosun-app/frontend/client/_app/immutable/chunks/w7_NKWP1.js.br +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/chunks/w7_NKWP1.js.gz +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/entry/{app.Trw4ULuE.js → app.Bq7QRKSZ.js} +2 -2
- package/build/bosun-app/frontend/client/_app/immutable/entry/app.Bq7QRKSZ.js.br +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/entry/app.Bq7QRKSZ.js.gz +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/entry/start.Ct26YHfm.js +1 -0
- package/build/bosun-app/frontend/client/_app/immutable/entry/start.Ct26YHfm.js.br +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/entry/start.Ct26YHfm.js.gz +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/nodes/{0.D_60dBJ-.js → 0.CIBqOQKB.js} +1 -1
- package/build/bosun-app/frontend/client/_app/immutable/nodes/0.CIBqOQKB.js.br +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/nodes/0.CIBqOQKB.js.gz +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/nodes/{1.Cb20jEGe.js → 1.Dv78wD0F.js} +1 -1
- package/build/bosun-app/frontend/client/_app/immutable/nodes/1.Dv78wD0F.js.br +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/nodes/1.Dv78wD0F.js.gz +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/nodes/10.Htrpia-u.js +35 -0
- package/build/bosun-app/frontend/client/_app/immutable/nodes/10.Htrpia-u.js.br +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/nodes/10.Htrpia-u.js.gz +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/nodes/{17.Dn5eKe2Q.js → 17.DmVfus5a.js} +1 -1
- package/build/bosun-app/frontend/client/_app/immutable/nodes/17.DmVfus5a.js.br +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/nodes/17.DmVfus5a.js.gz +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/nodes/18.DvJVYeXp.js +11 -0
- package/build/bosun-app/frontend/client/_app/immutable/nodes/18.DvJVYeXp.js.br +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/nodes/18.DvJVYeXp.js.gz +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/nodes/2.tyuQRxDb.js +35 -0
- package/build/bosun-app/frontend/client/_app/immutable/nodes/2.tyuQRxDb.js.br +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/nodes/2.tyuQRxDb.js.gz +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/nodes/3.B0NtJamE.js +1 -0
- package/build/bosun-app/frontend/client/_app/immutable/nodes/3.B0NtJamE.js.br +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/nodes/3.B0NtJamE.js.gz +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/nodes/{4.BhBj3Qad.js → 4.DKTRRObl.js} +1 -1
- package/build/bosun-app/frontend/client/_app/immutable/nodes/4.DKTRRObl.js.br +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/nodes/4.DKTRRObl.js.gz +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/nodes/{5.CMK8bzwn.js → 5.D9SClLPX.js} +1 -1
- package/build/bosun-app/frontend/client/_app/immutable/nodes/5.D9SClLPX.js.br +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/nodes/5.D9SClLPX.js.gz +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/nodes/{6.crW0u6fy.js → 6.DdAs7BvU.js} +1 -1
- package/build/bosun-app/frontend/client/_app/immutable/nodes/6.DdAs7BvU.js.br +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/nodes/6.DdAs7BvU.js.gz +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/nodes/{8.CxQxpCTc.js → 8.DNEyJy0a.js} +1 -1
- package/build/bosun-app/frontend/client/_app/immutable/nodes/8.DNEyJy0a.js.br +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/nodes/8.DNEyJy0a.js.gz +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/nodes/9.DcyIUk-F.js +2 -0
- package/build/bosun-app/frontend/client/_app/immutable/nodes/9.DcyIUk-F.js.br +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/nodes/9.DcyIUk-F.js.gz +0 -0
- package/build/bosun-app/frontend/client/_app/version.json +1 -1
- package/build/bosun-app/frontend/client/_app/version.json.br +0 -0
- package/build/bosun-app/frontend/client/_app/version.json.gz +0 -0
- package/build/bosun-app/frontend/handler.js +4 -4
- package/build/bosun-app/frontend/index.js +4 -4
- package/build/bosun-app/frontend/server/chunks/chunks/{ChatStepTrace.js-VTtwaKGp.js → ChatStepTrace.js-BY0y3Vbb.js} +3 -1
- package/build/bosun-app/frontend/server/chunks/chunks/ChatStepTrace.js-BY0y3Vbb.js.map +1 -0
- package/build/bosun-app/frontend/server/chunks/chunks/{internal.js-BTDNvJ-c.js → internal.js-CTNBeiir.js} +2 -2
- package/build/bosun-app/frontend/server/chunks/chunks/{internal.js-BTDNvJ-c.js.map → internal.js-CTNBeiir.js.map} +1 -1
- package/build/bosun-app/frontend/server/chunks/chunks/{source-selection.js-D5B8gfq2.js → source-selection.js-DFpObbhz.js} +3 -1
- package/build/bosun-app/frontend/server/chunks/chunks/source-selection.js-DFpObbhz.js.map +1 -0
- package/build/bosun-app/frontend/server/chunks/entries/pages/edit/_agent_/{_layout.svelte.js-B2wHKJV7.js → _layout.svelte.js-b9Q5TFEZ.js} +134 -24
- package/build/bosun-app/frontend/server/chunks/entries/pages/edit/_agent_/_layout.svelte.js-b9Q5TFEZ.js.map +1 -0
- package/build/bosun-app/frontend/server/chunks/entries/pages/edit/_agent_/roleplay/{_page.svelte.js-DDcIjgZD.js → _page.svelte.js-Chv8ybaj.js} +10 -4
- package/build/bosun-app/frontend/server/chunks/entries/pages/edit/_agent_/roleplay/_page.svelte.js-Chv8ybaj.js.map +1 -0
- package/build/bosun-app/frontend/server/chunks/entries/pages/edit/_agent_/tests/{_page.svelte.js-UVUg89-t.js → _page.svelte.js-Dkst1C_3.js} +3 -1
- package/build/bosun-app/frontend/server/chunks/entries/pages/edit/_agent_/tests/_page.svelte.js-Dkst1C_3.js.map +1 -0
- package/build/bosun-app/frontend/server/chunks/entries/pages/traces/conversations/_conversationId_/latency/{_page.svelte.js-SjAtxtA0.js → _page.svelte.js-DFZznMhQ.js} +2 -2
- package/build/bosun-app/frontend/server/chunks/entries/pages/traces/conversations/_conversationId_/latency/{_page.svelte.js-SjAtxtA0.js.map → _page.svelte.js-DFZznMhQ.js.map} +1 -1
- package/build/bosun-app/frontend/server/chunks/entries/pages/traces/conversations/_conversationId_/traces/{_page.svelte.js-DiZKDT2v.js → _page.svelte.js-Bxdn8vG5.js} +7 -3
- package/build/bosun-app/frontend/server/chunks/entries/pages/traces/conversations/_conversationId_/traces/_page.svelte.js-Bxdn8vG5.js.map +1 -0
- package/build/bosun-app/frontend/server/chunks/entries/pages/traces/conversations/{_layout.svelte.js-CfkCQ2Th.js → _layout.svelte.js-DhdYiNVL.js} +61 -9
- package/build/bosun-app/frontend/server/chunks/entries/pages/traces/conversations/_layout.svelte.js-DhdYiNVL.js.map +1 -0
- package/build/bosun-app/frontend/server/chunks/{handler-BXPSqa_7.js → handler-kZm9DU-v.js} +3 -3
- package/build/bosun-app/frontend/server/chunks/{handler-BXPSqa_7.js.map → handler-kZm9DU-v.js.map} +1 -1
- package/build/bosun-app/frontend/server/chunks/{index.js-BZbRqClk.js → index.js-BYV_PeV-.js} +2 -2
- package/build/bosun-app/frontend/server/chunks/{index.js-BZbRqClk.js.map → index.js-BYV_PeV-.js.map} +1 -1
- package/build/bosun-app/frontend/server/chunks/{manifest.js-p3UnZHmy.js → manifest.js-DknJwtFc.js} +14 -14
- package/build/bosun-app/frontend/server/chunks/{manifest.js-p3UnZHmy.js.map → manifest.js-DknJwtFc.js.map} +1 -1
- package/build/bosun-app/frontend/server/chunks/nodes/{0.js-BQwWqY6O.js → 0.js-B947oA7Q.js} +2 -2
- package/build/bosun-app/frontend/server/chunks/nodes/{0.js-BQwWqY6O.js.map → 0.js-B947oA7Q.js.map} +1 -1
- package/build/bosun-app/frontend/server/chunks/nodes/{1.js-DWMXqkHn.js → 1.js-D-bO8SBw.js} +2 -2
- package/build/bosun-app/frontend/server/chunks/nodes/{1.js-DWMXqkHn.js.map → 1.js-D-bO8SBw.js.map} +1 -1
- package/build/bosun-app/frontend/server/chunks/nodes/{10.js-CB3GNMkF.js → 10.js-BPINRsAS.js} +3 -3
- package/build/bosun-app/frontend/server/chunks/nodes/{10.js-CB3GNMkF.js.map → 10.js-BPINRsAS.js.map} +1 -1
- package/build/bosun-app/frontend/server/chunks/nodes/{17.js-DPvcLgLR.js → 17.js-BvBqWcLx.js} +3 -3
- package/build/bosun-app/frontend/server/chunks/nodes/{17.js-DPvcLgLR.js.map → 17.js-BvBqWcLx.js.map} +1 -1
- package/build/bosun-app/frontend/server/chunks/nodes/{18.js-B_lhm3O6.js → 18.js-BEfVGplP.js} +3 -3
- package/build/bosun-app/frontend/server/chunks/nodes/{18.js-B_lhm3O6.js.map → 18.js-BEfVGplP.js.map} +1 -1
- package/build/bosun-app/frontend/server/chunks/nodes/{2.js-Jm4bxpsW.js → 2.js-XaMsKwVG.js} +3 -3
- package/build/bosun-app/frontend/server/chunks/nodes/{2.js-Jm4bxpsW.js.map → 2.js-XaMsKwVG.js.map} +1 -1
- package/build/bosun-app/frontend/server/chunks/nodes/{3.js-DQMKjGbU.js → 3.js-9Rmo9ovG.js} +3 -3
- package/build/bosun-app/frontend/server/chunks/nodes/{3.js-DQMKjGbU.js.map → 3.js-9Rmo9ovG.js.map} +1 -1
- package/build/bosun-app/frontend/server/chunks/nodes/{4.js-BKjbVr3z.js → 4.js-DHzNp2kw.js} +2 -2
- package/build/bosun-app/frontend/server/chunks/nodes/{4.js-BKjbVr3z.js.map → 4.js-DHzNp2kw.js.map} +1 -1
- package/build/bosun-app/frontend/server/chunks/nodes/{5.js-zoBBtYRJ.js → 5.js-BtTetd8U.js} +2 -2
- package/build/bosun-app/frontend/server/chunks/nodes/{5.js-zoBBtYRJ.js.map → 5.js-BtTetd8U.js.map} +1 -1
- package/build/bosun-app/frontend/server/chunks/nodes/{6.js-x3TWBh2g.js → 6.js-dyYItn4O.js} +2 -2
- package/build/bosun-app/frontend/server/chunks/nodes/{6.js-x3TWBh2g.js.map → 6.js-dyYItn4O.js.map} +1 -1
- package/build/bosun-app/frontend/server/chunks/nodes/{8.js-lsQ6rRax.js → 8.js-D5qfNA9r.js} +2 -2
- package/build/bosun-app/frontend/server/chunks/nodes/{8.js-lsQ6rRax.js.map → 8.js-D5qfNA9r.js.map} +1 -1
- package/build/bosun-app/frontend/server/chunks/nodes/{9.js-MXqtxrRo.js → 9.js-CxI4tPnx.js} +3 -3
- package/build/bosun-app/frontend/server/chunks/nodes/{9.js-MXqtxrRo.js.map → 9.js-CxI4tPnx.js.map} +1 -1
- package/build/build/build.d.ts +1 -1
- package/build/build/build.d.ts.map +1 -1
- package/build/build/build.js +1 -1
- package/build/build/cli.js +2 -2
- package/build/build/index.d.ts +4 -4
- package/build/build/index.d.ts.map +1 -1
- package/build/build/index.js +3 -3
- package/build/call-control/call-control.d.ts +4 -4
- package/build/call-control/call-control.d.ts.map +1 -1
- package/build/call-control/call-control.js +4 -6
- package/build/call-control/call-details/index.d.ts +1 -1
- package/build/call-control/call-details/index.d.ts.map +1 -1
- package/build/call-control/call-details/index.js +1 -1
- package/build/call-control/call-details/noop-storage.d.ts +1 -1
- package/build/call-control/call-details/noop-storage.d.ts.map +1 -1
- package/build/call-control/index.d.ts +6 -7
- package/build/call-control/index.d.ts.map +1 -1
- package/build/call-control/index.js +4 -5
- package/build/call-control/port.d.ts +2 -2
- package/build/call-control/port.d.ts.map +1 -1
- package/build/call-control/schemas.generated.d.ts +2 -1
- package/build/call-control/schemas.generated.d.ts.map +1 -1
- package/build/call-control/schemas.generated.js +4 -4
- package/build/call-control/sip-setup-lock.d.ts +1 -1
- package/build/call-control/sip-setup-lock.d.ts.map +1 -1
- package/build/call-control/sip-setup-lock.js +1 -1
- package/build/call-control/sip.d.ts +2 -2
- package/build/call-control/sip.d.ts.map +1 -1
- package/build/call-control/sip.js +3 -3
- package/build/call-control/types.d.ts +160 -7
- package/build/call-control/types.d.ts.map +1 -1
- package/build/call-control/types.js +3 -3
- package/build/call-control/utils.d.ts +1 -1
- package/build/call-control/utils.d.ts.map +1 -1
- package/build/core/get-text-platform.d.ts +4 -4
- package/build/core/get-text-platform.d.ts.map +1 -1
- package/build/core/get-text-platform.js +4 -4
- package/build/core/get-voice-platform.d.ts +6 -6
- package/build/core/get-voice-platform.d.ts.map +1 -1
- package/build/core/get-voice-platform.js +5 -5
- package/build/core/index.d.ts +5 -5
- package/build/core/index.d.ts.map +1 -1
- package/build/core/index.js +2 -2
- package/build/core/platform.d.ts +6 -6
- package/build/core/platform.d.ts.map +1 -1
- package/build/dockyard/index.d.ts +3 -3
- package/build/dockyard/index.d.ts.map +1 -1
- package/build/dockyard/index.js +2 -2
- package/build/dockyard/logger/base.d.ts +1 -1
- package/build/dockyard/logger/base.d.ts.map +1 -1
- package/build/dockyard/logger/helpers.d.ts +1 -1
- package/build/dockyard/logger/helpers.d.ts.map +1 -1
- package/build/dockyard/logger/index.d.ts +3 -3
- package/build/dockyard/logger/index.d.ts.map +1 -1
- package/build/dockyard/logger/index.js +4 -4
- package/build/engine/bosun/agent.d.ts +6 -6
- package/build/engine/bosun/agent.d.ts.map +1 -1
- package/build/engine/bosun/api-call-tracer.d.ts +3 -3
- package/build/engine/bosun/api-call-tracer.d.ts.map +1 -1
- package/build/engine/bosun/conversational-tracer.d.ts +3 -3
- package/build/engine/bosun/conversational-tracer.d.ts.map +1 -1
- package/build/engine/bosun/index.d.ts +8 -8
- package/build/engine/bosun/index.d.ts.map +1 -1
- package/build/engine/bosun/index.js +7 -7
- package/build/engine/bosun/mock.d.ts +1 -1
- package/build/engine/bosun/mock.d.ts.map +1 -1
- package/build/engine/bosun/step-tracer.d.ts +3 -3
- package/build/engine/bosun/step-tracer.d.ts.map +1 -1
- package/build/engine/default-logger.d.ts +1 -1
- package/build/engine/default-logger.d.ts.map +1 -1
- package/build/engine/default-logger.js +1 -1
- package/build/engine/engine.d.ts +2 -2
- package/build/engine/engine.d.ts.map +1 -1
- package/build/engine/engine.js +4 -4
- package/build/engine/index.d.ts +14 -14
- package/build/engine/index.d.ts.map +1 -1
- package/build/engine/index.js +7 -7
- package/build/engine/interfaces/adapter.d.ts +1 -1
- package/build/engine/interfaces/adapter.d.ts.map +1 -1
- package/build/engine/interfaces/engine.d.ts +6 -6
- package/build/engine/interfaces/engine.d.ts.map +1 -1
- package/build/engine/interfaces/index.d.ts +7 -7
- package/build/engine/interfaces/index.d.ts.map +1 -1
- package/build/engine/interfaces/index.js +7 -7
- package/build/engine/interfaces/other.d.ts +2 -2
- package/build/engine/interfaces/other.d.ts.map +1 -1
- package/build/engine/interfaces/steps.d.ts +4 -4
- package/build/engine/interfaces/steps.d.ts.map +1 -1
- package/build/engine/interfaces/stream.d.ts +6 -6
- package/build/engine/interfaces/stream.d.ts.map +1 -1
- package/build/engine/interfaces/workflow.d.ts +2 -2
- package/build/engine/interfaces/workflow.d.ts.map +1 -1
- package/build/engine/llm-adapters/index.d.ts +4 -4
- package/build/engine/llm-adapters/index.d.ts.map +1 -1
- package/build/engine/llm-adapters/index.js +4 -4
- package/build/engine/llm-adapters/mock.d.ts +1 -1
- package/build/engine/llm-adapters/mock.d.ts.map +1 -1
- package/build/engine/llm-adapters/openai-stream.d.ts +1 -1
- package/build/engine/llm-adapters/openai-stream.d.ts.map +1 -1
- package/build/engine/llm-adapters/openai-stream.js +2 -2
- package/build/engine/llm-adapters/openai.d.ts +1 -1
- package/build/engine/llm-adapters/openai.d.ts.map +1 -1
- package/build/engine/llm-adapters/openai.js +2 -2
- package/build/engine/llm-adapters/provider.d.ts +1 -1
- package/build/engine/llm-adapters/provider.d.ts.map +1 -1
- package/build/engine/monitoring/index.d.ts +1 -1
- package/build/engine/monitoring/index.d.ts.map +1 -1
- package/build/engine/monitoring/index.js +1 -1
- package/build/engine/monitoring/provider-errors.d.ts +3 -3
- package/build/engine/monitoring/provider-errors.d.ts.map +1 -1
- package/build/engine/prompt-fs.d.ts +1 -1
- package/build/engine/prompt-fs.d.ts.map +1 -1
- package/build/engine/prompt-fs.js +1 -1
- package/build/engine/step-registry.d.ts +2 -2
- package/build/engine/step-registry.d.ts.map +1 -1
- package/build/engine/stream/engine.d.ts +1 -1
- package/build/engine/stream/engine.d.ts.map +1 -1
- package/build/engine/stream/engine.js +5 -5
- package/build/engine/stream/get-client.d.ts +1 -1
- package/build/engine/stream/get-client.d.ts.map +1 -1
- package/build/engine/stream/index.d.ts +3 -3
- package/build/engine/stream/index.d.ts.map +1 -1
- package/build/engine/stream/index.js +2 -2
- package/build/index.d.ts +2 -2
- package/build/index.d.ts.map +1 -1
- package/build/index.js +2 -2
- package/build/notifications/index.d.ts +4 -4
- package/build/notifications/index.d.ts.map +1 -1
- package/build/notifications/index.js +4 -4
- package/build/notifications/logger.d.ts +1 -1
- package/build/notifications/logger.d.ts.map +1 -1
- package/build/notifications/logger.js +1 -1
- package/build/notifications/publisher.d.ts +1 -1
- package/build/notifications/publisher.d.ts.map +1 -1
- package/build/notifications/publisher.js +2 -2
- package/build/notifications/router.d.ts +3 -3
- package/build/notifications/router.d.ts.map +1 -1
- package/build/notifications/router.js +2 -2
- package/build/notifications/transport.d.ts +1 -1
- package/build/notifications/transport.d.ts.map +1 -1
- package/build/notifications/transport.js +1 -1
- package/build/steps/helpers.d.ts +2 -2
- package/build/steps/helpers.d.ts.map +1 -1
- package/build/steps/index.d.ts +9 -9
- package/build/steps/index.d.ts.map +1 -1
- package/build/steps/index.js +5 -5
- package/build/steps/slot-booker/book-slot/step.d.ts +4 -4
- package/build/steps/slot-booker/book-slot/step.d.ts.map +1 -1
- package/build/steps/slot-booker/book-slot/step.js +2 -2
- package/build/steps/slot-booker/check-slots-for-match/step.d.ts +4 -4
- package/build/steps/slot-booker/check-slots-for-match/step.d.ts.map +1 -1
- package/build/steps/slot-booker/check-slots-for-match/step.js +1 -1
- package/build/steps/slot-booker/cleanup/step.d.ts +4 -4
- package/build/steps/slot-booker/cleanup/step.d.ts.map +1 -1
- package/build/steps/slot-booker/find-slots/step.d.ts +4 -4
- package/build/steps/slot-booker/find-slots/step.d.ts.map +1 -1
- package/build/steps/slot-booker/find-slots/step.js +2 -2
- package/build/steps/slot-booker/init/step.d.ts +4 -4
- package/build/steps/slot-booker/init/step.d.ts.map +1 -1
- package/build/steps/slot-booker/interfaces.d.ts +4 -4
- package/build/steps/slot-booker/interfaces.d.ts.map +1 -1
- package/build/steps/slot-booker/slot-booker.d.ts +7 -7
- package/build/steps/slot-booker/slot-booker.d.ts.map +1 -1
- package/build/steps/slot-booker/slot-booker.js +6 -6
- package/build/steps/slot-booker/util.d.ts +1 -1
- package/build/steps/slot-booker/util.d.ts.map +1 -1
- package/build/telescope/api.d.ts +1 -1
- package/build/telescope/api.d.ts.map +1 -1
- package/build/telescope/api.js +8 -2
- package/build/telescope/create-telescope.d.ts +3 -3
- package/build/telescope/create-telescope.d.ts.map +1 -1
- package/build/telescope/create-telescope.js +3 -3
- package/build/telescope/index.d.ts +21 -21
- package/build/telescope/index.d.ts.map +1 -1
- package/build/telescope/index.js +8 -8
- package/build/telescope/interfaces/conversation.d.ts +8 -0
- package/build/telescope/interfaces/conversation.d.ts.map +1 -1
- package/build/telescope/interfaces/event-tracer.d.ts +8 -0
- package/build/telescope/interfaces/event-tracer.d.ts.map +1 -1
- package/build/telescope/interfaces/storage.d.ts +3 -3
- package/build/telescope/interfaces/storage.d.ts.map +1 -1
- package/build/telescope/interfaces/telescope.d.ts +7 -6
- package/build/telescope/interfaces/telescope.d.ts.map +1 -1
- package/build/telescope/interfaces/traces.d.ts +1 -1
- package/build/telescope/interfaces/traces.d.ts.map +1 -1
- package/build/telescope/stub-storage.d.ts +5 -5
- package/build/telescope/stub-storage.d.ts.map +1 -1
- package/build/telescope/stub-storage.js +4 -9
- package/build/telescope/stub-telescope.d.ts +2 -2
- package/build/telescope/stub-telescope.d.ts.map +1 -1
- package/build/telescope/stub-telescope.js +1 -1
- package/build/telescope/stubs.d.ts +5 -5
- package/build/telescope/stubs.d.ts.map +1 -1
- package/build/telescope/telescope.d.ts +6 -6
- package/build/telescope/telescope.d.ts.map +1 -1
- package/build/telescope/telescope.js +1 -1
- package/build/telescope/trace-helpers.d.ts +3 -3
- package/build/telescope/trace-helpers.d.ts.map +1 -1
- package/build/telescope/tracers/api-call-tracer.d.ts +4 -4
- package/build/telescope/tracers/api-call-tracer.d.ts.map +1 -1
- package/build/telescope/tracers/conversational-tracer.d.ts +4 -4
- package/build/telescope/tracers/conversational-tracer.d.ts.map +1 -1
- package/build/telescope/tracers/event-tracer.d.ts +2 -2
- package/build/telescope/tracers/event-tracer.d.ts.map +1 -1
- package/build/telescope/tracers/event-tracer.js +5 -0
- package/build/telescope/tracers/index.d.ts +6 -6
- package/build/telescope/tracers/index.d.ts.map +1 -1
- package/build/telescope/tracers/index.js +5 -5
- package/build/telescope/tracers/latency-tracer.d.ts +4 -4
- package/build/telescope/tracers/latency-tracer.d.ts.map +1 -1
- package/build/telescope/tracers/step-tracer.d.ts +4 -4
- package/build/telescope/tracers/step-tracer.d.ts.map +1 -1
- package/build/text-agent-handlers/incoming-message.d.ts +3 -3
- package/build/text-agent-handlers/incoming-message.d.ts.map +1 -1
- package/build/text-agent-handlers/incoming-message.js +2 -2
- package/build/text-agent-handlers/index.d.ts +15 -14
- package/build/text-agent-handlers/index.d.ts.map +1 -1
- package/build/text-agent-handlers/index.js +7 -6
- package/build/text-agent-handlers/instrument.d.ts +4 -3
- package/build/text-agent-handlers/instrument.d.ts.map +1 -1
- package/build/text-agent-handlers/instrument.js +7 -3
- package/build/text-agent-handlers/jobs-handler.d.ts +3 -3
- package/build/text-agent-handlers/jobs-handler.d.ts.map +1 -1
- package/build/text-agent-handlers/jobs-handler.js +2 -2
- package/build/text-agent-handlers/jobs.d.ts +1 -0
- package/build/text-agent-handlers/jobs.d.ts.map +1 -1
- package/build/text-agent-handlers/message-acceptor.d.ts +8 -4
- package/build/text-agent-handlers/message-acceptor.d.ts.map +1 -1
- package/build/text-agent-handlers/message-acceptor.js +9 -3
- package/build/text-agent-handlers/notification-hook.d.ts +3 -3
- package/build/text-agent-handlers/notification-hook.d.ts.map +1 -1
- package/build/text-agent-handlers/notification-hook.js +2 -2
- package/build/text-agent-handlers/ports.d.ts +5 -4
- package/build/text-agent-handlers/ports.d.ts.map +1 -1
- package/build/text-agent-handlers/ports.js +6 -5
- package/build/text-agent-handlers/variant-scheduler.d.ts +3 -0
- package/build/text-agent-handlers/variant-scheduler.d.ts.map +1 -0
- package/build/text-agent-handlers/variant-scheduler.js +9 -0
- package/build/timeout-manager/index.d.ts +2 -2
- package/build/timeout-manager/index.d.ts.map +1 -1
- package/build/voice-agent-api/http-helpers.d.ts +1 -1
- package/build/voice-agent-api/http-helpers.d.ts.map +1 -1
- package/build/voice-agent-api/http-helpers.js +1 -1
- package/build/voice-agent-api/index.d.ts +7 -5
- package/build/voice-agent-api/index.d.ts.map +1 -1
- package/build/voice-agent-api/index.js +4 -3
- package/build/voice-agent-api/llm-completion-handler.d.ts +2 -2
- package/build/voice-agent-api/llm-completion-handler.d.ts.map +1 -1
- package/build/voice-agent-api/llm-completion-handler.js +3 -3
- package/build/voice-agent-api/logger.d.ts +2 -2
- package/build/voice-agent-api/logger.d.ts.map +1 -1
- package/build/voice-agent-api/logger.js +1 -1
- package/build/voice-agent-api/route-resolver.d.ts +19 -0
- package/build/voice-agent-api/route-resolver.d.ts.map +1 -0
- package/build/voice-agent-api/route-resolver.js +57 -0
- package/build/voice-agent-api/voice-http.d.ts +10 -6
- package/build/voice-agent-api/voice-http.d.ts.map +1 -1
- package/build/voice-agent-api/voice-http.js +36 -37
- package/package.json +3 -7
- package/build/bosun-app/frontend/client/_app/immutable/chunks/B3KppP__.js.br +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/chunks/B3KppP__.js.gz +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/chunks/BBk8_Xpk.js.br +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/chunks/BBk8_Xpk.js.gz +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/chunks/BEdAvgYp.js.br +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/chunks/BEdAvgYp.js.gz +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/chunks/C0rPkxmP.js.br +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/chunks/C0rPkxmP.js.gz +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/chunks/C3cROXCy.js.br +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/chunks/C3cROXCy.js.gz +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/chunks/CFHTd1Rp.js.br +0 -2
- package/build/bosun-app/frontend/client/_app/immutable/chunks/CFHTd1Rp.js.gz +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/chunks/CR5IRTqC.js.br +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/chunks/CR5IRTqC.js.gz +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/chunks/Csk7d6BP.js.br +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/chunks/Csk7d6BP.js.gz +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/chunks/DJnDF3d9.js.br +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/chunks/DJnDF3d9.js.gz +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/chunks/DjDpMqch.js.br +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/chunks/DjDpMqch.js.gz +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/chunks/g-PBecQM.js.br +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/chunks/g-PBecQM.js.gz +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/chunks/joiJcRPz.js.br +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/chunks/joiJcRPz.js.gz +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/chunks/ouMvMh56.js.br +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/chunks/ouMvMh56.js.gz +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/chunks/zEK2_zeg.js +0 -3
- package/build/bosun-app/frontend/client/_app/immutable/chunks/zEK2_zeg.js.br +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/chunks/zEK2_zeg.js.gz +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/entry/app.Trw4ULuE.js.br +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/entry/app.Trw4ULuE.js.gz +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/entry/start.DAo7jQEf.js +0 -1
- package/build/bosun-app/frontend/client/_app/immutable/entry/start.DAo7jQEf.js.br +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/entry/start.DAo7jQEf.js.gz +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/nodes/0.D_60dBJ-.js.br +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/nodes/0.D_60dBJ-.js.gz +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/nodes/1.Cb20jEGe.js.br +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/nodes/1.Cb20jEGe.js.gz +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/nodes/10.ihk_thZi.js +0 -35
- package/build/bosun-app/frontend/client/_app/immutable/nodes/10.ihk_thZi.js.br +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/nodes/10.ihk_thZi.js.gz +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/nodes/17.Dn5eKe2Q.js.br +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/nodes/17.Dn5eKe2Q.js.gz +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/nodes/18.C0bK6rdq.js +0 -11
- package/build/bosun-app/frontend/client/_app/immutable/nodes/18.C0bK6rdq.js.br +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/nodes/18.C0bK6rdq.js.gz +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/nodes/2.C2UMBwkC.js +0 -35
- package/build/bosun-app/frontend/client/_app/immutable/nodes/2.C2UMBwkC.js.br +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/nodes/2.C2UMBwkC.js.gz +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/nodes/3.D35G6Br8.js +0 -1
- package/build/bosun-app/frontend/client/_app/immutable/nodes/3.D35G6Br8.js.br +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/nodes/3.D35G6Br8.js.gz +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/nodes/4.BhBj3Qad.js.br +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/nodes/4.BhBj3Qad.js.gz +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/nodes/5.CMK8bzwn.js.br +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/nodes/5.CMK8bzwn.js.gz +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/nodes/6.crW0u6fy.js.br +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/nodes/6.crW0u6fy.js.gz +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/nodes/8.CxQxpCTc.js.br +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/nodes/8.CxQxpCTc.js.gz +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/nodes/9.BXh1IZwx.js +0 -2
- package/build/bosun-app/frontend/client/_app/immutable/nodes/9.BXh1IZwx.js.br +0 -0
- package/build/bosun-app/frontend/client/_app/immutable/nodes/9.BXh1IZwx.js.gz +0 -0
- package/build/bosun-app/frontend/server/chunks/chunks/ChatStepTrace.js-VTtwaKGp.js.map +0 -1
- package/build/bosun-app/frontend/server/chunks/chunks/source-selection.js-D5B8gfq2.js.map +0 -1
- package/build/bosun-app/frontend/server/chunks/entries/pages/edit/_agent_/_layout.svelte.js-B2wHKJV7.js.map +0 -1
- package/build/bosun-app/frontend/server/chunks/entries/pages/edit/_agent_/roleplay/_page.svelte.js-DDcIjgZD.js.map +0 -1
- package/build/bosun-app/frontend/server/chunks/entries/pages/edit/_agent_/tests/_page.svelte.js-UVUg89-t.js.map +0 -1
- package/build/bosun-app/frontend/server/chunks/entries/pages/traces/conversations/_conversationId_/traces/_page.svelte.js-DiZKDT2v.js.map +0 -1
- package/build/bosun-app/frontend/server/chunks/entries/pages/traces/conversations/_layout.svelte.js-CfkCQ2Th.js.map +0 -1
- package/build/call-control/voice-agent-config.d.ts +0 -155
- package/build/call-control/voice-agent-config.d.ts.map +0 -1
- package/build/call-control/voice-agent-config.js +0 -53
- package/build/call-control.runtime.js +0 -1057
|
@@ -1,1057 +0,0 @@
|
|
|
1
|
-
// src/call-control/types.ts
|
|
2
|
-
import {
|
|
3
|
-
Room,
|
|
4
|
-
SIPDispatchRuleInfo as SipDispatchRule,
|
|
5
|
-
SIPInboundTrunkInfo as SipInboundTrunk,
|
|
6
|
-
SIPOutboundTrunkInfo as SipOutboundTrunk
|
|
7
|
-
} from "livekit-server-sdk";
|
|
8
|
-
|
|
9
|
-
// src/call-control/schemas.generated.ts
|
|
10
|
-
import { z } from "zod";
|
|
11
|
-
var configSchema = z.object({
|
|
12
|
-
agent_background_audio_volume: z.number().default(0.2),
|
|
13
|
-
agent_background_audio_autopause: z.boolean().default(false),
|
|
14
|
-
session_turn_detection: z.enum(["stt", "vad", "model"]).describe(
|
|
15
|
-
"Strategy for deciding when the user has finished speaking. 'stt' relies on speech-to-text end-of-utterance cues, 'vad' relies on Voice Activity Detection start/stop cues, and 'model' uses the audio turn detector"
|
|
16
|
-
).default("model"),
|
|
17
|
-
session_allow_interruptions: z.boolean().describe("Whether the user can interrupt the agent mid-utterance").default(true),
|
|
18
|
-
agent_dynamic_interruption_escalation: z.boolean().describe(
|
|
19
|
-
"Whether to dynamically escalate interruption threshold if user does not interrupt within the defined delay after TTS starts"
|
|
20
|
-
).default(false),
|
|
21
|
-
session_min_interruption_words: z.number().int().describe(
|
|
22
|
-
"Minimum number of transcribed words to consider an interruption (only used when STT is enabled)"
|
|
23
|
-
).default(1),
|
|
24
|
-
session_min_interruption_duration: z.number().describe("Minimum speech length in seconds to register as an interruption").default(0.1),
|
|
25
|
-
session_min_endpointing_delay: z.number().describe(
|
|
26
|
-
"Minimum time in seconds since the last detected speech before the agent declares the user's turn complete. In VAD mode behaves like max(VAD silence, min_endpointing_delay); in STT mode applied after the STT end-of-speech signal, so it can be additive with the STT provider's endpointing delay"
|
|
27
|
-
).default(0.1),
|
|
28
|
-
session_max_endpointing_delay: z.number().describe("Maximum time in seconds the agent will wait before terminating the turn").default(3),
|
|
29
|
-
session_preemptive_generation: z.boolean().describe(
|
|
30
|
-
"Whether to speculatively begin LLM and TTS requests before end-of-turn is detected. Reduces response latency by overlapping model inference with user audio, but may incur extra compute if the user interrupts mid-utterance"
|
|
31
|
-
).default(true),
|
|
32
|
-
vad_min_speech_duration: z.number().describe("Minimum duration of speech in seconds to start a new speech chunk").default(0.02),
|
|
33
|
-
vad_min_silence_duration: z.number().describe(
|
|
34
|
-
"At the end of each speech, wait this duration in seconds before ending the speech. The audio turn detector requires at least 0.25 seconds"
|
|
35
|
-
).default(1),
|
|
36
|
-
vad_prefix_padding_duration: z.number().describe("Duration in seconds of padding to add to the beginning of each speech chunk").default(0.5),
|
|
37
|
-
vad_max_buffered_speech: z.number().describe("Maximum duration of speech to keep in the buffer, in seconds").default(180),
|
|
38
|
-
vad_activation_threshold: z.number().describe("Threshold to consider a frame as speech").default(0.1),
|
|
39
|
-
vad_deactivation_threshold: z.union([z.number(), z.null()]).describe(
|
|
40
|
-
"Negative threshold (noise or exit threshold). If model's current state is SPEECH, values below this are considered as NON-SPEECH. Default is max(activation_threshold - 0.15, 0.01)"
|
|
41
|
-
).default(null),
|
|
42
|
-
vad_sample_rate: z.union([z.literal(8e3), z.literal(16e3)]).describe("Sample rate for VAD inference (only 8KHz and 16KHz are supported)").default(8e3),
|
|
43
|
-
stt_api_version: z.union([z.literal(1), z.literal(2)]).describe(
|
|
44
|
-
"Deepgram API version. Version 1 is the default with rich configuration options. Version 2 uses the Flux model family with end-of-turn detection (eot_threshold, eot_timeout_ms, eager_eot_threshold)"
|
|
45
|
-
).default(1),
|
|
46
|
-
stt_model: z.union([
|
|
47
|
-
z.literal("flux-general-en"),
|
|
48
|
-
z.enum([
|
|
49
|
-
"nova-general",
|
|
50
|
-
"nova-phonecall",
|
|
51
|
-
"nova-meeting",
|
|
52
|
-
"nova-2-general",
|
|
53
|
-
"nova-2-meeting",
|
|
54
|
-
"nova-2-phonecall",
|
|
55
|
-
"nova-2-finance",
|
|
56
|
-
"nova-2-conversationalai",
|
|
57
|
-
"nova-2-voicemail",
|
|
58
|
-
"nova-2-video",
|
|
59
|
-
"nova-2-medical",
|
|
60
|
-
"nova-2-drivethru",
|
|
61
|
-
"nova-2-automotive",
|
|
62
|
-
"nova-3",
|
|
63
|
-
"nova-3-general",
|
|
64
|
-
"nova-3-medical",
|
|
65
|
-
"enhanced-general",
|
|
66
|
-
"enhanced-meeting",
|
|
67
|
-
"enhanced-phonecall",
|
|
68
|
-
"enhanced-finance",
|
|
69
|
-
"base",
|
|
70
|
-
"meeting",
|
|
71
|
-
"phonecall",
|
|
72
|
-
"finance",
|
|
73
|
-
"conversationalai",
|
|
74
|
-
"voicemail",
|
|
75
|
-
"video",
|
|
76
|
-
"whisper-tiny",
|
|
77
|
-
"whisper-base",
|
|
78
|
-
"whisper-small",
|
|
79
|
-
"whisper-medium",
|
|
80
|
-
"whisper-large"
|
|
81
|
-
])
|
|
82
|
-
]).describe("The Deepgram model to use for speech recognition").default("nova-3"),
|
|
83
|
-
stt_language: z.enum([
|
|
84
|
-
"zh",
|
|
85
|
-
"zh-CN",
|
|
86
|
-
"zh-TW",
|
|
87
|
-
"da",
|
|
88
|
-
"nl",
|
|
89
|
-
"en",
|
|
90
|
-
"en-US",
|
|
91
|
-
"en-AU",
|
|
92
|
-
"en-GB",
|
|
93
|
-
"en-NZ",
|
|
94
|
-
"en-IN",
|
|
95
|
-
"fr",
|
|
96
|
-
"fr-CA",
|
|
97
|
-
"de",
|
|
98
|
-
"hi",
|
|
99
|
-
"hi-Latn",
|
|
100
|
-
"pt",
|
|
101
|
-
"pt-BR",
|
|
102
|
-
"es",
|
|
103
|
-
"es-419",
|
|
104
|
-
"it",
|
|
105
|
-
"ja",
|
|
106
|
-
"ko",
|
|
107
|
-
"no",
|
|
108
|
-
"pl",
|
|
109
|
-
"es-LATAM",
|
|
110
|
-
"sv",
|
|
111
|
-
"ta",
|
|
112
|
-
"taq",
|
|
113
|
-
"uk",
|
|
114
|
-
"tr",
|
|
115
|
-
"id",
|
|
116
|
-
"ru",
|
|
117
|
-
"th",
|
|
118
|
-
"multi"
|
|
119
|
-
]).describe("The language code for recognition").default("en"),
|
|
120
|
-
stt_detect_language: z.boolean().describe("Whether to enable automatic language detection").default(false),
|
|
121
|
-
stt_interim_results: z.boolean().describe("Whether to return interim (non-final) transcription results").default(false),
|
|
122
|
-
stt_punctuate: z.boolean().describe(
|
|
123
|
-
"Whether to add punctuations to the transcription. Turn detector will work better with punctuations"
|
|
124
|
-
).default(true),
|
|
125
|
-
stt_smart_format: z.boolean().describe("Whether to apply smart formatting to numbers, dates, etc.").default(false),
|
|
126
|
-
stt_sample_rate: z.number().int().describe("The sample rate of the audio in Hz").default(8e3),
|
|
127
|
-
stt_no_delay: z.boolean().describe(
|
|
128
|
-
"When smart_format is used, ensures it does not wait for sequence to be complete before returning results"
|
|
129
|
-
).default(true),
|
|
130
|
-
stt_endpointing_ms: z.number().int().describe("Time in milliseconds of silence to consider end of speech. Set to 0 to disable").default(25),
|
|
131
|
-
stt_filler_words: z.boolean().describe("Whether to include filler words (um, uh, etc.) in transcription.").default(true),
|
|
132
|
-
stt_keyterms: z.array(z.string()).describe("Key terms to improve recognition accuracy. Only supported by Nova-3 models").default([]),
|
|
133
|
-
stt_tags: z.array(z.string()).describe("List of tags to add to the requests for usage reporting.").default([]),
|
|
134
|
-
stt_profanity_filter: z.boolean().describe("Whether to filter profanity from the transcription.").default(false),
|
|
135
|
-
stt_eager_eot_threshold: z.union([z.number(), z.null()]).describe(
|
|
136
|
-
"Threshold for eager end-of-turn to enable preemptive generation. Disabled by default. Set to 0.3-0.9 to enable. Only used when stt_api_version is 2"
|
|
137
|
-
).default(null),
|
|
138
|
-
stt_eot_threshold: z.number().describe("Threshold for end-of-turn detection. Only used when stt_api_version is 2").default(0.7),
|
|
139
|
-
stt_eot_timeout_ms: z.number().int().describe(
|
|
140
|
-
"Timeout in milliseconds for end-of-turn detection. Only used when stt_api_version is 2"
|
|
141
|
-
).default(3e3),
|
|
142
|
-
tts_voice_id: z.string().describe("ElevenLabs voice ID (default `bIHbv24MWmeRgasZH58o` used if none set)").default("bIHbv24MWmeRgasZH58o"),
|
|
143
|
-
tts_voice_similarity_boost: z.number().describe("Voice similarity boost [0.0 - 1.0]").default(0.6),
|
|
144
|
-
tts_voice_stability: z.number().describe("Voice stability [0.0 - 1.0]").default(0.95),
|
|
145
|
-
tts_voice_speed: z.number().describe("Voice speed [0.8 - 1.2]").default(1),
|
|
146
|
-
tts_voice_style: z.number().describe("Voice style exaggeration [0.0 - 1.0]").default(0.1),
|
|
147
|
-
tts_voice_use_speaker_boost: z.boolean().describe("Whether to use speaker boost for the voice").default(false),
|
|
148
|
-
tts_model: z.enum([
|
|
149
|
-
"eleven_monolingual_v1",
|
|
150
|
-
"eleven_multilingual_v1",
|
|
151
|
-
"eleven_multilingual_v2",
|
|
152
|
-
"eleven_turbo_v2",
|
|
153
|
-
"eleven_turbo_v2_5",
|
|
154
|
-
"eleven_flash_v2_5",
|
|
155
|
-
"eleven_flash_v2",
|
|
156
|
-
"eleven_v3"
|
|
157
|
-
]).describe("ElevenLabs model to use").default("eleven_turbo_v2"),
|
|
158
|
-
tts_inactivity_timeout: z.number().int().describe("Inactivity timeout in seconds for the websocket connection").default(300),
|
|
159
|
-
tts_enable_ssml_parsing: z.boolean().describe("Enable SSML parsing for input text").default(true),
|
|
160
|
-
tts_streaming_latency: z.number().int().describe(
|
|
161
|
-
"Optimize for streaming latency, 0 to disable, 4 for max latency optimizations (deprecated)"
|
|
162
|
-
).default(3),
|
|
163
|
-
tts_auto_mode: z.boolean().describe(
|
|
164
|
-
"Reduces latency by disabling chunk schedule and buffers. Sentence tokenizer will be used to synthesize one sentence at a time"
|
|
165
|
-
).default(true),
|
|
166
|
-
tts_encoding: z.enum([
|
|
167
|
-
"mp3_22050_32",
|
|
168
|
-
"mp3_24000_48",
|
|
169
|
-
"mp3_44100",
|
|
170
|
-
"mp3_44100_32",
|
|
171
|
-
"mp3_44100_64",
|
|
172
|
-
"mp3_44100_96",
|
|
173
|
-
"mp3_44100_128",
|
|
174
|
-
"mp3_44100_192",
|
|
175
|
-
"opus_48000_32",
|
|
176
|
-
"opus_48000_64",
|
|
177
|
-
"opus_48000_96",
|
|
178
|
-
"opus_48000_128",
|
|
179
|
-
"opus_48000_192",
|
|
180
|
-
"pcm_8000",
|
|
181
|
-
"pcm_16000",
|
|
182
|
-
"pcm_22050",
|
|
183
|
-
"pcm_24000",
|
|
184
|
-
"pcm_32000",
|
|
185
|
-
"pcm_44100",
|
|
186
|
-
"pcm_48000"
|
|
187
|
-
]).describe("Audio encoding format for TTS output").default("mp3_44100_128"),
|
|
188
|
-
tts_chunk_length_schedule: z.array(z.number().int()).describe("Schedule for chunk lengths, ranging 50...500").default([120, 160, 250, 290]),
|
|
189
|
-
tts_language: z.string().describe("Language code for the TTS model").default("en")
|
|
190
|
-
});
|
|
191
|
-
|
|
192
|
-
// src/call-control/voice-agent-config.ts
|
|
193
|
-
var TURN_DETECTION_MODES = /* @__PURE__ */ new Set(["model", "stt", "vad"]);
|
|
194
|
-
var TURN_DETECTOR_MIN_SILENCE_DURATION = 0.25;
|
|
195
|
-
function getTurnDetectionSettingsIssue(settings) {
|
|
196
|
-
if (typeof settings !== "object" || settings === null || Array.isArray(settings)) {
|
|
197
|
-
return {
|
|
198
|
-
message: "Voice agent settings must be an object",
|
|
199
|
-
path: [],
|
|
200
|
-
type: "type"
|
|
201
|
-
};
|
|
202
|
-
}
|
|
203
|
-
const values = settings;
|
|
204
|
-
const mode = values.session_turn_detection;
|
|
205
|
-
if (mode !== void 0 && (typeof mode !== "string" || !TURN_DETECTION_MODES.has(mode))) {
|
|
206
|
-
return {
|
|
207
|
-
message: "Turn detection must use model, STT, or VAD mode",
|
|
208
|
-
path: ["session_turn_detection"],
|
|
209
|
-
type: "type"
|
|
210
|
-
};
|
|
211
|
-
}
|
|
212
|
-
const minSilence = values.vad_min_silence_duration;
|
|
213
|
-
if (minSilence !== void 0 && (typeof minSilence !== "number" || !Number.isFinite(minSilence))) {
|
|
214
|
-
return {
|
|
215
|
-
message: "The minimum VAD silence duration must be a finite number",
|
|
216
|
-
path: ["vad_min_silence_duration"],
|
|
217
|
-
type: "type"
|
|
218
|
-
};
|
|
219
|
-
}
|
|
220
|
-
if (minSilence !== void 0 && minSilence < TURN_DETECTOR_MIN_SILENCE_DURATION && (mode === void 0 || mode === "model")) {
|
|
221
|
-
return {
|
|
222
|
-
message: "Audio turn detection requires at least 0.25 seconds of VAD silence",
|
|
223
|
-
path: ["vad_min_silence_duration"],
|
|
224
|
-
type: "range"
|
|
225
|
-
};
|
|
226
|
-
}
|
|
227
|
-
return void 0;
|
|
228
|
-
}
|
|
229
|
-
var voiceAgentConfigSchema = configSchema.superRefine((settings, context) => {
|
|
230
|
-
const issue = getTurnDetectionSettingsIssue(settings);
|
|
231
|
-
if (issue) context.addIssue({ code: "custom", message: issue.message, path: issue.path });
|
|
232
|
-
});
|
|
233
|
-
function validateVoiceAgentTurnDetectionSettings(settings) {
|
|
234
|
-
const issue = getTurnDetectionSettingsIssue(settings);
|
|
235
|
-
if (!issue) return;
|
|
236
|
-
if (issue.type === "range") throw new RangeError(issue.message);
|
|
237
|
-
throw new TypeError(issue.message);
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
// src/call-control/types.ts
|
|
241
|
-
var MediaEncryption = { DISABLE: 0, ALLOW: 1, REQUIRE: 2 };
|
|
242
|
-
var Transport = { AUTO: 0, UDP: 1, TCP: 2, TLS: 3 };
|
|
243
|
-
var IncludeHeaders = { NO_HEADERS: 0, X_HEADERS: 1, ALL_HEADERS: 2 };
|
|
244
|
-
var CallSignalType = /* @__PURE__ */ ((CallSignalType2) => {
|
|
245
|
-
CallSignalType2["Transfer"] = "transfer";
|
|
246
|
-
CallSignalType2["Reload"] = "reload";
|
|
247
|
-
CallSignalType2["HangUp"] = "hangup";
|
|
248
|
-
CallSignalType2["Freeze"] = "freeze";
|
|
249
|
-
CallSignalType2["Unfreeze"] = "unfreeze";
|
|
250
|
-
CallSignalType2["SendMessage"] = "send-message";
|
|
251
|
-
CallSignalType2["UpdateSettings"] = "update-settings";
|
|
252
|
-
CallSignalType2["Steer"] = "steer";
|
|
253
|
-
return CallSignalType2;
|
|
254
|
-
})(CallSignalType || {});
|
|
255
|
-
var CallDataTopic = /* @__PURE__ */ ((CallDataTopic2) => {
|
|
256
|
-
CallDataTopic2["AgentSignal"] = "agent-signal";
|
|
257
|
-
return CallDataTopic2;
|
|
258
|
-
})(CallDataTopic || {});
|
|
259
|
-
var _defaults = voiceAgentConfigSchema.parse({});
|
|
260
|
-
var _defaultsExcluded = [
|
|
261
|
-
// Produces errors if set to null, complicated dynamic logic of setter
|
|
262
|
-
"vad_deactivation_threshold",
|
|
263
|
-
// Deepgram Flux-only fields, not used anywhere now
|
|
264
|
-
"stt_eager_eot_threshold",
|
|
265
|
-
"stt_eot_timeout_ms",
|
|
266
|
-
"stt_eot_threshold"
|
|
267
|
-
];
|
|
268
|
-
var voiceAgentDefaultConfig = Object.fromEntries(
|
|
269
|
-
Object.entries(_defaults).filter(
|
|
270
|
-
([field]) => !_defaultsExcluded.includes(field)
|
|
271
|
-
)
|
|
272
|
-
);
|
|
273
|
-
|
|
274
|
-
// src/call-control/call-details/noop-storage.ts
|
|
275
|
-
var NoopCallDetailsStorage = class {
|
|
276
|
-
async get(_) {
|
|
277
|
-
return null;
|
|
278
|
-
}
|
|
279
|
-
async list() {
|
|
280
|
-
return [];
|
|
281
|
-
}
|
|
282
|
-
async delete(_) {
|
|
283
|
-
return;
|
|
284
|
-
}
|
|
285
|
-
};
|
|
286
|
-
|
|
287
|
-
// src/call-control/sip.ts
|
|
288
|
-
import {
|
|
289
|
-
RoomAgentDispatch,
|
|
290
|
-
RoomConfiguration,
|
|
291
|
-
SipClient
|
|
292
|
-
} from "livekit-server-sdk";
|
|
293
|
-
|
|
294
|
-
// src/call-control/sip-setup-lock.ts
|
|
295
|
-
import { randomUUID } from "node:crypto";
|
|
296
|
-
import { RoomServiceClient } from "livekit-server-sdk";
|
|
297
|
-
|
|
298
|
-
// src/call-control/utils.ts
|
|
299
|
-
import { createHash } from "node:crypto";
|
|
300
|
-
var CallControlError = class extends Error {
|
|
301
|
-
constructor(message, cause) {
|
|
302
|
-
super(message, { cause });
|
|
303
|
-
this.name = "CallControlError";
|
|
304
|
-
}
|
|
305
|
-
};
|
|
306
|
-
function getLiveKitConnectionOptions(options = {}) {
|
|
307
|
-
const {
|
|
308
|
-
url = process.env.LIVEKIT_URL,
|
|
309
|
-
key = process.env.LIVEKIT_API_KEY,
|
|
310
|
-
secret = process.env.LIVEKIT_API_SECRET
|
|
311
|
-
} = options;
|
|
312
|
-
const finalOptions = { url, key, secret };
|
|
313
|
-
Object.entries(finalOptions).forEach(([key2, value]) => {
|
|
314
|
-
if (!value) throw new CallControlError(`LiveKit ${key2} not set`);
|
|
315
|
-
});
|
|
316
|
-
return finalOptions;
|
|
317
|
-
}
|
|
318
|
-
function getCallIdFromRoomName(roomName) {
|
|
319
|
-
return roomName.split("_").pop() ?? "";
|
|
320
|
-
}
|
|
321
|
-
function toTitleCase(str) {
|
|
322
|
-
return str.toLowerCase().replace(new RegExp("\\b\\p{L}", "gu"), (char) => char.toUpperCase());
|
|
323
|
-
}
|
|
324
|
-
function sortKeys(value) {
|
|
325
|
-
if (Array.isArray(value)) return value.map(sortKeys);
|
|
326
|
-
if (value !== null && typeof value === "object") {
|
|
327
|
-
return Object.fromEntries(
|
|
328
|
-
Object.keys(value).sort().map((k) => [k, sortKeys(value[k])])
|
|
329
|
-
);
|
|
330
|
-
}
|
|
331
|
-
return value;
|
|
332
|
-
}
|
|
333
|
-
function computeObjectHash(value, algo = "sha256") {
|
|
334
|
-
return createHash(algo).update(JSON.stringify(sortKeys(value)) ?? "").digest("hex");
|
|
335
|
-
}
|
|
336
|
-
function anyOf(...items) {
|
|
337
|
-
return [...items].some(Boolean);
|
|
338
|
-
}
|
|
339
|
-
|
|
340
|
-
// src/call-control/sip-setup-lock.ts
|
|
341
|
-
var LOCK_ROOM_NAME = "__sip_setup_lock__";
|
|
342
|
-
var LOCK_ROOM_EMPTY_TIMEOUT_S = 60;
|
|
343
|
-
var LOCK_ACQUIRE_TIMEOUT_MS = 3e4;
|
|
344
|
-
var LOCK_RETRY_INTERVAL_MS = 500;
|
|
345
|
-
var LOCK_REQUEST_TIMEOUT_S = 5;
|
|
346
|
-
function createSipSetupLock(url, key, secret, logger = console) {
|
|
347
|
-
const roomService = new RoomServiceClient(url, key, secret, {
|
|
348
|
-
requestTimeout: LOCK_REQUEST_TIMEOUT_S
|
|
349
|
-
});
|
|
350
|
-
let lockId;
|
|
351
|
-
return {
|
|
352
|
-
async acquire() {
|
|
353
|
-
lockId = randomUUID();
|
|
354
|
-
const startTime = Date.now();
|
|
355
|
-
while (Date.now() - startTime < LOCK_ACQUIRE_TIMEOUT_MS) {
|
|
356
|
-
try {
|
|
357
|
-
const room = await roomService.createRoom({
|
|
358
|
-
name: LOCK_ROOM_NAME,
|
|
359
|
-
emptyTimeout: LOCK_ROOM_EMPTY_TIMEOUT_S,
|
|
360
|
-
agents: [],
|
|
361
|
-
metadata: lockId
|
|
362
|
-
});
|
|
363
|
-
if (room.metadata === lockId) {
|
|
364
|
-
logger.info("SIP setup lock acquired");
|
|
365
|
-
return;
|
|
366
|
-
}
|
|
367
|
-
logger.info("SIP setup lock held by another instance, waiting...", {
|
|
368
|
-
holder: room.metadata
|
|
369
|
-
});
|
|
370
|
-
} catch (err) {
|
|
371
|
-
logger.warn("SIP setup lock acquire attempt failed, retrying...", { err });
|
|
372
|
-
}
|
|
373
|
-
await new Promise((resolve) => setTimeout(resolve, LOCK_RETRY_INTERVAL_MS));
|
|
374
|
-
}
|
|
375
|
-
lockId = void 0;
|
|
376
|
-
throw new CallControlError(
|
|
377
|
-
`Failed to acquire SIP setup lock within ${LOCK_ACQUIRE_TIMEOUT_MS}ms`
|
|
378
|
-
);
|
|
379
|
-
},
|
|
380
|
-
async release() {
|
|
381
|
-
try {
|
|
382
|
-
await roomService.deleteRoom(LOCK_ROOM_NAME);
|
|
383
|
-
logger.info("SIP setup lock released");
|
|
384
|
-
} catch (err) {
|
|
385
|
-
if (err instanceof Error && err.message.includes("not found")) {
|
|
386
|
-
logger.debug("SIP setup lock already released");
|
|
387
|
-
return;
|
|
388
|
-
}
|
|
389
|
-
logger.error("Failed to release SIP setup lock", { err });
|
|
390
|
-
throw err;
|
|
391
|
-
} finally {
|
|
392
|
-
lockId = void 0;
|
|
393
|
-
}
|
|
394
|
-
}
|
|
395
|
-
};
|
|
396
|
-
}
|
|
397
|
-
|
|
398
|
-
// src/call-control/sip.ts
|
|
399
|
-
var DEFAULT_TRUNK_CONFIG = {
|
|
400
|
-
mediaEncryption: MediaEncryption.ALLOW,
|
|
401
|
-
includeHeaders: IncludeHeaders.ALL_HEADERS
|
|
402
|
-
};
|
|
403
|
-
var SipManager = class {
|
|
404
|
-
agentName;
|
|
405
|
-
client;
|
|
406
|
-
lock;
|
|
407
|
-
options;
|
|
408
|
-
trunksConfigHash;
|
|
409
|
-
logger;
|
|
410
|
-
constructor(options, logger = console, debugMode = Boolean(process.env.SIP_DEBUG)) {
|
|
411
|
-
if (debugMode) {
|
|
412
|
-
populateOptionsFromEnv(options);
|
|
413
|
-
}
|
|
414
|
-
const { agentName, livekit = {} } = options;
|
|
415
|
-
this.agentName = agentName;
|
|
416
|
-
this.options = options;
|
|
417
|
-
this.validateOptions();
|
|
418
|
-
this.trunksConfigHash = computeObjectHash(options.trunks);
|
|
419
|
-
const { url, key, secret } = getLiveKitConnectionOptions(livekit);
|
|
420
|
-
this.client = new SipClient(url, key, secret);
|
|
421
|
-
this.logger = logger;
|
|
422
|
-
this.lock = createSipSetupLock(url, key, secret, this.logger);
|
|
423
|
-
}
|
|
424
|
-
get trunksConfig() {
|
|
425
|
-
return this.options.trunks;
|
|
426
|
-
}
|
|
427
|
-
get trunksConfigDefaultMeta() {
|
|
428
|
-
return {
|
|
429
|
-
["agentName" /* AgentName */]: this.agentName,
|
|
430
|
-
["_configHash" /* ConfigHash */]: this.trunksConfigHash
|
|
431
|
-
};
|
|
432
|
-
}
|
|
433
|
-
validateOptions() {
|
|
434
|
-
const { in: inbound, out: outbound, transfer } = this.trunksConfig ?? {};
|
|
435
|
-
if (!anyOf(inbound, outbound, transfer)) {
|
|
436
|
-
throw new SipError("No trunk configured");
|
|
437
|
-
}
|
|
438
|
-
if (inbound && !(inbound.numbers ?? []).filter(Boolean).length) {
|
|
439
|
-
throw new SipError("No phone numbers set for the inbound trunk");
|
|
440
|
-
}
|
|
441
|
-
if (transfer && !transfer.server) {
|
|
442
|
-
throw new SipError("No SIP server set for transfer trunk");
|
|
443
|
-
}
|
|
444
|
-
if (outbound && !outbound.server) {
|
|
445
|
-
throw new SipError("No SIP server set for outbound trunk");
|
|
446
|
-
}
|
|
447
|
-
if (this.options.transferRequired) {
|
|
448
|
-
if (!anyOf(outbound, transfer))
|
|
449
|
-
throw new SipError("No configuration for the transfer trunk");
|
|
450
|
-
}
|
|
451
|
-
}
|
|
452
|
-
async setup(withCleanup = true) {
|
|
453
|
-
const agentName = this.agentName;
|
|
454
|
-
let resources = { agentName };
|
|
455
|
-
let inboundTrunk, transferTrunk, outboundTrunk, dispatchRule, error;
|
|
456
|
-
this.logger.info("SIP resources setup started...", { agentName });
|
|
457
|
-
await this.lock.acquire();
|
|
458
|
-
try {
|
|
459
|
-
const existing = await this.getAllResources();
|
|
460
|
-
if (this.isResourceSetComplete(existing)) {
|
|
461
|
-
const ownedInbound = existing.inboundTrunks.find(this.isOwnResource);
|
|
462
|
-
const ownedOutbound = existing.outboundTrunks.find(
|
|
463
|
-
(trunk) => this.isOwnResource(trunk) && getMetaValue(trunk.metadata, "trunkType" /* Type */) === "outbound"
|
|
464
|
-
);
|
|
465
|
-
const ownedTransfer = existing.outboundTrunks.find(
|
|
466
|
-
(trunk) => this.isOwnResource(trunk) && getMetaValue(trunk.metadata, "trunkType" /* Type */) === "transfer"
|
|
467
|
-
);
|
|
468
|
-
const storedHash = getMetaValue(
|
|
469
|
-
(ownedInbound ?? ownedTransfer ?? ownedOutbound)?.metadata,
|
|
470
|
-
"_configHash" /* ConfigHash */
|
|
471
|
-
);
|
|
472
|
-
if (storedHash === this.trunksConfigHash) {
|
|
473
|
-
this.logger.info("SIP resources unchanged, reusing existing.", {
|
|
474
|
-
agentName,
|
|
475
|
-
["_configHash" /* ConfigHash */]: storedHash
|
|
476
|
-
});
|
|
477
|
-
inboundTrunk = ownedInbound;
|
|
478
|
-
transferTrunk = ownedTransfer;
|
|
479
|
-
outboundTrunk = ownedOutbound;
|
|
480
|
-
dispatchRule = existing.rules.find(this.isOwnResource);
|
|
481
|
-
}
|
|
482
|
-
}
|
|
483
|
-
if (!anyOf(inboundTrunk, transferTrunk, outboundTrunk)) {
|
|
484
|
-
if (withCleanup) {
|
|
485
|
-
await this.cleanup(existing);
|
|
486
|
-
}
|
|
487
|
-
if (this.trunksConfig.in) {
|
|
488
|
-
await this.resolveNumberConflicts(existing);
|
|
489
|
-
inboundTrunk = await this.createInboundTrunk();
|
|
490
|
-
if (inboundTrunk) {
|
|
491
|
-
dispatchRule = await this.createDispatchRule(inboundTrunk.sipTrunkId);
|
|
492
|
-
}
|
|
493
|
-
}
|
|
494
|
-
if (this.trunksConfig.transfer) {
|
|
495
|
-
transferTrunk = await this.createOutboundTrunk("transfer");
|
|
496
|
-
}
|
|
497
|
-
if (this.trunksConfig.out) {
|
|
498
|
-
outboundTrunk = await this.createOutboundTrunk("outbound");
|
|
499
|
-
}
|
|
500
|
-
}
|
|
501
|
-
resources = { ...resources, inboundTrunk, transferTrunk, outboundTrunk, dispatchRule };
|
|
502
|
-
} catch (_error) {
|
|
503
|
-
error = _error;
|
|
504
|
-
} finally {
|
|
505
|
-
await this.lock.release();
|
|
506
|
-
}
|
|
507
|
-
if (error) {
|
|
508
|
-
this.logger.error("SIP resources setup failed!", { error });
|
|
509
|
-
throw new SipError("Resources setup error", error);
|
|
510
|
-
}
|
|
511
|
-
this.logger.info("SIP resources setup completed.", { resources });
|
|
512
|
-
return resources;
|
|
513
|
-
}
|
|
514
|
-
async getTransferTrunkId() {
|
|
515
|
-
return (await this.client.listSipOutboundTrunk()).find(
|
|
516
|
-
(trunk) => this.isOwnResource(trunk) && getMetaValue(trunk.metadata, "trunkType" /* Type */) === "transfer"
|
|
517
|
-
)?.sipTrunkId;
|
|
518
|
-
}
|
|
519
|
-
async createInboundTrunk() {
|
|
520
|
-
const agentName = this.agentName;
|
|
521
|
-
const config = this.trunksConfig.in;
|
|
522
|
-
const metadata = {
|
|
523
|
-
...config.metadata ?? {},
|
|
524
|
-
...this.trunksConfigDefaultMeta
|
|
525
|
-
};
|
|
526
|
-
const options = {
|
|
527
|
-
...DEFAULT_TRUNK_CONFIG,
|
|
528
|
-
...config,
|
|
529
|
-
metadata: JSON.stringify(metadata)
|
|
530
|
-
};
|
|
531
|
-
this.logger.info("Creating inbound trunk...", {
|
|
532
|
-
agentName,
|
|
533
|
-
numbers: config.numbers,
|
|
534
|
-
options
|
|
535
|
-
});
|
|
536
|
-
if (config.allowedAddresses) {
|
|
537
|
-
options.allowedAddresses = config.allowedAddresses;
|
|
538
|
-
}
|
|
539
|
-
const trunk = await this.client.createSipInboundTrunk(agentName, config.numbers, options);
|
|
540
|
-
this.logger.info("Inbound trunk created.", { agentName, ...trunk });
|
|
541
|
-
return trunk;
|
|
542
|
-
}
|
|
543
|
-
async createOutboundTrunk(type = "transfer") {
|
|
544
|
-
const agentName = this.agentName;
|
|
545
|
-
const config = type === "transfer" ? this.trunksConfig.transfer : this.trunksConfig.out;
|
|
546
|
-
const metadata = {
|
|
547
|
-
...config.metadata ?? {},
|
|
548
|
-
...this.trunksConfigDefaultMeta,
|
|
549
|
-
["trunkType" /* Type */]: type
|
|
550
|
-
};
|
|
551
|
-
const { numbers = ["*"], server, transport = Transport.TCP } = config;
|
|
552
|
-
const options = {
|
|
553
|
-
...DEFAULT_TRUNK_CONFIG,
|
|
554
|
-
...config,
|
|
555
|
-
transport,
|
|
556
|
-
metadata: JSON.stringify(metadata)
|
|
557
|
-
};
|
|
558
|
-
this.logger.info(`Creating ${type} trunk...`, { agentName, numbers, server, options });
|
|
559
|
-
const trunk = await this.client.createSipOutboundTrunk(
|
|
560
|
-
`${toTitleCase(type)} trunk for ${agentName}`,
|
|
561
|
-
server,
|
|
562
|
-
numbers,
|
|
563
|
-
options
|
|
564
|
-
);
|
|
565
|
-
this.logger.info(`${toTitleCase(type)} trunk created.`, { agentName, ...trunk });
|
|
566
|
-
return trunk;
|
|
567
|
-
}
|
|
568
|
-
async createDispatchRule(trunkId, type = "individual") {
|
|
569
|
-
const agentName = this.agentName;
|
|
570
|
-
const ruleConfig = {
|
|
571
|
-
type,
|
|
572
|
-
roomPrefix: this.options.roomPrefix
|
|
573
|
-
};
|
|
574
|
-
const attributes = {
|
|
575
|
-
...this.trunksConfig.in?.metadata ?? {},
|
|
576
|
-
...this.trunksConfigDefaultMeta
|
|
577
|
-
};
|
|
578
|
-
const metadata = JSON.stringify(attributes);
|
|
579
|
-
this.logger.info("Creating dispatch rule...", {
|
|
580
|
-
agentName,
|
|
581
|
-
inboundTrunkId: trunkId,
|
|
582
|
-
attributes,
|
|
583
|
-
ruleConfig
|
|
584
|
-
});
|
|
585
|
-
const roomAgentDispatch = new RoomAgentDispatch({
|
|
586
|
-
// IMPORTANT!
|
|
587
|
-
// agentName MUST be empty string for jobs to be dispatched to universal voice agent
|
|
588
|
-
agentName: "",
|
|
589
|
-
metadata
|
|
590
|
-
});
|
|
591
|
-
const options = {
|
|
592
|
-
trunkIds: [trunkId],
|
|
593
|
-
metadata,
|
|
594
|
-
attributes,
|
|
595
|
-
roomConfig: new RoomConfiguration({ agents: [roomAgentDispatch] })
|
|
596
|
-
};
|
|
597
|
-
const rule = await this.client.createSipDispatchRule(ruleConfig, options);
|
|
598
|
-
this.logger.info("Dispatch rule created.", { agentName, ...rule });
|
|
599
|
-
return rule;
|
|
600
|
-
}
|
|
601
|
-
async resolveNumberConflicts(preloaded) {
|
|
602
|
-
const numbers = this.trunksConfig.in.numbers;
|
|
603
|
-
const all = preloaded ?? await this.getAllResources();
|
|
604
|
-
const conflicting = all.inboundTrunks.filter(
|
|
605
|
-
(trunk) => !this.isOwnResource(trunk) && trunk.numbers?.some((n) => numbers.includes(n))
|
|
606
|
-
);
|
|
607
|
-
if (conflicting.length === 0) return;
|
|
608
|
-
const conflictingTrunkIds = new Set(conflicting.map(({ sipTrunkId: id }) => id));
|
|
609
|
-
const orphanedRules = all.rules.filter(
|
|
610
|
-
(rule) => rule.trunkIds?.some((id) => conflictingTrunkIds.has(id))
|
|
611
|
-
);
|
|
612
|
-
for (const rule of orphanedRules) {
|
|
613
|
-
this.logger.warn("Deleting dispatch rule associated with conflicting trunk", {
|
|
614
|
-
ruleId: rule.sipDispatchRuleId,
|
|
615
|
-
owner: getMetaValue(rule.metadata, "agentName" /* AgentName */)
|
|
616
|
-
});
|
|
617
|
-
try {
|
|
618
|
-
await this.deleteDispatchRule(rule.sipDispatchRuleId);
|
|
619
|
-
} catch (err) {
|
|
620
|
-
this.logger.error("Failed to delete conflicting dispatch rule", {
|
|
621
|
-
ruleId: rule.sipDispatchRuleId,
|
|
622
|
-
err
|
|
623
|
-
});
|
|
624
|
-
throw new SipError("Cannot delete dispatch rule", err);
|
|
625
|
-
}
|
|
626
|
-
}
|
|
627
|
-
for (const trunk of conflicting) {
|
|
628
|
-
this.logger.warn("Deleting inbound trunk with conflicting phone numbers", {
|
|
629
|
-
trunkId: trunk.sipTrunkId,
|
|
630
|
-
owner: getMetaValue(trunk.metadata, "agentName" /* AgentName */),
|
|
631
|
-
conflictingNumbers: trunk.numbers?.filter((n) => numbers.includes(n))
|
|
632
|
-
});
|
|
633
|
-
try {
|
|
634
|
-
await this.deleteTrunk(trunk.sipTrunkId);
|
|
635
|
-
} catch (err) {
|
|
636
|
-
this.logger.error("Failed to delete conflicting inbound trunk", {
|
|
637
|
-
trunkId: trunk.sipTrunkId,
|
|
638
|
-
err
|
|
639
|
-
});
|
|
640
|
-
throw new SipError("Cannot delete trunk", err);
|
|
641
|
-
}
|
|
642
|
-
}
|
|
643
|
-
}
|
|
644
|
-
isOwnResource = (resource) => {
|
|
645
|
-
return getMetaValue(resource.metadata, "agentName" /* AgentName */) === this.agentName;
|
|
646
|
-
};
|
|
647
|
-
isResourceSetComplete(resources) {
|
|
648
|
-
const ownedInbound = resources.inboundTrunks.filter(this.isOwnResource);
|
|
649
|
-
const ownedOutbound = resources.outboundTrunks.filter(this.isOwnResource);
|
|
650
|
-
const ownedRules = resources.rules.filter(this.isOwnResource);
|
|
651
|
-
if (this.trunksConfig.in && (ownedInbound.length === 0 || ownedRules.length === 0)) {
|
|
652
|
-
return false;
|
|
653
|
-
}
|
|
654
|
-
const neededOutbound = (this.trunksConfig.transfer ? 1 : 0) + (this.trunksConfig.out ? 1 : 0);
|
|
655
|
-
if (neededOutbound > 0 && ownedOutbound.length < neededOutbound) return false;
|
|
656
|
-
return true;
|
|
657
|
-
}
|
|
658
|
-
async cleanup(preloaded) {
|
|
659
|
-
await this.deleteAllResources(5, 500, preloaded);
|
|
660
|
-
}
|
|
661
|
-
async deleteAllResources(maxAttempts = 5, retryInterval = 500, preloaded) {
|
|
662
|
-
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
663
|
-
const all2 = attempt === 1 && preloaded ? preloaded : await this.getAllResources();
|
|
664
|
-
const rules = all2.rules.filter(this.isOwnResource);
|
|
665
|
-
const inboundTrunks = all2.inboundTrunks.filter(this.isOwnResource);
|
|
666
|
-
const outboundTrunks = all2.outboundTrunks.filter(this.isOwnResource);
|
|
667
|
-
const trunkIds = /* @__PURE__ */ new Set([
|
|
668
|
-
...inboundTrunks.map((t) => t.sipTrunkId),
|
|
669
|
-
...outboundTrunks.map((t) => t.sipTrunkId)
|
|
670
|
-
]);
|
|
671
|
-
this.logger.info("Cleanup: resources found", {
|
|
672
|
-
attempt,
|
|
673
|
-
maxAttempts,
|
|
674
|
-
dispatchRules: rules.length,
|
|
675
|
-
inboundTrunks: inboundTrunks.length,
|
|
676
|
-
outboundTrunks: outboundTrunks.length,
|
|
677
|
-
uniqueTrunks: trunkIds.size
|
|
678
|
-
});
|
|
679
|
-
if (rules.length === 0 && trunkIds.size === 0) {
|
|
680
|
-
this.logger.info("Cleanup: nothing to delete");
|
|
681
|
-
return;
|
|
682
|
-
}
|
|
683
|
-
for (const rule of rules) {
|
|
684
|
-
this.logger.info("Cleanup: deleting dispatch rule", { rule });
|
|
685
|
-
try {
|
|
686
|
-
await this.deleteDispatchRule(rule.sipDispatchRuleId);
|
|
687
|
-
} catch (err) {
|
|
688
|
-
this.logger.error("Cleanup: dispatch rule deletion failed (will retry)", {
|
|
689
|
-
ruleId: rule.sipDispatchRuleId,
|
|
690
|
-
err
|
|
691
|
-
});
|
|
692
|
-
}
|
|
693
|
-
}
|
|
694
|
-
for (const trunk of inboundTrunks) {
|
|
695
|
-
this.logger.info("Cleanup: deleting inbound trunk", { trunk });
|
|
696
|
-
try {
|
|
697
|
-
await this.deleteTrunk(trunk.sipTrunkId);
|
|
698
|
-
} catch (err) {
|
|
699
|
-
this.logger.error("Cleanup: inbound trunk deletion failed (will retry)", {
|
|
700
|
-
trunkId: trunk.sipTrunkId,
|
|
701
|
-
err
|
|
702
|
-
});
|
|
703
|
-
}
|
|
704
|
-
}
|
|
705
|
-
for (const trunk of outboundTrunks) {
|
|
706
|
-
this.logger.info("Cleanup: deleting outbound trunk", { trunk });
|
|
707
|
-
try {
|
|
708
|
-
await this.deleteTrunk(trunk.sipTrunkId);
|
|
709
|
-
} catch (err) {
|
|
710
|
-
this.logger.error("Cleanup: outbound trunk deletion failed (will retry)", {
|
|
711
|
-
trunkId: trunk.sipTrunkId,
|
|
712
|
-
err
|
|
713
|
-
});
|
|
714
|
-
}
|
|
715
|
-
}
|
|
716
|
-
await new Promise((resolve) => setTimeout(resolve, retryInterval));
|
|
717
|
-
}
|
|
718
|
-
const all = await this.getAllResources();
|
|
719
|
-
const remainingRules = all.rules.filter(this.isOwnResource);
|
|
720
|
-
const remainingInbound = all.inboundTrunks.filter(this.isOwnResource);
|
|
721
|
-
const remainingOutbound = all.outboundTrunks.filter(this.isOwnResource);
|
|
722
|
-
const remainingTrunkIds = /* @__PURE__ */ new Set([
|
|
723
|
-
...remainingInbound.map(({ sipTrunkId }) => sipTrunkId),
|
|
724
|
-
...remainingOutbound.map(({ sipTrunkId }) => sipTrunkId)
|
|
725
|
-
]);
|
|
726
|
-
this.logger.error("Cleanup: resources still remain after retries", {
|
|
727
|
-
dispatchRules: remainingRules.length,
|
|
728
|
-
inboundTrunks: remainingInbound.length,
|
|
729
|
-
outboundTrunks: remainingOutbound.length,
|
|
730
|
-
uniqueTrunks: remainingTrunkIds.size
|
|
731
|
-
});
|
|
732
|
-
throw new SipError(
|
|
733
|
-
`Failed to delete all SIP trunks/dispatch rules after ${maxAttempts} attempts`
|
|
734
|
-
);
|
|
735
|
-
}
|
|
736
|
-
async getAllResources() {
|
|
737
|
-
const [rules, inboundTrunks, outboundTrunks] = await Promise.all([
|
|
738
|
-
this.client.listSipDispatchRule(),
|
|
739
|
-
this.client.listSipInboundTrunk(),
|
|
740
|
-
this.client.listSipOutboundTrunk()
|
|
741
|
-
]);
|
|
742
|
-
return { rules, inboundTrunks, outboundTrunks };
|
|
743
|
-
}
|
|
744
|
-
async deleteTrunk(trunkId) {
|
|
745
|
-
try {
|
|
746
|
-
await this.client.deleteSipTrunk(trunkId);
|
|
747
|
-
} catch (err) {
|
|
748
|
-
if (err instanceof Error && err.message.includes("not found")) {
|
|
749
|
-
this.logger.info("Trunk was deleted previously", { trunkId });
|
|
750
|
-
return;
|
|
751
|
-
}
|
|
752
|
-
this.logger.error("Failed to delete trunk", { trunkId, err });
|
|
753
|
-
throw new SipError("Failed to delete trunk", err);
|
|
754
|
-
}
|
|
755
|
-
this.logger.info("Trunk deleted", { trunkId });
|
|
756
|
-
}
|
|
757
|
-
async deleteDispatchRule(ruleId) {
|
|
758
|
-
try {
|
|
759
|
-
await this.client.deleteSipDispatchRule(ruleId);
|
|
760
|
-
} catch (err) {
|
|
761
|
-
if (err instanceof Error && err.message.includes("not found")) {
|
|
762
|
-
this.logger.info("Dispatch rule was deleted previously", { ruleId });
|
|
763
|
-
return;
|
|
764
|
-
}
|
|
765
|
-
this.logger.error("Failed to delete dispatch rule", { ruleId, err });
|
|
766
|
-
throw new SipError("Failed to delete dispatch rule", err);
|
|
767
|
-
}
|
|
768
|
-
this.logger.info("Dispatch rule deleted", { ruleId });
|
|
769
|
-
}
|
|
770
|
-
};
|
|
771
|
-
function getMetaValue(metadata, key) {
|
|
772
|
-
if (!metadata) {
|
|
773
|
-
return void 0;
|
|
774
|
-
}
|
|
775
|
-
try {
|
|
776
|
-
const meta = JSON.parse(metadata);
|
|
777
|
-
return meta[key];
|
|
778
|
-
} catch {
|
|
779
|
-
return void 0;
|
|
780
|
-
}
|
|
781
|
-
}
|
|
782
|
-
var SipError = class extends CallControlError {
|
|
783
|
-
constructor(message, cause) {
|
|
784
|
-
super(message, cause);
|
|
785
|
-
this.name = "SipError";
|
|
786
|
-
}
|
|
787
|
-
};
|
|
788
|
-
function populateOptionsFromEnv(options = {}, parse = JSON.parse) {
|
|
789
|
-
const {
|
|
790
|
-
SIP_ROOM_PREFIX: roomPrefix,
|
|
791
|
-
SIP_INBOUND_NUMBERS: inboundNumbers,
|
|
792
|
-
SIP_INBOUND_ALLOWED_NUMBERS: inboundAllowedNumbers,
|
|
793
|
-
SIP_INBOUND_ALLOWED_ADDRESSES: inboundAllowedAddresses,
|
|
794
|
-
SIP_INBOUND_AUTH_USERNAME: inboundAuthUsername,
|
|
795
|
-
SIP_INBOUND_AUTH_PASSWORD: inboundAuthPassword,
|
|
796
|
-
SIP_INBOUND_METADATA: inboundMetadata,
|
|
797
|
-
SIP_INBOUND_MEDIA_ENCRYPTION: inboundMediaEncryption,
|
|
798
|
-
SIP_INBOUND_HEADERS: inboundHeaders,
|
|
799
|
-
SIP_INBOUND_HEADERS_TO_ATTRS: inboundHeadersToAttrs,
|
|
800
|
-
SIP_INBOUND_ATTRS_TO_HEADERS: inboundAttrsToHeaders
|
|
801
|
-
} = process.env;
|
|
802
|
-
if (roomPrefix && !options.roomPrefix) {
|
|
803
|
-
options.roomPrefix = roomPrefix;
|
|
804
|
-
}
|
|
805
|
-
const inbound = options.trunks?.in ?? {};
|
|
806
|
-
if (inboundNumbers) inbound.numbers = parse(inboundNumbers);
|
|
807
|
-
if (inboundAllowedNumbers) inbound.allowedNumbers = parse(inboundAllowedNumbers);
|
|
808
|
-
if (inboundAllowedAddresses)
|
|
809
|
-
inbound.allowedAddresses = parse(inboundAllowedAddresses);
|
|
810
|
-
if (inboundAuthUsername) inbound.authUsername = inboundAuthUsername;
|
|
811
|
-
if (inboundAuthPassword) inbound.authPassword = inboundAuthPassword;
|
|
812
|
-
if (inboundMetadata) inbound.metadata = parse(inboundMetadata);
|
|
813
|
-
if (inboundMediaEncryption)
|
|
814
|
-
inbound.mediaEncryption = Number(inboundMediaEncryption);
|
|
815
|
-
if (inboundHeaders) inbound.headers = parse(inboundHeaders);
|
|
816
|
-
if (inboundHeadersToAttrs)
|
|
817
|
-
inbound.headersToAttributes = parse(inboundHeadersToAttrs);
|
|
818
|
-
if (inboundAttrsToHeaders)
|
|
819
|
-
inbound.attributesToHeaders = parse(inboundAttrsToHeaders);
|
|
820
|
-
if (Object.keys(inbound).length) {
|
|
821
|
-
options.trunks = { ...options.trunks ?? {}, in: inbound };
|
|
822
|
-
}
|
|
823
|
-
return options;
|
|
824
|
-
}
|
|
825
|
-
|
|
826
|
-
// src/call-control/call-control.ts
|
|
827
|
-
import { DataPacket_Kind, RoomServiceClient as RoomServiceClient2 } from "livekit-server-sdk";
|
|
828
|
-
var DEFAULT_ROOM_PREFIX = "call";
|
|
829
|
-
var STALE_FREEZE_MS = 30 * 60 * 1e3;
|
|
830
|
-
var CallControl = class {
|
|
831
|
-
roomService;
|
|
832
|
-
livekit;
|
|
833
|
-
/** One SIP manager per agent that called `setUpSip`. */
|
|
834
|
-
sips = /* @__PURE__ */ new Map();
|
|
835
|
-
storage;
|
|
836
|
-
conversationalTracer;
|
|
837
|
-
eventTracer;
|
|
838
|
-
freezeStarts = /* @__PURE__ */ new Map();
|
|
839
|
-
logger;
|
|
840
|
-
constructor({ livekit = {}, storage, conversationalTracer, eventTracer }, logger = console) {
|
|
841
|
-
const { url, key, secret } = getLiveKitConnectionOptions(livekit);
|
|
842
|
-
this.roomService = new RoomServiceClient2(url, key, secret);
|
|
843
|
-
this.livekit = livekit;
|
|
844
|
-
this.storage = storage ?? new NoopCallDetailsStorage();
|
|
845
|
-
this.conversationalTracer = conversationalTracer;
|
|
846
|
-
this.eventTracer = eventTracer;
|
|
847
|
-
this.logger = logger;
|
|
848
|
-
}
|
|
849
|
-
async trace(eventName, callId, content) {
|
|
850
|
-
if (!this.conversationalTracer) return;
|
|
851
|
-
try {
|
|
852
|
-
this.conversationalTracer.addConversationalTrace({
|
|
853
|
-
conversationId: callId,
|
|
854
|
-
eventName,
|
|
855
|
-
role: "agent",
|
|
856
|
-
medium: "phone",
|
|
857
|
-
content,
|
|
858
|
-
createdAt: Date.now()
|
|
859
|
-
});
|
|
860
|
-
await this.conversationalTracer.flush();
|
|
861
|
-
} catch (err) {
|
|
862
|
-
this.logger.error("Failed to write conversational trace", { err });
|
|
863
|
-
}
|
|
864
|
-
}
|
|
865
|
-
/**
|
|
866
|
-
* Safe on every signal that releases a freeze: a no-op when the call is not frozen, so an
|
|
867
|
-
* unfreeze straight after a reload counts once.
|
|
868
|
-
*/
|
|
869
|
-
endFreeze(callId, endedBy) {
|
|
870
|
-
const startedAt = this.freezeStarts.get(callId);
|
|
871
|
-
if (startedAt === void 0) return;
|
|
872
|
-
this.freezeStarts.delete(callId);
|
|
873
|
-
this.eventTracer?.emit({
|
|
874
|
-
event: "workflow.freeze.outlier",
|
|
875
|
-
attributes: {
|
|
876
|
-
conversationId: callId,
|
|
877
|
-
durationMs: Date.now() - startedAt,
|
|
878
|
-
endedBy
|
|
879
|
-
}
|
|
880
|
-
});
|
|
881
|
-
}
|
|
882
|
-
dropStaleFreezes() {
|
|
883
|
-
const oldest = Date.now() - STALE_FREEZE_MS;
|
|
884
|
-
for (const [callId, startedAt] of this.freezeStarts) {
|
|
885
|
-
if (startedAt < oldest) this.freezeStarts.delete(callId);
|
|
886
|
-
}
|
|
887
|
-
}
|
|
888
|
-
async sendSignalToRoom(room, signal, packetType = DataPacket_Kind.RELIABLE, topic = "agent-signal" /* AgentSignal */) {
|
|
889
|
-
const data = Buffer.from(JSON.stringify(signal));
|
|
890
|
-
await this.roomService.sendData(room.name, data, packetType, { topic });
|
|
891
|
-
}
|
|
892
|
-
async setVoiceSettings(callId, settings) {
|
|
893
|
-
validateVoiceAgentTurnDetectionSettings(settings);
|
|
894
|
-
await this.sendSignalToRoom(await this.getRoomByCallId(callId), {
|
|
895
|
-
signal: "update-settings" /* UpdateSettings */,
|
|
896
|
-
payload: settings
|
|
897
|
-
});
|
|
898
|
-
this.logger.info("Settings update request sent", { settings });
|
|
899
|
-
}
|
|
900
|
-
/**
|
|
901
|
-
* Build the SIP resources for one agent. One connector serves every agent of the process, so
|
|
902
|
-
* each agent brings its own trunk configuration, usually from `onServiceStartup`.
|
|
903
|
-
*/
|
|
904
|
-
async setUpSip(agentName, sip) {
|
|
905
|
-
const options = {
|
|
906
|
-
...sip,
|
|
907
|
-
roomPrefix: sip.roomPrefix ?? DEFAULT_ROOM_PREFIX,
|
|
908
|
-
livekit: this.livekit,
|
|
909
|
-
agentName
|
|
910
|
-
};
|
|
911
|
-
const sipManager = new SipManager(options, this.logger);
|
|
912
|
-
await this.waitForHealth();
|
|
913
|
-
await sipManager.setup();
|
|
914
|
-
this.sips.set(agentName, sipManager);
|
|
915
|
-
}
|
|
916
|
-
async freeze(callId, muteBackgroundAudio = true) {
|
|
917
|
-
await this.sendSignalToRoom(await this.getRoomByCallId(callId), {
|
|
918
|
-
signal: "freeze" /* Freeze */,
|
|
919
|
-
payload: { mute_background_audio: muteBackgroundAudio }
|
|
920
|
-
});
|
|
921
|
-
this.dropStaleFreezes();
|
|
922
|
-
if (!this.freezeStarts.has(callId)) {
|
|
923
|
-
this.freezeStarts.set(callId, Date.now());
|
|
924
|
-
}
|
|
925
|
-
}
|
|
926
|
-
async unfreeze(callId) {
|
|
927
|
-
await this.sendSignalToRoom(await this.getRoomByCallId(callId), {
|
|
928
|
-
signal: "unfreeze" /* Unfreeze */
|
|
929
|
-
});
|
|
930
|
-
this.endFreeze(callId, "unfreeze");
|
|
931
|
-
}
|
|
932
|
-
async steer(callId, payload) {
|
|
933
|
-
await this.sendSignalToRoom(await this.getRoomByCallId(callId), {
|
|
934
|
-
signal: "steer" /* Steer */,
|
|
935
|
-
payload
|
|
936
|
-
});
|
|
937
|
-
if (payload.respond) {
|
|
938
|
-
this.endFreeze(callId, "steer");
|
|
939
|
-
}
|
|
940
|
-
}
|
|
941
|
-
async addMessage(callId, message) {
|
|
942
|
-
await this.sendSignalToRoom(await this.getRoomByCallId(callId), {
|
|
943
|
-
signal: "send-message" /* SendMessage */,
|
|
944
|
-
payload: { content: message.text, role: message.sender }
|
|
945
|
-
});
|
|
946
|
-
}
|
|
947
|
-
async reload(callId) {
|
|
948
|
-
await this.sendSignalToRoom(await this.getRoomByCallId(callId), {
|
|
949
|
-
signal: "reload" /* Reload */
|
|
950
|
-
});
|
|
951
|
-
this.endFreeze(callId, "reload");
|
|
952
|
-
}
|
|
953
|
-
async transfer(agentName, destination, callId, headers, reason = "escalation", disclaimer, waitBefore = 500) {
|
|
954
|
-
await this.trace("transfer-requested", callId, destination);
|
|
955
|
-
this.eventTracer?.emit({
|
|
956
|
-
event: "agent.escalation.requested",
|
|
957
|
-
attributes: {
|
|
958
|
-
conversationId: callId,
|
|
959
|
-
agentId: agentName,
|
|
960
|
-
escalationReason: reason,
|
|
961
|
-
channel: "phone"
|
|
962
|
-
}
|
|
963
|
-
});
|
|
964
|
-
if (waitBefore > 0) {
|
|
965
|
-
await new Promise((resolve) => setTimeout(resolve, waitBefore));
|
|
966
|
-
}
|
|
967
|
-
const room = await this.getRoomByCallId(callId);
|
|
968
|
-
const sipTrunkId = await this.sips.get(agentName)?.getTransferTrunkId();
|
|
969
|
-
if (!sipTrunkId) {
|
|
970
|
-
this.logger.warn(
|
|
971
|
-
"Transfer requested without SIP trunk configured: proceeding with empty `sipTrunkId`",
|
|
972
|
-
{ agentName, callId, destination, reason }
|
|
973
|
-
);
|
|
974
|
-
}
|
|
975
|
-
const request = {
|
|
976
|
-
to: destination,
|
|
977
|
-
...sipTrunkId ? { sipTrunkId } : {},
|
|
978
|
-
...headers ? { headers } : {},
|
|
979
|
-
...disclaimer ? { disclaimer } : {},
|
|
980
|
-
reason,
|
|
981
|
-
playDialtone: true
|
|
982
|
-
};
|
|
983
|
-
this.logger.info("Transfer requested", { request });
|
|
984
|
-
await this.sendSignalToRoom(room, { signal: "transfer" /* Transfer */, payload: request });
|
|
985
|
-
this.endFreeze(callId, "transfer");
|
|
986
|
-
}
|
|
987
|
-
async hangup(callId, waitBefore = 500) {
|
|
988
|
-
await this.trace("hangup-requested", callId, "hangup");
|
|
989
|
-
if (waitBefore > 0) {
|
|
990
|
-
await new Promise((resolve) => setTimeout(resolve, waitBefore));
|
|
991
|
-
}
|
|
992
|
-
await this.sendSignalToRoom(await this.getRoomByCallId(callId), {
|
|
993
|
-
signal: "hangup" /* HangUp */
|
|
994
|
-
});
|
|
995
|
-
this.endFreeze(callId, "hangup");
|
|
996
|
-
}
|
|
997
|
-
async getCallDetails(callId) {
|
|
998
|
-
return await this.storage.get(callId);
|
|
999
|
-
}
|
|
1000
|
-
async healthCheck() {
|
|
1001
|
-
try {
|
|
1002
|
-
await this.roomService.listRooms();
|
|
1003
|
-
return true;
|
|
1004
|
-
} catch (err) {
|
|
1005
|
-
console.error("LiveKit health-check error", { err });
|
|
1006
|
-
return false;
|
|
1007
|
-
}
|
|
1008
|
-
}
|
|
1009
|
-
async waitForHealth(retries = 5, baseDelayMs = 1e3) {
|
|
1010
|
-
let isHealthy = false;
|
|
1011
|
-
for (let attempt = 0; attempt < retries; attempt++) {
|
|
1012
|
-
this.logger.debug("Checking LiveKit connection...", { attempt: attempt + 1, retries });
|
|
1013
|
-
isHealthy = await this.healthCheck();
|
|
1014
|
-
if (isHealthy) {
|
|
1015
|
-
break;
|
|
1016
|
-
}
|
|
1017
|
-
if (attempt === retries - 1) {
|
|
1018
|
-
throw new CallControlError(`Failed to connect to LiveKit after ${retries} attempts`);
|
|
1019
|
-
}
|
|
1020
|
-
const delayMs = baseDelayMs * Math.pow(2, attempt);
|
|
1021
|
-
this.logger.error("Failed to connect to LiveKit, retrying...", { delayMs });
|
|
1022
|
-
await new Promise((resolve) => setTimeout(resolve, delayMs));
|
|
1023
|
-
}
|
|
1024
|
-
return isHealthy;
|
|
1025
|
-
}
|
|
1026
|
-
async getRoomByCallId(callId) {
|
|
1027
|
-
const roomsList = await this.roomService.listRooms();
|
|
1028
|
-
const room = roomsList.find(({ name }) => getCallIdFromRoomName(name) === callId);
|
|
1029
|
-
if (!room) {
|
|
1030
|
-
const err = new CallControlError(`Room not found for call [${callId}]`);
|
|
1031
|
-
this.logger.error("Room not found", { callId, err });
|
|
1032
|
-
throw err;
|
|
1033
|
-
}
|
|
1034
|
-
return room;
|
|
1035
|
-
}
|
|
1036
|
-
};
|
|
1037
|
-
export {
|
|
1038
|
-
CallControl,
|
|
1039
|
-
CallControlError,
|
|
1040
|
-
CallDataTopic,
|
|
1041
|
-
CallSignalType,
|
|
1042
|
-
DEFAULT_ROOM_PREFIX,
|
|
1043
|
-
IncludeHeaders,
|
|
1044
|
-
MediaEncryption,
|
|
1045
|
-
NoopCallDetailsStorage,
|
|
1046
|
-
Room,
|
|
1047
|
-
SipDispatchRule,
|
|
1048
|
-
SipError,
|
|
1049
|
-
SipInboundTrunk,
|
|
1050
|
-
SipManager,
|
|
1051
|
-
SipOutboundTrunk,
|
|
1052
|
-
Transport,
|
|
1053
|
-
CallControl as default,
|
|
1054
|
-
validateVoiceAgentTurnDetectionSettings,
|
|
1055
|
-
voiceAgentConfigSchema,
|
|
1056
|
-
voiceAgentDefaultConfig
|
|
1057
|
-
};
|