@convai/web-sdk 1.8.0-beta.2 → 1.8.0-beta.3

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.
@@ -1 +1 @@
1
- {"version":3,"file":"MessageHandler.js","sourceRoot":"","sources":["../../src/core/MessageHandler.ts"],"names":[],"mappings":"AAAA,OAAO,EAAQ,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAEjD,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EACL,eAAe,GAEhB,MAAM,mBAAmB,CAAC;AAS3B;;;GAGG;AACH,MAAM,OAAO,cAAe,SAAQ,YAAY;IAwB9C,YAAY,IAAW;QACrB,KAAK,EAAE,CAAC;QAxBF,SAAI,GAAgB,IAAI,CAAC;QACzB,iBAAY,GAAkB,EAAE,CAAC;QACjC,sBAAiB,GAAW,EAAE,CAAC;QAC/B,oBAAe,GAAY,IAAI,CAAC;QAChC,oBAAe,GAAY,KAAK,CAAC;QACjC,eAAU,GAAY,KAAK,CAAC;QAC5B,gBAAW,GAAY,KAAK,CAAC;QAC7B,6BAAwB,GAAW,CAAC,CAAC;QAErC,oBAAe,GAA+C,IAAI,CAAC;QAC3E,yEAAyE;QACzE,mEAAmE;QACnE,wEAAwE;QAChE,0BAAqB,GAAG,IAAI,GAAG,EAAmB,CAAC;QAYzD,IAAI,CAAC,wBAAwB,GAAG,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACnE,IAAI,CAAC,eAAe,GAAG,IAAI,eAAe,EAAE,CAAC;QAC7C,IAAI,IAAI,EAAE,CAAC;YACT,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QACrB,CAAC;IACH,CAAC;IAED;;OAEG;IACH,kBAAkB;QAChB,OAAO,IAAI,CAAC,eAAe,CAAC;IAC9B,CAAC;IAED;;OAEG;IACH,qBAAqB,CAAC,OAAgB;QACpC,IAAI,CAAC,eAAe,GAAG,OAAO,CAAC;IACjC,CAAC;IAED;;OAEG;IACH,eAAe;QACb,OAAO,IAAI,CAAC,YAAY,CAAC;IAC3B,CAAC;IAED;;OAEG;IACH,oBAAoB;QAClB,OAAO,IAAI,CAAC,iBAAiB,CAAC;IAChC,CAAC;IAED;;OAEG;IACH,kBAAkB;QAChB,OAAO,IAAI,CAAC,eAAe,CAAC;IAC9B,CAAC;IAED;;OAEG;IACH,aAAa;QACX,OAAO,IAAI,CAAC,UAAU,CAAC;IACzB,CAAC;IAED;;OAEG;IACH,UAAU;QACR,OAAO,IAAI,CAAC,eAAe,CAAC;IAC9B,CAAC;IAED;;;OAGG;IACH,cAAc;QACZ,OAAO,IAAI,CAAC,WAAW,CAAC;IAC1B,CAAC;IAED;;;;OAIG;IACH,wBAAwB;QACtB,MAAM,WAAW,GAAG,IAAI,CAAC,UAAU,CAAC;QACpC,IAAI,CAAC,UAAU,GAAG,KAAK,CAAC;QACxB,IAAI,CAAC,eAAe,CAAC,SAAS,EAAE,CAAC;QACjC,IAAI,WAAW,EAAE,CAAC;YAChB,IAAI,CAAC,IAAI,CAAC,gBAAgB,EAAE,KAAK,CAAC,CAAC;QACrC,CAAC;IACH,CAAC;IAED;;OAEG;IACH,OAAO,CAAC,IAAU;QAChB,mCAAmC;QACnC,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;YACd,IAAI,CAAC,gBAAgB,EAAE,CAAC;QAC1B,CAAC;QAED,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,cAAc,EAAE,CAAC;IACxB,CAAC;IAED;;OAEG;IACK,cAAc;QACpB,IAAI,CAAC,IAAI,CAAC,IAAI;YAAE,OAAO;QAEvB,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,SAAS,CAAC,YAAY,EAAE,IAAI,CAAC,wBAAwB,CAAC,CAAC;IACtE,CAAC;IAED;;OAEG;IACK,gBAAgB;QACtB,IAAI,CAAC,IAAI,CAAC,IAAI;YAAE,OAAO;QAEvB,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,YAAY,EAAE,IAAI,CAAC,wBAAwB,CAAC,CAAC;IACvE,CAAC;IAED;;OAEG;IACK,kBAAkB,CACxB,OAAmB,EACnB,YAAqB,EACrB,aAAsC,SAAS;QAE/C,IAAI,aAAa,GAAG,EAAE,CAAC;QACvB,IAAI,MAAM,GAAG,KAAK,CAAC;QAEnB,IAAI,CAAC;YACH,yBAAyB;YACzB,MAAM,OAAO,GAAG,IAAI,WAAW,EAAE,CAAC;YAClC,aAAa,GAAG,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;YAExC,aAAa;YACb,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC;YAC9C,MAAM,GAAG,IAAI,CAAC;YAEd,mDAAmD;YACnD,MAAM,SAAS,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;YAC3C,MAAM,SAAS,GAAG,GAAG,WAAW,CAAC,IAAI,IAAI,IAAI,CAAC,GAAG,EAAE,IAAI,IAAI,CAAC,MAAM,EAAE,EAAE,CAAC;YAEvE,iCAAiC;YACjC,QAAQ,WAAW,CAAC,IAAI,EAAE,CAAC;gBACzB,iEAAiE;gBACjE,KAAK,mBAAmB,CAAC;gBACzB,KAAK,eAAe,CAAC;gBACrB,KAAK,YAAY,CAAC;gBAClB,KAAK,YAAY,CAAC;gBAClB,KAAK,cAAc,CAAC;gBACpB,KAAK,cAAc,CAAC;gBACpB,KAAK,YAAY,CAAC;gBAClB,KAAK,SAAS;oBACZ,0DAA0D;oBAC1D,MAAM;gBAER,sDAAsD;gBACtD,KAAK,WAAW;oBACd,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;oBACtB,MAAM;gBAER,6CAA6C;gBAC7C,KAAK,iBAAiB;oBACpB,IAAI,CAAC,eAAe,GAAG,IAAI,CAAC;oBAC5B,IAAI,CAAC,IAAI,CAAC,qBAAqB,EAAE,IAAI,CAAC,CAAC;oBACvC,IAAI,CAAC,qBAAqB,CAAC,KAAK,EAAE,CAAC;oBAEnC,wCAAwC;oBACxC,MAAM,gBAAgB,GAAgB;wBACpC,EAAE,EAAE,SAAS;wBACb,IAAI,EAAE,cAAc;wBACpB,OAAO,EAAE,EAAE;wBACX,SAAS,EAAE,SAAS;wBACpB,WAAW,EAAE,IAAI;qBAClB,CAAC;oBACF,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;oBACzC,IAAI,CAAC,IAAI,CAAC,gBAAgB,EAAE,IAAI,CAAC,YAAY,CAAC,CAAC;oBAC/C,MAAM;gBAER,uFAAuF;gBACvF,qEAAqE;gBACrE,kEAAkE;gBAClE,yDAAyD;gBACzD,mEAAmE;gBACnE,0BAA0B;gBAC1B,KAAK,YAAY;oBACf,IAAI,WAAW,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC;wBAC3B,MAAM,OAAO,GAAG,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC;wBACtC,MAAM,SAAS,GAAG,WAAW,CAAC,IAAI,CAAC,UAGtB,CAAC;wBACd,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE;4BACrB,IAAI,EAAE,OAAO;4BACb,MAAM,EAAE,WAAW,CAAC,IAAI,CAAC,MAAM,IAAI,KAAK;4BACxC,YAAY,EAAE,WAAW,CAAC,IAAI,CAAC,aAAa,IAAI,UAAU;4BAC1D,SAAS;4BACT,YAAY,EAAE,WAAW,CAAC,IAAI,CAAC,aAAa;yBAC7C,CAAC,CAAC;wBAEH,4DAA4D;wBAC5D,IAAI,SAAS,KAAK,SAAS,EAAE,CAAC;4BAC5B,IAAI,IAAI,CAAC,qBAAqB,CAAC,GAAG,CAAC,SAAS,CAAC;gCAAE,MAAM;4BACrD,IAAI,CAAC,qBAAqB,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;wBAC5C,CAAC;wBAED,MAAM,OAAO,GAAG,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,YAAY,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;wBAChE,oDAAoD;wBACpD,wDAAwD;wBACxD,yDAAyD;wBACzD,IAAI,OAAO,EAAE,IAAI,KAAK,cAAc;4BAAE,MAAM;wBAC5C,IACE,OAAO,EAAE,IAAI,KAAK,YAAY;4BAC9B,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,EACjC,CAAC;4BACD,MAAM;wBACR,CAAC;wBACD,IAAI,OAAO,EAAE,IAAI,KAAK,YAAY,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC;4BAC1D,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,YAAY,CAAC,MAAM,GAAG,CAAC,CAAC,GAAG;gCAChD,GAAG,OAAO;gCACV,OAAO,EAAE,OAAO,CAAC,OAAO,GAAG,OAAO;6BACnC,CAAC;wBACJ,CAAC;6BAAM,CAAC;4BACN,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC;gCACrB,EAAE,EAAE,cAAc,IAAI,CAAC,GAAG,EAAE,IAAI,IAAI,CAAC,MAAM,EAAE,EAAE;gCAC/C,IAAI,EAAE,YAAY;gCAClB,OAAO,EAAE,OAAO;gCAChB,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;gCACnC,WAAW,EAAE,IAAI;6BAClB,CAAC,CAAC;wBACL,CAAC;wBACD,IAAI,CAAC,IAAI,CAAC,gBAAgB,EAAE,IAAI,CAAC,YAAY,CAAC,CAAC;oBACjD,CAAC;oBACD,MAAM;gBAER,2CAA2C;gBAC3C,KAAK,cAAc;oBACjB,IAAI,WAAW,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC;wBAC3B,MAAM,QAAQ,GAAG,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC;wBAEvC,uCAAuC;wBACvC,MAAM,WAAW,GAAG,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,YAAY,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;wBACpE,IAAI,WAAW,IAAI,WAAW,CAAC,WAAW,EAAE,CAAC;4BAC3C,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,YAAY,CAAC,MAAM,GAAG,CAAC,CAAC,GAAG;gCAChD,GAAG,WAAW;gCACd,OAAO,EAAE,WAAW,CAAC,OAAO,GAAG,QAAQ;6BACxC,CAAC;wBACJ,CAAC;6BAAM,CAAC;4BACN,iDAAiD;4BACjD,MAAM,YAAY,GAAgB;gCAChC,EAAE,EAAE,GAAG,WAAW,CAAC,IAAI,IAAI,IAAI,CAAC,GAAG,EAAE,IAAI,IAAI,CAAC,MAAM,EAAE,EAAE;gCACxD,IAAI,EAAE,cAAc;gCACpB,OAAO,EAAE,QAAQ;gCACjB,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;gCACnC,WAAW,EAAE,IAAI;6BAClB,CAAC;4BACF,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;wBACvC,CAAC;wBACD,IAAI,CAAC,IAAI,CAAC,gBAAgB,EAAE,IAAI,CAAC,YAAY,CAAC,CAAC;oBACjD,CAAC;oBACD,MAAM;gBAER,gDAAgD;gBAChD,KAAK,iBAAiB;oBACpB,MAAM,UAAU,GAAG,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,YAAY,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;oBACnE,IAAI,UAAU,IAAI,UAAU,CAAC,WAAW,EAAE,CAAC;wBACzC,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,YAAY,CAAC,MAAM,GAAG,CAAC,CAAC,GAAG;4BAChD,GAAG,UAAU;4BACb,WAAW,EAAE,KAAK;yBACnB,CAAC;oBACJ,CAAC;oBAED,wBAAwB;oBACxB,IAAI,CAAC,eAAe,GAAG,KAAK,CAAC;oBAC7B,IAAI,CAAC,IAAI,CAAC,qBAAqB,EAAE,KAAK,CAAC,CAAC;oBACxC,IAAI,CAAC,IAAI,CAAC,gBAAgB,EAAE,IAAI,CAAC,YAAY,CAAC,CAAC;oBAC/C,MAAM;gBAER,8BAA8B;gBAC9B,KAAK,oBAAoB;oBACvB,IAAI,WAAW,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC;wBAC3B,MAAM,cAAc,GAAG,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC;wBAE7C,IAAI,WAAW,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC;4BAC5B,uEAAuE;4BACvE,MAAM,WAAW,GACf,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,YAAY,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;4BAElD,2EAA2E;4BAC3E,IACE,WAAW;gCACX,WAAW,CAAC,IAAI,KAAK,oBAAoB;gCACzC,WAAW,CAAC,WAAW,KAAK,IAAI,EAChC,CAAC;gCACD,gEAAgE;gCAChE,MAAM,kBAAkB,GACtB,WAAW,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,GAAG,GAAG,cAAc,CAAC,IAAI,EAAE,CAAC;gCAE3D,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,YAAY,CAAC,MAAM,GAAG,CAAC,CAAC,GAAG;oCAChD,GAAG,WAAW;oCACd,OAAO,EAAE,kBAAkB;oCAC3B,SAAS,EAAE,SAAS;iCACrB,CAAC;4BACJ,CAAC;iCAAM,CAAC;gCACN,+EAA+E;gCAC/E,MAAM,WAAW,GAAgB;oCAC/B,EAAE,EAAE,SAAS;oCACb,IAAI,EAAE,oBAAoB;oCAC1B,OAAO,EAAE,cAAc;oCACvB,SAAS,EAAE,SAAS;oCACpB,WAAW,EAAE,IAAI;iCAClB,CAAC;gCACF,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;4BACtC,CAAC;4BACD,IAAI,CAAC,IAAI,CAAC,gBAAgB,EAAE,IAAI,CAAC,YAAY,CAAC,CAAC;4BAE/C,sCAAsC;4BACtC,IAAI,CAAC,iBAAiB,GAAG,EAAE,CAAC;4BAC5B,IAAI,CAAC,IAAI,CAAC,yBAAyB,EAAE,EAAE,CAAC,CAAC;wBAC3C,CAAC;6BAAM,CAAC;4BACN,gDAAgD;4BAChD,IAAI,CAAC,iBAAiB,GAAG,cAAc,CAAC;4BACxC,IAAI,CAAC,IAAI,CAAC,yBAAyB,EAAE,cAAc,CAAC,CAAC;wBACvD,CAAC;oBACH,CAAC;oBACD,MAAM;gBAER,2FAA2F;gBAC3F,KAAK,aAAa;oBAChB,IAAI,WAAW,CAAC,IAAI,EAAE,OAAO,EAAE,CAAC;wBAC9B,IAAI,CAAC,eAAe,GAAG;4BACrB,OAAO,EAAE,WAAW,CAAC,IAAI,CAAC,OAAO;4BACjC,KAAK,EAAE,WAAW,CAAC,IAAI,CAAC,KAAK;yBAC9B,CAAC;wBACF,OAAO,CAAC,GAAG,CAAC,mBAAmB,EAAE,WAAW,CAAC,IAAI,CAAC,CAAC;wBACnD,IAAI,CAAC,IAAI,CAAC,eAAe,EAAE,IAAI,CAAC,eAAe,CAAC,CAAC;wBACjD,MAAM,cAAc,GAAgB;4BAClC,EAAE,EAAE,SAAS;4BACb,IAAI,EAAE,aAAa;4BACnB,OAAO,EAAE,GAAG,WAAW,CAAC,IAAI,CAAC,OAAO,YAAY,WAAW,CAAC,IAAI,CAAC,KAAK,IAAI,CAAC,GAAG;4BAC9E,SAAS;yBACV,CAAC;wBACF,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;wBACvC,IAAI,CAAC,IAAI,CAAC,gBAAgB,EAAE,IAAI,CAAC,YAAY,CAAC,CAAC;oBACjD,CAAC;oBACD,MAAM;gBACR,4EAA4E;gBAC5E,KAAK,cAAc;oBACjB,IAAI,WAAW,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC;wBAC3B,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,EAAE,IAAI,EAAE,WAAW,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;oBAC3D,CAAC;oBACD,MAAM;gBAER,sEAAsE;gBACtE,KAAK,iBAAiB;oBACpB,IAAI,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;oBAC3B,MAAM;gBAER,KAAK,iBAAiB;oBACpB,IAAI,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;oBAC3B,MAAM;gBAER,gCAAgC;gBAChC,KAAK,mBAAmB;oBACtB,IAAI,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;oBAC7B,MAAM;gBAER,KAAK,mBAAmB;oBACtB,IAAI,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;oBAC7B,MAAM;gBAER,KAAK,uBAAuB;oBAC1B,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC;oBACxB,IAAI,CAAC,IAAI,CAAC,iBAAiB,EAAE,IAAI,CAAC,CAAC;oBACnC,MAAM;gBAER,KAAK,uBAAuB;oBAC1B,IAAI,CAAC,WAAW,GAAG,KAAK,CAAC;oBACzB,IAAI,CAAC,IAAI,CAAC,iBAAiB,EAAE,KAAK,CAAC,CAAC;oBACpC,MAAM;gBAER,yEAAyE;gBACzE,KAAK,sBAAsB,CAAC,CAAC,CAAC;oBAC5B,MAAM,KAAK,GAAG,IAAI,CAAC,cAAc,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC;oBACpD,IAAI,IAAI,CAAC,eAAe,CAAC,YAAY,CAAC,KAAK,CAAC,EAAE,CAAC;wBAC7C,MAAM;oBACR,CAAC;oBACD,MAAM,OAAO,GAAG,IAAI,CAAC,eAAe,CAAC,gBAAgB,EAAE,CAAC;oBACxD,IAAI,OAAO,EAAE,CAAC;wBACZ,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC;wBACvB,IAAI,CAAC,wBAAwB,GAAG,CAAC,CAAC;wBAClC,IAAI,CAAC,IAAI,CAAC,gBAAgB,EAAE,IAAI,CAAC,CAAC;oBACpC,CAAC;oBACD,MAAM;gBACR,CAAC;gBAED,uBAAuB;gBACvB,KAAK,sBAAsB;oBACzB,IAAI,IAAI,CAAC,eAAe,CAAC,YAAY,CAAC,IAAI,CAAC,cAAc,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC;wBAC7E,MAAM;oBACR,CAAC;oBACD,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;wBACpB,IAAI,CAAC,UAAU,GAAG,KAAK,CAAC;wBACxB,IAAI,CAAC,eAAe,CAAC,eAAe,EAAE,CAAC;wBACvC,IAAI,CAAC,IAAI,CAAC,gBAAgB,EAAE,KAAK,CAAC,CAAC;oBACrC,CAAC;oBACD,MAAM;gBAER,iDAAiD;gBACjD,KAAK,iBAAiB;oBACpB,IAAI,CAAC,qBAAqB,CAAC,WAAW,CAAC,IAAI,EAAE,OAAO,IAAI,EAAE,EAAE,SAAS,EAAE,SAAS,CAAC,CAAC;oBAClF,MAAM;gBAER,KAAK,SAAS;oBACZ,IAAI,WAAW,CAAC,IAAI,EAAE,CAAC;wBACrB,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,WAAW,CAAC,IAAI,CAAC,CAAC;oBACzC,CAAC;oBACD,MAAM;gBACR,kCAAkC;gBAClC,KAAK,wBAAwB;oBAC3B,IAAI,WAAW,CAAC,IAAI,EAAE,oBAAoB,EAAE,CAAC;wBAC3C,MAAM,eAAe,GAAgB;4BACnC,EAAE,EAAE,SAAS;4BACb,IAAI,EAAE,eAAe;4BACrB,OAAO,EAAE,sBAAsB,WAAW,CAAC,IAAI,CAAC,oBAAoB,EAAE;4BACtE,SAAS;yBACV,CAAC;wBACF,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;wBACxC,IAAI,CAAC,IAAI,CAAC,gBAAgB,EAAE,IAAI,CAAC,YAAY,CAAC,CAAC;oBACjD,CAAC;oBACD,MAAM;gBAER,gEAAgE;gBAChE,KAAK,gBAAgB;oBACnB,IAAI,WAAW,CAAC,IAAI,EAAE,CAAC;wBACrB,MAAM,UAAU,GAAG,WAAW,CAAC,IAAI,CAAC;wBAEpC,QAAQ,UAAU,CAAC,IAAI,EAAE,CAAC;4BACxB,KAAK,0BAA0B;gCAC7B,IAAI,UAAU,CAAC,IAAI,EAAE,CAAC;oCACpB,MAAM,SAAS,GAAG,UAAU,CAAC,IAAI,CAAC;oCAClC,MAAM,WAAW,GACf,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,YAAY,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;oCAClD,IACE,WAAW;wCACX,WAAW,CAAC,IAAI,KAAK,oBAAoB;wCACzC,WAAW,CAAC,WAAW,KAAK,IAAI,EAChC,CAAC;wCACD,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,YAAY,CAAC,MAAM,GAAG,CAAC,CAAC,GAAG;4CAChD,GAAG,WAAW;4CACd,OAAO,EAAE,SAAS;4CAClB,SAAS;4CACT,WAAW,EAAE,KAAK;yCACnB,CAAC;oCACJ,CAAC;yCAAM,CAAC;wCACN,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC;4CACrB,EAAE,EAAE,GAAG,UAAU,CAAC,IAAI,IAAI,IAAI,CAAC,GAAG,EAAE,IAAI,IAAI,CAAC,MAAM,EAAE,EAAE;4CACvD,IAAI,EAAE,oBAAoB;4CAC1B,OAAO,EAAE,SAAS;4CAClB,SAAS;4CACT,WAAW,EAAE,KAAK;yCACnB,CAAC,CAAC;oCACL,CAAC;oCACD,IAAI,CAAC,IAAI,CAAC,gBAAgB,EAAE,IAAI,CAAC,YAAY,CAAC,CAAC;oCAC/C,IAAI,CAAC,iBAAiB,GAAG,EAAE,CAAC;oCAC5B,IAAI,CAAC,IAAI,CAAC,yBAAyB,EAAE,EAAE,CAAC,CAAC;gCAC3C,CAAC;gCACD,MAAM;4BAER,8FAA8F;4BAC9F,KAAK,aAAa;gCAChB,IAAI,UAAU,CAAC,OAAO,EAAE,CAAC;oCACvB,IAAI,CAAC,eAAe,GAAG;wCACrB,OAAO,EAAE,UAAU,CAAC,OAAO;wCAC3B,KAAK,EAAE,UAAU,CAAC,KAAK;qCACxB,CAAC;oCACF,OAAO,CAAC,GAAG,CAAC,wBAAwB,EAAE,UAAU,CAAC,CAAC;oCAClD,IAAI,CAAC,IAAI,CAAC,eAAe,EAAE,IAAI,CAAC,eAAe,CAAC,CAAC;gCACnD,CAAC;gCACD,MAAM;4BAER,KAAK,uBAAuB;gCAC1B,IAAI,IAAI,CAAC,eAAe,CAAC,YAAY,CAAC,IAAI,CAAC,cAAc,CAAC,UAAU,CAAC,CAAC,EAAE,CAAC;oCACvE,MAAM;gCACR,CAAC;gCACD,IAAI,CAAC,eAAe,CAAC,eAAe,CAClC,UAAU,CAAC,KAAK,EAChB,IAAI,CAAC,cAAc,CAAC,UAAU,CAAC,CAChC,CAAC;gCACF,IAAI,CAAC,IAAI,CAAC,yBAAyB,EAAE,UAAU,CAAC,CAAC;gCACjD,MAAM;4BAER,KAAK,+BAA+B;gCAClC,IAAI,UAAU,CAAC,WAAW,EAAE,CAAC;oCAC3B,MAAM,KAAK,GAAG,IAAI,CAAC,cAAc,CAAC,UAAU,CAAC,CAAC;oCAC9C,IAAI,IAAI,CAAC,eAAe,CAAC,cAAc,CAAC,KAAK,CAAC,EAAE,CAAC;wCAC/C,MAAM;oCACR,CAAC;oCACD,uEAAuE;oCACvE,oEAAoE;oCACpE,6CAA6C;oCAC7C,IACE,CAAC,IAAI,CAAC,eAAe,CAAC,oBAAoB,EAAE;wCAC5C,CAAC,IAAI,CAAC,UAAU,EAChB,CAAC;wCACD,IAAI,CAAC,eAAe,CAAC,iBAAiB,EAAE,CAAC;oCAC3C,CAAC;oCACD,IAAI,CAAC,eAAe,CAAC,QAAQ,CAC3B,UAAU,CAAC,WAAW,EACtB,KAAK,CACN,CAAC;oCACF,IACE,IAAI,CAAC,eAAe,CAAC,sCAAsC,EAAE;wCAC7D,IAAI,CAAC,UAAU,EACf,CAAC;wCACD,IAAI,CAAC,UAAU,GAAG,KAAK,CAAC;wCACxB,IAAI,CAAC,IAAI,CAAC,gBAAgB,EAAE,KAAK,CAAC,CAAC;oCACrC,CAAC;oCACD,IAAI,CAAC,wBAAwB;wCAC3B,UAAU,CAAC,WAAW,CAAC,MAAM,CAAC;oCAChC,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,UAAU,CAAC,CAAC;gCACvC,CAAC;gCACD,MAAM;4BAER,KAAK,8BAA8B,CAAC,CAAC,CAAC;gCACpC,MAAM,eAAe,GAAG,IAAI,CAAC,eAAe,CAAC,WAAW,CACtD,IAAI,CAAC,cAAc,CAAC,UAAU,CAAC,CAChC,CAAC;gCACF,IAAI,eAAe,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;oCACvC,IAAI,CAAC,UAAU,GAAG,KAAK,CAAC;oCACxB,IAAI,CAAC,IAAI,CAAC,gBAAgB,EAAE,KAAK,CAAC,CAAC;gCACrC,CAAC;gCACD,IAAI,CAAC,IAAI,CAAC,kBAAkB,EAAE,UAAU,CAAC,CAAC;gCAC1C,MAAM;4BACR,CAAC;4BAED,KAAK,mBAAmB,CAAC,CAAC,CAAC;gCACzB,MAAM,gBAAgB,GACpB,UAAU,CAAC,iBAAiB;oCAC5B,UAAU,CAAC,gBAAgB;oCAC3B,IAAI,CAAC;gCACP,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,EAAE,gBAAgB,EAAE,CAAC,CAAC;gCAC/C,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC;oCACrB,EAAE,EAAE,qBAAqB,IAAI,CAAC,GAAG,EAAE,IAAI,IAAI,CAAC,MAAM,EAAE,EAAE;oCACtD,IAAI,EAAE,cAAc;oCACpB,OAAO,EACL,gBAAgB,KAAK,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,EAAE;oCAC3D,SAAS;iCACV,CAAC,CAAC;gCACH,IAAI,CAAC,IAAI,CAAC,gBAAgB,EAAE,IAAI,CAAC,YAAY,CAAC,CAAC;gCAC/C,MAAM;4BACR,CAAC;4BAED,KAAK,iBAAiB;gCACpB,IAAI,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;gCAC3B,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC;oCACrB,EAAE,EAAE,mBAAmB,IAAI,CAAC,GAAG,EAAE,IAAI,IAAI,CAAC,MAAM,EAAE,EAAE;oCACpD,IAAI,EAAE,iBAAiB;oCACvB,OAAO,EAAE,EAAE;oCACX,SAAS;iCACV,CAAC,CAAC;gCACH,IAAI,CAAC,IAAI,CAAC,gBAAgB,EAAE,IAAI,CAAC,YAAY,CAAC,CAAC;gCAC/C,MAAM;4BAER,oEAAoE;4BACpE,KAAK,iBAAiB;gCACpB,IAAI,CAAC,qBAAqB,CAAC,UAAU,CAAC,OAAO,IAAI,EAAE,EAAE,SAAS,EAAE,SAAS,CAAC,CAAC;gCAC3E,MAAM;4BAER,qEAAqE;4BACrE,KAAK,iBAAiB,CAAC,CAAC,CAAC;gCACvB,+DAA+D;gCAC/D,sEAAsE;gCACtE,IAAI,UAAU,CAAC,UAAU,KAAK,cAAc;oCAAE,MAAM;gCACpD,MAAM,cAAc,GAAmB;oCACrC,UAAU,EAAE,UAAU,CAAC,UAAU,IAAI,SAAS;oCAC9C,MAAM,EAAE,UAAU,CAAC,MAAM,IAAI,OAAO;oCACpC,OAAO,EAAE,UAAU,CAAC,OAAO,IAAI,IAAI;oCACnC,MAAM,EAAE,UAAU,CAAC,MAAM,IAAI,IAAI;iCAClC,CAAC;gCACF,IAAI,CAAC,IAAI,CAAC,gBAAgB,EAAE,cAAc,CAAC,CAAC;gCAC5C,MAAM;4BACR,CAAC;4BAED,0DAA0D;4BAC1D,KAAK,qBAAqB,CAAC,CAAC,CAAC;gCAC3B,MAAM,kBAAkB,GAAuB;oCAC7C,aAAa,EAAE,UAAU,CAAC,cAAc;oCACxC,kBAAkB,EAAE,UAAU,CAAC,oBAAoB;iCACpD,CAAC;gCACF,IAAI,CAAC,IAAI,CAAC,oBAAoB,EAAE,kBAAkB,CAAC,CAAC;gCACpD,MAAM;4BACR,CAAC;wBACH,CAAC;oBACH,CAAC;oBACD,MAAM;gBAER,sFAAsF;gBACtF,KAAK,iBAAiB,CAAC,CAAC,CAAC;oBACvB,IAAI,WAAW,CAAC,UAAU,KAAK,cAAc;wBAAE,MAAM;oBACrD,MAAM,cAAc,GAAmB;wBACrC,UAAU,EAAE,WAAW,CAAC,UAAU,IAAI,SAAS;wBAC/C,MAAM,EAAE,WAAW,CAAC,MAAM,IAAI,OAAO;wBACrC,OAAO,EAAE,WAAW,CAAC,OAAO,IAAI,IAAI;wBACpC,MAAM,EAAE,WAAW,CAAC,MAAM,IAAI,IAAI;qBACnC,CAAC;oBACF,IAAI,CAAC,IAAI,CAAC,gBAAgB,EAAE,cAAc,CAAC,CAAC;oBAC5C,MAAM;gBACR,CAAC;gBAED,sCAAsC;gBACtC,KAAK,qBAAqB,CAAC;gBAC3B,KAAK,iBAAiB,CAAC;gBACvB,KAAK,sBAAsB,CAAC;gBAC5B,KAAK,qBAAqB,CAAC;gBAC3B,KAAK,eAAe;oBAClB,MAAM;YACV,CAAC;QACH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,+BAA+B;QACjC,CAAC;IACH,CAAC;IAEO,qBAAqB,CAC3B,OAAuB,EACvB,SAAiB,EACjB,SAAiB;QAEjB,IAAI,CAAC,IAAI,CAAC,gBAAgB,EAAE,EAAE,OAAO,EAAE,CAAC,CAAC;QACzC,MAAM,KAAK,GAAG,OAAO,CAAC,MAAM,KAAK,CAAC;YAChC,CAAC,CAAC,WAAW;YACb,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,MAAM,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACnF,MAAM,aAAa,GAAgB;YACjC,EAAE,EAAE,SAAS;YACb,IAAI,EAAE,QAAQ;YACd,OAAO,EAAE,KAAK;YACd,SAAS;SACV,CAAC;QACF,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;QACtC,IAAI,CAAC,IAAI,CAAC,gBAAgB,EAAE,IAAI,CAAC,YAAY,CAAC,CAAC;IACjD,CAAC;IAEO,cAAc,CACpB,IAAuC;QAEvC,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,OAAO,EAAE,CAAC;QACZ,CAAC;QAED,OAAO;YACL,UAAU,EAAE,IAAI,CAAC,WAAW;YAC5B,eAAe,EAAE,IAAI,CAAC,iBAAiB,IAAI,IAAI,CAAC,OAAO;YACvD,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,GAAG,EAAE,IAAI,CAAC,iBAAiB,CAAE,IAAyB,CAAC,GAAG,CAAC;YAC3D,eAAe,EAAE,IAAI,CAAC,iBAAiB,CACpC,IAAuC,CAAC,iBAAiB,CAC3D;SACF,CAAC;IACJ,CAAC;IAEO,iBAAiB,CAAC,KAAc;QACtC,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC;YACxD,CAAC,CAAC,KAAK;YACP,CAAC,CAAC,SAAS,CAAC;IAChB,CAAC;IAED;;OAEG;IACH,wBAAwB,CAAC,OAAmB;QAC1C,IAAI,CAAC,kBAAkB,CAAC,OAAO,EAAE,IAAI,EAAE,WAAW,CAAC,CAAC;IACtD,CAAC;IAED;;OAEG;IACH,KAAK;QACH,IAAI,CAAC,YAAY,GAAG,EAAE,CAAC;QACvB,IAAI,CAAC,iBAAiB,GAAG,EAAE,CAAC;QAC5B,IAAI,CAAC,eAAe,GAAG,KAAK,CAAC;QAC7B,IAAI,CAAC,UAAU,GAAG,KAAK,CAAC;QACxB,IAAI,CAAC,WAAW,GAAG,KAAK,CAAC;QACzB,IAAI,CAAC,wBAAwB,GAAG,CAAC,CAAC;QAClC,IAAI,CAAC,eAAe,GAAG,IAAI,CAAC;QAC5B,IAAI,CAAC,eAAe,CAAC,KAAK,EAAE,CAAC;QAC7B,IAAI,CAAC,IAAI,CAAC,gBAAgB,EAAE,IAAI,CAAC,YAAY,CAAC,CAAC;QAC/C,IAAI,CAAC,IAAI,CAAC,yBAAyB,EAAE,EAAE,CAAC,CAAC;QACzC,IAAI,CAAC,IAAI,CAAC,qBAAqB,EAAE,KAAK,CAAC,CAAC;QACxC,IAAI,CAAC,IAAI,CAAC,gBAAgB,EAAE,KAAK,CAAC,CAAC;QACnC,IAAI,CAAC,IAAI,CAAC,iBAAiB,EAAE,KAAK,CAAC,CAAC;QACpC,IAAI,CAAC,IAAI,CAAC,eAAe,EAAE,IAAI,CAAC,CAAC;IACnC,CAAC;CACF","sourcesContent":["import { Room, RoomEvent } from \"livekit-client\";\nimport { ChatMessage, ConvaiAction, InteractionCreated, ServerResponse } from \"./types\";\nimport { EventEmitter } from \"./EventEmitter\";\nimport {\n BlendshapeQueue,\n type BlendshapeChunkMetadata,\n} from \"./BlendshapeQueue\";\n\ntype LifecycleOwnerPayload = {\n response_id?: string;\n neurosync_turn_id?: number;\n turn_id?: number;\n epoch?: number;\n};\n\n/**\n * Handles incoming messages from Convai\n * Processes various message types from the AI assistant and updates chat history\n */\nexport class MessageHandler extends EventEmitter {\n private room: Room | null = null;\n private chatMessages: ChatMessage[] = [];\n private userTranscription: string = \"\";\n private logRtviMessages: boolean = true;\n private isBotResponding: boolean = false;\n private isSpeaking: boolean = false;\n private isListening: boolean = false;\n private totalBlendshapesReceived: number = 0;\n private blendshapeQueue: BlendshapeQueue;\n private _currentEmotion: { emotion: string; scale?: number } | null = null;\n // bot-output segments already added to the chat. The server re-sends the\n // same segment (full text) as TTS progress advances (spoken_status\n // in-progress → completed); only the first sighting may touch the chat.\n private seenBotOutputSegments = new Set<number | string>();\n\n // Fix 4: store a single bound reference so setupListeners/cleanupListeners use the\n // exact same function object. Previously .bind(this) in each call created a new\n // reference every time, making room.off() a no-op and leaking listeners on reconnect.\n private readonly _boundHandleDataReceived: (\n payload: Uint8Array,\n participant: unknown,\n ) => void;\n\n constructor(room?: Room) {\n super();\n this._boundHandleDataReceived = this.handleDataReceived.bind(this);\n this.blendshapeQueue = new BlendshapeQueue();\n if (room) {\n this.setRoom(room);\n }\n }\n\n /**\n * Get the blendshape queue instance\n */\n getBlendshapeQueue(): BlendshapeQueue {\n return this.blendshapeQueue;\n }\n\n /**\n * Enable or disable console logging for decoded incoming RTVI messages.\n */\n setRtviMessageLogging(enabled: boolean): void {\n this.logRtviMessages = enabled;\n }\n\n /**\n * Get current chat messages\n */\n getChatMessages(): ChatMessage[] {\n return this.chatMessages;\n }\n\n /**\n * Get current user transcription\n */\n getUserTranscription(): string {\n return this.userTranscription;\n }\n\n /**\n * Get bot responding state\n */\n getIsBotResponding(): boolean {\n return this.isBotResponding;\n }\n\n /**\n * Get speaking state\n */\n getIsSpeaking(): boolean {\n return this.isSpeaking;\n }\n\n /**\n * Get current bot emotion (updated from bot-emotion messages)\n */\n getEmotion(): { emotion: string; scale?: number } | null {\n return this._currentEmotion;\n }\n\n /**\n * Get whether the user is currently speaking (bot is in \"listening\" state).\n * True from user-started-speaking until user-stopped-speaking.\n */\n getIsListening(): boolean {\n return this.isListening;\n }\n\n /**\n * Local interruption path used by the client before the server cancel/terminal\n * arrives. Keep MessageHandler state and BlendshapeQueue state in sync so the\n * next bot-started-speaking can activate cleanly.\n */\n interruptLipsyncPlayback(): void {\n const wasSpeaking = this.isSpeaking;\n this.isSpeaking = false;\n this.blendshapeQueue.interrupt();\n if (wasSpeaking) {\n this.emit(\"speakingChange\", false);\n }\n }\n\n /**\n * Set the LiveKit room instance\n */\n setRoom(room: Room): void {\n // Clean up previous room listeners\n if (this.room) {\n this.cleanupListeners();\n }\n\n this.room = room;\n this.setupListeners();\n }\n\n /**\n * Setup message listeners\n */\n private setupListeners(): void {\n if (!this.room) return;\n\n this.room.on(RoomEvent.DataReceived, this._boundHandleDataReceived);\n }\n\n /**\n * Clean up message listeners\n */\n private cleanupListeners(): void {\n if (!this.room) return;\n\n this.room.off(RoomEvent.DataReceived, this._boundHandleDataReceived);\n }\n\n /**\n * Handle incoming data message\n */\n private handleDataReceived(\n payload: Uint8Array,\n _participant: unknown,\n _transport: \"livekit\" | \"websocket\" = \"livekit\",\n ): void {\n let messageString = \"\";\n let parsed = false;\n\n try {\n // Decode bytes to string\n const decoder = new TextDecoder();\n messageString = decoder.decode(payload);\n\n // Parse JSON\n const messageData = JSON.parse(messageString);\n parsed = true;\n\n // Extract and categorize messages for chat display\n const timestamp = new Date().toISOString();\n const messageId = `${messageData.type}-${Date.now()}-${Math.random()}`;\n\n // Handle different message types\n switch (messageData.type) {\n // User text messages - Skip these, only allow user-transcription\n case \"user_text_message\":\n case \"user-llm-text\":\n case \"text-input\":\n case \"user-input\":\n case \"text-message\":\n case \"chat-message\":\n case \"input-text\":\n case \"message\":\n // Skip user text messages - only allow user-transcription\n break;\n\n // Bot Ready - Bot is ready, connection should be true\n case \"bot-ready\":\n this.emit(\"botReady\");\n break;\n\n // Bot LLM Started - Begin streaming response\n case \"bot-llm-started\":\n this.isBotResponding = true;\n this.emit(\"botRespondingChange\", true);\n this.seenBotOutputSegments.clear();\n\n // Add initial streaming message to chat\n const streamingMessage: ChatMessage = {\n id: messageId,\n type: \"bot-llm-text\",\n content: \"\",\n timestamp: timestamp,\n isStreaming: true,\n };\n this.chatMessages.push(streamingMessage);\n this.emit(\"messagesChange\", this.chatMessages);\n break;\n\n // Bot Output - Aggregated output stream (sentence/word-level, replaces bot-transcript)\n // Payload: { text, spoken, aggregated_by, segment_id, spoken_status,\n // spoken_progress }. The same segment_id is re-sent with the FULL\n // segment text on every TTS progress tick (spoken_status\n // \"in-progress\" → \"completed\"), so appending per event repeats the\n // sentence once per tick.\n case \"bot-output\":\n if (messageData.data?.text) {\n const newText = messageData.data.text;\n const segmentId = messageData.data.segment_id as\n | number\n | string\n | undefined;\n this.emit(\"botOutput\", {\n text: newText,\n spoken: messageData.data.spoken ?? false,\n aggregatedBy: messageData.data.aggregated_by ?? \"sentence\",\n segmentId,\n spokenStatus: messageData.data.spoken_status,\n });\n\n // Progress re-send of a segment already in the chat — skip.\n if (segmentId !== undefined) {\n if (this.seenBotOutputSegments.has(segmentId)) break;\n this.seenBotOutputSegments.add(segmentId);\n }\n\n const lastMsg = this.chatMessages[this.chatMessages.length - 1];\n // When the reply is rendered by the LLM text stream\n // (bot-llm-text), the TTS echo adds nothing — never mix\n // bot-output into an LLM bubble (streaming or complete).\n if (lastMsg?.type === \"bot-llm-text\") break;\n if (\n lastMsg?.type === \"bot-output\" &&\n lastMsg.content.includes(newText)\n ) {\n break;\n }\n if (lastMsg?.type === \"bot-output\" && lastMsg.isStreaming) {\n this.chatMessages[this.chatMessages.length - 1] = {\n ...lastMsg,\n content: lastMsg.content + newText,\n };\n } else {\n this.chatMessages.push({\n id: `bot-output-${Date.now()}-${Math.random()}`,\n type: \"bot-output\",\n content: newText,\n timestamp: new Date().toISOString(),\n isStreaming: true,\n });\n }\n this.emit(\"messagesChange\", this.chatMessages);\n }\n break;\n\n // Bot LLM Text Messages - Streaming chunks\n case \"bot-llm-text\":\n if (messageData.data?.text) {\n const newChunk = messageData.data.text;\n\n // Update the streaming message in chat\n const lastMessage = this.chatMessages[this.chatMessages.length - 1];\n if (lastMessage && lastMessage.isStreaming) {\n this.chatMessages[this.chatMessages.length - 1] = {\n ...lastMessage,\n content: lastMessage.content + newChunk,\n };\n } else {\n // If no streaming message exists yet, create one\n const streamingMsg: ChatMessage = {\n id: `${messageData.type}-${Date.now()}-${Math.random()}`,\n type: \"bot-llm-text\",\n content: newChunk,\n timestamp: new Date().toISOString(),\n isStreaming: true,\n };\n this.chatMessages.push(streamingMsg);\n }\n this.emit(\"messagesChange\", this.chatMessages);\n }\n break;\n\n // Bot LLM Stopped - Complete streaming response\n case \"bot-llm-stopped\":\n const lastBotMsg = this.chatMessages[this.chatMessages.length - 1];\n if (lastBotMsg && lastBotMsg.isStreaming) {\n this.chatMessages[this.chatMessages.length - 1] = {\n ...lastBotMsg,\n isStreaming: false,\n };\n }\n\n // Clear streaming state\n this.isBotResponding = false;\n this.emit(\"botRespondingChange\", false);\n this.emit(\"messagesChange\", this.chatMessages);\n break;\n\n // User Transcription Messages\n case \"user-transcription\":\n if (messageData.data?.text) {\n const messageContent = messageData.data.text;\n\n if (messageData.data?.final) {\n // Final transcription - accumulate in single bubble until bot responds\n const lastUserMsg =\n this.chatMessages[this.chatMessages.length - 1];\n\n // Check if last message is an accumulating user message (isStreaming=true)\n if (\n lastUserMsg &&\n lastUserMsg.type === \"user-transcription\" &&\n lastUserMsg.isStreaming === true\n ) {\n // Accumulate: append new content to existing message with space\n const accumulatedContent =\n lastUserMsg.content.trim() + \" \" + messageContent.trim();\n\n this.chatMessages[this.chatMessages.length - 1] = {\n ...lastUserMsg,\n content: accumulatedContent,\n timestamp: timestamp,\n };\n } else {\n // Start new accumulating message (isStreaming=true means \"still accumulating\")\n const userMessage: ChatMessage = {\n id: messageId,\n type: \"user-transcription\",\n content: messageContent,\n timestamp: timestamp,\n isStreaming: true,\n };\n this.chatMessages.push(userMessage);\n }\n this.emit(\"messagesChange\", this.chatMessages);\n\n // Clear live transcription when final\n this.userTranscription = \"\";\n this.emit(\"userTranscriptionChange\", \"\");\n } else {\n // Non-final transcription - show in input field\n this.userTranscription = messageContent;\n this.emit(\"userTranscriptionChange\", messageContent);\n }\n }\n break;\n\n // Bot Emotion Messages — LiveKit path: arrives as an RTVI message frame (messageData.data)\n case \"bot-emotion\":\n if (messageData.data?.emotion) {\n this._currentEmotion = {\n emotion: messageData.data.emotion,\n scale: messageData.data.scale,\n };\n console.log(\"[SDK bot-emotion]\", messageData.data);\n this.emit(\"emotionChange\", this._currentEmotion);\n const emotionMessage: ChatMessage = {\n id: messageId,\n type: \"bot-emotion\",\n content: `${messageData.data.emotion} (scale: ${messageData.data.scale || 1})`,\n timestamp,\n };\n this.chatMessages.push(emotionMessage);\n this.emit(\"messagesChange\", this.chatMessages);\n }\n break;\n // Bot TTS Text - Words as spoken by TTS (word-by-word for socket-based TTS)\n case \"bot-tts-text\":\n if (messageData.data?.text) {\n this.emit(\"botTtsText\", { text: messageData.data.text });\n }\n break;\n\n // Bot TTS lifecycle (more granular than bot-started/stopped-speaking)\n case \"bot-tts-started\":\n this.emit(\"botTtsStarted\");\n break;\n\n case \"bot-tts-stopped\":\n this.emit(\"botTtsStopped\");\n break;\n\n // Server-side muting indicators\n case \"user-mute-started\":\n this.emit(\"userMuteStarted\");\n break;\n\n case \"user-mute-stopped\":\n this.emit(\"userMuteStopped\");\n break;\n\n case \"user-started-speaking\":\n this.isListening = true;\n this.emit(\"listeningChange\", true);\n break;\n\n case \"user-stopped-speaking\":\n this.isListening = false;\n this.emit(\"listeningChange\", false);\n break;\n\n // Bot Started Speaking (priority over listening: state becomes speaking)\n case \"bot-started-speaking\": {\n const owner = this.lifecycleOwner(messageData.data);\n if (this.blendshapeQueue.isStaleOwner(owner)) {\n break;\n }\n const allowed = this.blendshapeQueue.startBotSpeaking();\n if (allowed) {\n this.isSpeaking = true;\n this.totalBlendshapesReceived = 0;\n this.emit(\"speakingChange\", true);\n }\n break;\n }\n\n // Bot Stopped Speaking\n case \"bot-stopped-speaking\":\n if (this.blendshapeQueue.isStaleOwner(this.lifecycleOwner(messageData.data))) {\n break;\n }\n if (this.isSpeaking) {\n this.isSpeaking = false;\n this.blendshapeQueue.stopBotSpeaking();\n this.emit(\"speakingChange\", false);\n }\n break;\n\n // Action Response Messages (LiveKit/WebRTC path)\n case \"action-response\":\n this._handleActionResponse(messageData.data?.actions ?? [], messageId, timestamp);\n break;\n\n case \"metrics\":\n if (messageData.data) {\n this.emit(\"metrics\", messageData.data);\n }\n break;\n // Behavior Tree Response Messages\n case \"behavior-tree-response\":\n if (messageData.data?.narrative_section_id) {\n const behaviorMessage: ChatMessage = {\n id: messageId,\n type: \"behavior-tree\",\n content: `Narrative Section: ${messageData.data.narrative_section_id}`,\n timestamp,\n };\n this.chatMessages.push(behaviorMessage);\n this.emit(\"messagesChange\", this.chatMessages);\n }\n break;\n\n // Server Message - Contains various data types like blendshapes\n case \"server-message\":\n if (messageData.data) {\n const serverData = messageData.data;\n\n switch (serverData.type) {\n case \"final-user-transcription\":\n if (serverData.text) {\n const finalText = serverData.text;\n const lastUserMsg =\n this.chatMessages[this.chatMessages.length - 1];\n if (\n lastUserMsg &&\n lastUserMsg.type === \"user-transcription\" &&\n lastUserMsg.isStreaming === true\n ) {\n this.chatMessages[this.chatMessages.length - 1] = {\n ...lastUserMsg,\n content: finalText,\n timestamp,\n isStreaming: false,\n };\n } else {\n this.chatMessages.push({\n id: `${serverData.type}-${Date.now()}-${Math.random()}`,\n type: \"user-transcription\",\n content: finalText,\n timestamp,\n isStreaming: false,\n });\n }\n this.emit(\"messagesChange\", this.chatMessages);\n this.userTranscription = \"\";\n this.emit(\"userTranscriptionChange\", \"\");\n }\n break;\n\n // WebSocket path: arrives inside a bot-text data message as serverData (not messageData.data)\n case \"bot-emotion\":\n if (serverData.emotion) {\n this._currentEmotion = {\n emotion: serverData.emotion,\n scale: serverData.scale,\n };\n console.log(\"[SDK bot-emotion (ws)]\", serverData);\n this.emit(\"emotionChange\", this._currentEmotion);\n }\n break;\n\n case \"blendshape-turn-stats\":\n if (this.blendshapeQueue.isStaleOwner(this.lifecycleOwner(serverData))) {\n break;\n }\n this.blendshapeQueue.endConversation(\n serverData.stats,\n this.lifecycleOwner(serverData),\n );\n this.emit(\"blendshapeStatsReceived\", serverData);\n break;\n\n case \"chunked-neurosync-blendshapes\":\n if (serverData.blendshapes) {\n const owner = this.lifecycleOwner(serverData);\n if (this.blendshapeQueue.isRetiredOwner(owner)) {\n break;\n }\n // If the queue is idle (no active conversation, bot not yet speaking),\n // start a conversation so early chunks from an initial bot greeting\n // are accepted rather than silently dropped.\n if (\n !this.blendshapeQueue.isConversationActive() &&\n !this.isSpeaking\n ) {\n this.blendshapeQueue.startConversation();\n }\n this.blendshapeQueue.addChunk(\n serverData.blendshapes,\n owner,\n );\n if (\n this.blendshapeQueue.consumeOwnerReplacementStoppedSpeaking() &&\n this.isSpeaking\n ) {\n this.isSpeaking = false;\n this.emit(\"speakingChange\", false);\n }\n this.totalBlendshapesReceived +=\n serverData.blendshapes.length;\n this.emit(\"blendshapes\", serverData);\n }\n break;\n\n case \"neurosync-blendshapes-cancel\": {\n const cancelledActive = this.blendshapeQueue.cancelOwner(\n this.lifecycleOwner(serverData),\n );\n if (cancelledActive && this.isSpeaking) {\n this.isSpeaking = false;\n this.emit(\"speakingChange\", false);\n }\n this.emit(\"blendshapeCancel\", serverData);\n break;\n }\n\n case \"user-idle-warning\": {\n const remainingSeconds: number | null =\n serverData.remaining_seconds ??\n serverData.remainingSeconds ??\n null;\n this.emit(\"idleWarning\", { remainingSeconds });\n this.chatMessages.push({\n id: `user-idle-warning-${Date.now()}-${Math.random()}`,\n type: \"idle-warning\",\n content:\n remainingSeconds !== null ? String(remainingSeconds) : \"\",\n timestamp,\n });\n this.emit(\"messagesChange\", this.chatMessages);\n break;\n }\n\n case \"llm-no-response\":\n this.emit(\"llmNoResponse\");\n this.chatMessages.push({\n id: `llm-no-response-${Date.now()}-${Math.random()}`,\n type: \"llm-no-response\",\n content: \"\",\n timestamp,\n });\n this.emit(\"messagesChange\", this.chatMessages);\n break;\n\n // Action Response (WebSocket/RTVI path — wrapped in server-message)\n case \"action-response\":\n this._handleActionResponse(serverData.actions ?? [], messageId, timestamp);\n break;\n\n // Server acknowledgment — arrives wrapped in server-message envelope\n case \"server-response\": {\n // client-ready is an internal RTVI handshake; server echoes an\n // \"Unknown message type\" error for it which is expected and harmless.\n if (serverData.event_type === \"client-ready\") break;\n const serverResponse: ServerResponse = {\n event_type: serverData.event_type ?? \"unknown\",\n status: serverData.status ?? \"error\",\n message: serverData.message ?? null,\n extras: serverData.extras ?? null,\n };\n this.emit(\"serverResponse\", serverResponse);\n break;\n }\n\n // interaction-created: session IDs for analytics/tracking\n case \"interaction-created\": {\n const interactionCreated: InteractionCreated = {\n interactionId: serverData.interaction_id,\n characterSessionId: serverData.character_session_id,\n };\n this.emit(\"interactionCreated\", interactionCreated);\n break;\n }\n }\n }\n break;\n\n // Fallback: server-response at top level (not currently observed but kept for safety)\n case \"server-response\": {\n if (messageData.event_type === \"client-ready\") break;\n const serverResponse: ServerResponse = {\n event_type: messageData.event_type ?? \"unknown\",\n status: messageData.status ?? \"error\",\n message: messageData.message ?? null,\n extras: messageData.extras ?? null,\n };\n this.emit(\"serverResponse\", serverResponse);\n break;\n }\n\n // Silently ignore other message types\n case \"moderation-response\":\n case \"trigger-message\":\n case \"update-template-keys\":\n case \"update-dynamic-info\":\n case \"interrupt-bot\":\n break;\n }\n } catch (error) {\n // Silently handle parse errors\n }\n }\n\n private _handleActionResponse(\n actions: ConvaiAction[],\n messageId: string,\n timestamp: string,\n ): void {\n this.emit(\"actionResponse\", { actions });\n const label = actions.length === 0\n ? \"No action\"\n : actions.map((a) => (a.target ? `${a.name} → ${a.target}` : a.name)).join(\", \");\n const actionMessage: ChatMessage = {\n id: messageId,\n type: \"action\",\n content: label,\n timestamp,\n };\n this.chatMessages.push(actionMessage);\n this.emit(\"messagesChange\", this.chatMessages);\n }\n\n private lifecycleOwner(\n data: LifecycleOwnerPayload | undefined,\n ): BlendshapeChunkMetadata {\n if (!data) {\n return {};\n }\n\n return {\n responseId: data.response_id,\n neurosyncTurnId: data.neurosync_turn_id ?? data.turn_id,\n epoch: data.epoch,\n fps: this.numberOrUndefined((data as { fps?: number }).fps),\n startFrameIndex: this.numberOrUndefined(\n (data as { start_frame_index?: number }).start_frame_index,\n ),\n };\n }\n\n private numberOrUndefined(value: unknown): number | undefined {\n return typeof value === \"number\" && Number.isFinite(value)\n ? value\n : undefined;\n }\n\n /**\n * Public entry point for WebSocket transport to inject messages into the same pipeline.\n */\n handleDataReceivedPublic(payload: Uint8Array): void {\n this.handleDataReceived(payload, null, \"websocket\");\n }\n\n /**\n * Reset message state\n */\n reset(): void {\n this.chatMessages = [];\n this.userTranscription = \"\";\n this.isBotResponding = false;\n this.isSpeaking = false;\n this.isListening = false;\n this.totalBlendshapesReceived = 0;\n this._currentEmotion = null;\n this.blendshapeQueue.reset();\n this.emit(\"messagesChange\", this.chatMessages);\n this.emit(\"userTranscriptionChange\", \"\");\n this.emit(\"botRespondingChange\", false);\n this.emit(\"speakingChange\", false);\n this.emit(\"listeningChange\", false);\n this.emit(\"emotionChange\", null);\n }\n}\n"]}
1
+ {"version":3,"file":"MessageHandler.js","sourceRoot":"","sources":["../../src/core/MessageHandler.ts"],"names":[],"mappings":"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","sourcesContent":["import { Room, RoomEvent } from \"livekit-client\";\nimport { ChatMessage, ConvaiAction, InteractionCreated, ServerResponse } from \"./types\";\nimport { EventEmitter } from \"./EventEmitter\";\nimport {\n BlendshapeQueue,\n type BlendshapeChunkMetadata,\n} from \"./BlendshapeQueue\";\n\ntype LifecycleOwnerPayload = {\n response_id?: string;\n neurosync_turn_id?: number;\n turn_id?: number;\n epoch?: number;\n};\n\n/**\n * Handles incoming messages from Convai\n * Processes various message types from the AI assistant and updates chat history\n */\nexport class MessageHandler extends EventEmitter {\n private room: Room | null = null;\n private chatMessages: ChatMessage[] = [];\n private activeBotLlmMessageId: string | null = null;\n private userTranscription: string = \"\";\n private logRtviMessages: boolean = true;\n private isBotResponding: boolean = false;\n private isSpeaking: boolean = false;\n private isListening: boolean = false;\n private totalBlendshapesReceived: number = 0;\n private blendshapeQueue: BlendshapeQueue;\n private _currentEmotion: { emotion: string; scale?: number } | null = null;\n // bot-output segments already added to the chat. The server re-sends the\n // same segment (full text) as TTS progress advances (spoken_status\n // in-progress → completed); only the first sighting may touch the chat.\n private seenBotOutputSegments = new Set<number | string>();\n\n // Fix 4: store a single bound reference so setupListeners/cleanupListeners use the\n // exact same function object. Previously .bind(this) in each call created a new\n // reference every time, making room.off() a no-op and leaking listeners on reconnect.\n private readonly _boundHandleDataReceived: (\n payload: Uint8Array,\n participant: unknown,\n ) => void;\n\n constructor(room?: Room) {\n super();\n this._boundHandleDataReceived = this.handleDataReceived.bind(this);\n this.blendshapeQueue = new BlendshapeQueue();\n if (room) {\n this.setRoom(room);\n }\n }\n\n /**\n * Get the blendshape queue instance\n */\n getBlendshapeQueue(): BlendshapeQueue {\n return this.blendshapeQueue;\n }\n\n /**\n * Enable or disable console logging for decoded incoming RTVI messages.\n */\n setRtviMessageLogging(enabled: boolean): void {\n this.logRtviMessages = enabled;\n }\n\n /**\n * Get current chat messages\n */\n getChatMessages(): ChatMessage[] {\n return this.chatMessages;\n }\n\n /**\n * Get current user transcription\n */\n getUserTranscription(): string {\n return this.userTranscription;\n }\n\n /**\n * Get bot responding state\n */\n getIsBotResponding(): boolean {\n return this.isBotResponding;\n }\n\n /**\n * Get speaking state\n */\n getIsSpeaking(): boolean {\n return this.isSpeaking;\n }\n\n /**\n * Get current bot emotion (updated from bot-emotion messages)\n */\n getEmotion(): { emotion: string; scale?: number } | null {\n return this._currentEmotion;\n }\n\n /**\n * Get whether the user is currently speaking (bot is in \"listening\" state).\n * True from user-started-speaking until user-stopped-speaking.\n */\n getIsListening(): boolean {\n return this.isListening;\n }\n\n /**\n * Local interruption path used by the client before the server cancel/terminal\n * arrives. Keep MessageHandler state and BlendshapeQueue state in sync so the\n * next bot-started-speaking can activate cleanly.\n */\n interruptLipsyncPlayback(): void {\n const wasSpeaking = this.isSpeaking;\n this.isSpeaking = false;\n this.blendshapeQueue.interrupt();\n if (wasSpeaking) {\n this.emit(\"speakingChange\", false);\n }\n }\n\n /**\n * Set the LiveKit room instance\n */\n setRoom(room: Room): void {\n // Clean up previous room listeners\n if (this.room) {\n this.cleanupListeners();\n }\n\n this.room = room;\n this.setupListeners();\n }\n\n /**\n * Setup message listeners\n */\n private setupListeners(): void {\n if (!this.room) return;\n\n this.room.on(RoomEvent.DataReceived, this._boundHandleDataReceived);\n }\n\n /**\n * Clean up message listeners\n */\n private cleanupListeners(): void {\n if (!this.room) return;\n\n this.room.off(RoomEvent.DataReceived, this._boundHandleDataReceived);\n }\n\n /**\n * Handle incoming data message\n */\n private handleDataReceived(\n payload: Uint8Array,\n _participant: unknown,\n _transport: \"livekit\" | \"websocket\" = \"livekit\",\n ): void {\n let messageString = \"\";\n let parsed = false;\n\n try {\n // Decode bytes to string\n const decoder = new TextDecoder();\n messageString = decoder.decode(payload);\n\n // Parse JSON\n const messageData = JSON.parse(messageString);\n parsed = true;\n\n // Extract and categorize messages for chat display\n const timestamp = new Date().toISOString();\n const messageId = `${messageData.type}-${Date.now()}-${Math.random()}`;\n\n // Handle different message types\n switch (messageData.type) {\n // User text messages - Skip these, only allow user-transcription\n case \"user_text_message\":\n case \"user-llm-text\":\n case \"text-input\":\n case \"user-input\":\n case \"text-message\":\n case \"chat-message\":\n case \"input-text\":\n case \"message\":\n // Skip user text messages - only allow user-transcription\n break;\n\n // Bot Ready - Bot is ready, connection should be true\n case \"bot-ready\":\n this.emit(\"botReady\");\n break;\n\n // Bot LLM Started - Begin streaming response\n case \"bot-llm-started\":\n this.isBotResponding = true;\n this.emit(\"botRespondingChange\", true);\n this.seenBotOutputSegments.clear();\n\n // Add initial streaming message to chat\n const streamingMessage: ChatMessage = {\n id: messageId,\n type: \"bot-llm-text\",\n content: \"\",\n timestamp: timestamp,\n isStreaming: true,\n };\n this.activeBotLlmMessageId = messageId;\n this.chatMessages.push(streamingMessage);\n this.emit(\"messagesChange\", this.chatMessages);\n break;\n\n // Bot Output - Aggregated output stream (sentence/word-level, replaces bot-transcript)\n // Payload: { text, spoken, aggregated_by, segment_id, spoken_status,\n // spoken_progress }. The same segment_id is re-sent with the FULL\n // segment text on every TTS progress tick (spoken_status\n // \"in-progress\" → \"completed\"), so appending per event repeats the\n // sentence once per tick.\n case \"bot-output\":\n if (messageData.data?.text) {\n const newText = messageData.data.text;\n const segmentId = messageData.data.segment_id as\n | number\n | string\n | undefined;\n this.emit(\"botOutput\", {\n text: newText,\n spoken: messageData.data.spoken ?? false,\n aggregatedBy: messageData.data.aggregated_by ?? \"sentence\",\n segmentId,\n spokenStatus: messageData.data.spoken_status,\n });\n\n // Progress re-send of a segment already in the chat — skip.\n if (segmentId !== undefined) {\n if (this.seenBotOutputSegments.has(segmentId)) break;\n this.seenBotOutputSegments.add(segmentId);\n }\n\n const activeBotLlmMessage = this.activeBotLlmMessageId\n ? this.chatMessages.find(\n (message) => message.id === this.activeBotLlmMessageId,\n )\n : undefined;\n const lastMsg = this.chatMessages[this.chatMessages.length - 1];\n // When the reply is rendered by the LLM text stream\n // (bot-llm-text), the TTS echo adds nothing — never mix\n // bot-output into an LLM bubble (streaming or complete).\n if (activeBotLlmMessage?.type === \"bot-llm-text\") break;\n if (lastMsg?.type === \"bot-llm-text\") break;\n if (\n lastMsg?.type === \"bot-output\" &&\n lastMsg.content.includes(newText)\n ) {\n break;\n }\n if (lastMsg?.type === \"bot-output\" && lastMsg.isStreaming) {\n this.chatMessages[this.chatMessages.length - 1] = {\n ...lastMsg,\n content: lastMsg.content + newText,\n };\n } else {\n this.chatMessages.push({\n id: `bot-output-${Date.now()}-${Math.random()}`,\n type: \"bot-output\",\n content: newText,\n timestamp: new Date().toISOString(),\n isStreaming: true,\n });\n }\n this.emit(\"messagesChange\", this.chatMessages);\n }\n break;\n\n // Bot LLM Text Messages - Streaming chunks\n case \"bot-llm-text\":\n if (messageData.data?.text) {\n const newChunk = messageData.data.text;\n\n // Update the streaming message in chat\n const activeIndex = this.activeBotLlmMessageId\n ? this.chatMessages.findIndex(\n (message) =>\n message.id === this.activeBotLlmMessageId &&\n message.type === \"bot-llm-text\" &&\n message.isStreaming,\n )\n : -1;\n if (activeIndex >= 0) {\n const activeMessage = this.chatMessages[activeIndex];\n this.chatMessages[activeIndex] = {\n ...activeMessage,\n content: activeMessage.content + newChunk,\n };\n } else {\n // If no streaming message exists yet, create one\n const streamingMsg: ChatMessage = {\n id: `${messageData.type}-${Date.now()}-${Math.random()}`,\n type: \"bot-llm-text\",\n content: newChunk,\n timestamp: new Date().toISOString(),\n isStreaming: true,\n };\n this.activeBotLlmMessageId = streamingMsg.id;\n this.chatMessages.push(streamingMsg);\n }\n this.emit(\"messagesChange\", this.chatMessages);\n }\n break;\n\n // Bot LLM Stopped - Complete streaming response\n case \"bot-llm-stopped\":\n const activeIndex = this.activeBotLlmMessageId\n ? this.chatMessages.findIndex(\n (message) => message.id === this.activeBotLlmMessageId,\n )\n : -1;\n if (activeIndex >= 0 && this.chatMessages[activeIndex].isStreaming) {\n const activeMessage = this.chatMessages[activeIndex];\n this.chatMessages[activeIndex] = {\n ...activeMessage,\n isStreaming: false,\n };\n }\n\n // Clear streaming state\n this.isBotResponding = false;\n this.emit(\"botRespondingChange\", false);\n this.emit(\"messagesChange\", this.chatMessages);\n break;\n\n // User Transcription Messages\n case \"user-transcription\":\n if (messageData.data?.text) {\n const messageContent = messageData.data.text;\n\n if (messageData.data?.final) {\n // Final transcription - accumulate in single bubble until bot responds\n const lastUserMsg =\n this.chatMessages[this.chatMessages.length - 1];\n\n // Check if last message is an accumulating user message (isStreaming=true)\n if (\n lastUserMsg &&\n lastUserMsg.type === \"user-transcription\" &&\n lastUserMsg.isStreaming === true\n ) {\n // Accumulate: append new content to existing message with space\n const accumulatedContent =\n lastUserMsg.content.trim() + \" \" + messageContent.trim();\n\n this.chatMessages[this.chatMessages.length - 1] = {\n ...lastUserMsg,\n content: accumulatedContent,\n timestamp: timestamp,\n };\n } else {\n // Start new accumulating message (isStreaming=true means \"still accumulating\")\n const userMessage: ChatMessage = {\n id: messageId,\n type: \"user-transcription\",\n content: messageContent,\n timestamp: timestamp,\n isStreaming: true,\n };\n this.chatMessages.push(userMessage);\n }\n this.emit(\"messagesChange\", this.chatMessages);\n\n // Clear live transcription when final\n this.userTranscription = \"\";\n this.emit(\"userTranscriptionChange\", \"\");\n } else {\n // Non-final transcription - show in input field\n this.userTranscription = messageContent;\n this.emit(\"userTranscriptionChange\", messageContent);\n }\n }\n break;\n\n // Bot Emotion Messages — LiveKit path: arrives as an RTVI message frame (messageData.data)\n case \"bot-emotion\":\n if (messageData.data?.emotion) {\n this._currentEmotion = {\n emotion: messageData.data.emotion,\n scale: messageData.data.scale,\n };\n console.log(\"[SDK bot-emotion]\", messageData.data);\n this.emit(\"emotionChange\", this._currentEmotion);\n const emotionMessage: ChatMessage = {\n id: messageId,\n type: \"bot-emotion\",\n content: `${messageData.data.emotion} (scale: ${messageData.data.scale || 1})`,\n timestamp,\n };\n this.chatMessages.push(emotionMessage);\n this.emit(\"messagesChange\", this.chatMessages);\n }\n break;\n // Bot TTS Text - Words as spoken by TTS (word-by-word for socket-based TTS)\n case \"bot-tts-text\":\n if (messageData.data?.text) {\n this.emit(\"botTtsText\", { text: messageData.data.text });\n }\n break;\n\n // Bot TTS lifecycle (more granular than bot-started/stopped-speaking)\n case \"bot-tts-started\":\n this.emit(\"botTtsStarted\");\n break;\n\n case \"bot-tts-stopped\":\n this.emit(\"botTtsStopped\");\n break;\n\n // Server-side muting indicators\n case \"user-mute-started\":\n this.emit(\"userMuteStarted\");\n break;\n\n case \"user-mute-stopped\":\n this.emit(\"userMuteStopped\");\n break;\n\n case \"user-started-speaking\":\n this.isListening = true;\n this.emit(\"listeningChange\", true);\n break;\n\n case \"user-stopped-speaking\":\n this.isListening = false;\n this.emit(\"listeningChange\", false);\n break;\n\n // Bot Started Speaking (priority over listening: state becomes speaking)\n case \"bot-started-speaking\": {\n const owner = this.lifecycleOwner(messageData.data);\n if (this.blendshapeQueue.isStaleOwner(owner)) {\n break;\n }\n const allowed = this.blendshapeQueue.startBotSpeaking();\n if (allowed) {\n this.isSpeaking = true;\n this.totalBlendshapesReceived = 0;\n this.emit(\"speakingChange\", true);\n }\n break;\n }\n\n // Bot Stopped Speaking\n case \"bot-stopped-speaking\":\n if (this.blendshapeQueue.isStaleOwner(this.lifecycleOwner(messageData.data))) {\n break;\n }\n if (this.isSpeaking) {\n this.isSpeaking = false;\n this.blendshapeQueue.stopBotSpeaking();\n this.emit(\"speakingChange\", false);\n }\n break;\n\n // Action Response Messages (LiveKit/WebRTC path)\n case \"action-response\":\n this._handleActionResponse(messageData.data?.actions ?? [], messageId, timestamp);\n break;\n\n case \"metrics\":\n if (messageData.data) {\n this.emit(\"metrics\", messageData.data);\n }\n break;\n // Behavior Tree Response Messages\n case \"behavior-tree-response\":\n if (messageData.data?.narrative_section_id) {\n const behaviorMessage: ChatMessage = {\n id: messageId,\n type: \"behavior-tree\",\n content: `Narrative Section: ${messageData.data.narrative_section_id}`,\n timestamp,\n };\n this.chatMessages.push(behaviorMessage);\n this.emit(\"messagesChange\", this.chatMessages);\n }\n break;\n\n // Server Message - Contains various data types like blendshapes\n case \"server-message\":\n if (messageData.data) {\n const serverData = messageData.data;\n\n switch (serverData.type) {\n case \"final-user-transcription\":\n if (serverData.text) {\n const finalText = serverData.text;\n const lastUserMsg =\n this.chatMessages[this.chatMessages.length - 1];\n if (\n lastUserMsg &&\n lastUserMsg.type === \"user-transcription\" &&\n lastUserMsg.isStreaming === true\n ) {\n this.chatMessages[this.chatMessages.length - 1] = {\n ...lastUserMsg,\n content: finalText,\n timestamp,\n isStreaming: false,\n };\n } else {\n this.chatMessages.push({\n id: `${serverData.type}-${Date.now()}-${Math.random()}`,\n type: \"user-transcription\",\n content: finalText,\n timestamp,\n isStreaming: false,\n });\n }\n this.emit(\"messagesChange\", this.chatMessages);\n this.userTranscription = \"\";\n this.emit(\"userTranscriptionChange\", \"\");\n }\n break;\n\n // WebSocket path: arrives inside a bot-text data message as serverData (not messageData.data)\n case \"bot-emotion\":\n if (serverData.emotion) {\n this._currentEmotion = {\n emotion: serverData.emotion,\n scale: serverData.scale,\n };\n console.log(\"[SDK bot-emotion (ws)]\", serverData);\n this.emit(\"emotionChange\", this._currentEmotion);\n }\n break;\n\n case \"blendshape-turn-stats\":\n if (this.blendshapeQueue.isStaleOwner(this.lifecycleOwner(serverData))) {\n break;\n }\n this.blendshapeQueue.endConversation(\n serverData.stats,\n this.lifecycleOwner(serverData),\n );\n this.emit(\"blendshapeStatsReceived\", serverData);\n break;\n\n case \"chunked-neurosync-blendshapes\":\n if (serverData.blendshapes) {\n const owner = this.lifecycleOwner(serverData);\n if (this.blendshapeQueue.isRetiredOwner(owner)) {\n break;\n }\n // If the queue is idle (no active conversation, bot not yet speaking),\n // start a conversation so early chunks from an initial bot greeting\n // are accepted rather than silently dropped.\n if (\n !this.blendshapeQueue.isConversationActive() &&\n !this.isSpeaking\n ) {\n this.blendshapeQueue.startConversation();\n }\n this.blendshapeQueue.addChunk(\n serverData.blendshapes,\n owner,\n );\n if (\n this.blendshapeQueue.consumeOwnerReplacementStoppedSpeaking() &&\n this.isSpeaking\n ) {\n this.isSpeaking = false;\n this.emit(\"speakingChange\", false);\n }\n this.totalBlendshapesReceived +=\n serverData.blendshapes.length;\n this.emit(\"blendshapes\", serverData);\n }\n break;\n\n case \"neurosync-blendshapes-cancel\": {\n const cancelledActive = this.blendshapeQueue.cancelOwner(\n this.lifecycleOwner(serverData),\n );\n if (cancelledActive && this.isSpeaking) {\n this.isSpeaking = false;\n this.emit(\"speakingChange\", false);\n }\n this.emit(\"blendshapeCancel\", serverData);\n break;\n }\n\n case \"user-idle-warning\": {\n const remainingSeconds: number | null =\n serverData.remaining_seconds ??\n serverData.remainingSeconds ??\n null;\n this.emit(\"idleWarning\", { remainingSeconds });\n this.chatMessages.push({\n id: `user-idle-warning-${Date.now()}-${Math.random()}`,\n type: \"idle-warning\",\n content:\n remainingSeconds !== null ? String(remainingSeconds) : \"\",\n timestamp,\n });\n this.emit(\"messagesChange\", this.chatMessages);\n break;\n }\n\n case \"llm-no-response\":\n this.emit(\"llmNoResponse\");\n this.chatMessages.push({\n id: `llm-no-response-${Date.now()}-${Math.random()}`,\n type: \"llm-no-response\",\n content: \"\",\n timestamp,\n });\n this.emit(\"messagesChange\", this.chatMessages);\n break;\n\n // Action Response (WebSocket/RTVI path — wrapped in server-message)\n case \"action-response\":\n this._handleActionResponse(serverData.actions ?? [], messageId, timestamp);\n break;\n\n // Server acknowledgment — arrives wrapped in server-message envelope\n case \"server-response\": {\n // client-ready is an internal RTVI handshake; server echoes an\n // \"Unknown message type\" error for it which is expected and harmless.\n if (serverData.event_type === \"client-ready\") break;\n const serverResponse: ServerResponse = {\n event_type: serverData.event_type ?? \"unknown\",\n status: serverData.status ?? \"error\",\n message: serverData.message ?? null,\n extras: serverData.extras ?? null,\n };\n this.emit(\"serverResponse\", serverResponse);\n break;\n }\n\n // interaction-created: session IDs for analytics/tracking\n case \"interaction-created\": {\n const interactionCreated: InteractionCreated = {\n interactionId: serverData.interaction_id,\n characterSessionId: serverData.character_session_id,\n };\n this.emit(\"interactionCreated\", interactionCreated);\n break;\n }\n }\n }\n break;\n\n // Fallback: server-response at top level (not currently observed but kept for safety)\n case \"server-response\": {\n if (messageData.event_type === \"client-ready\") break;\n const serverResponse: ServerResponse = {\n event_type: messageData.event_type ?? \"unknown\",\n status: messageData.status ?? \"error\",\n message: messageData.message ?? null,\n extras: messageData.extras ?? null,\n };\n this.emit(\"serverResponse\", serverResponse);\n break;\n }\n\n // Silently ignore other message types\n case \"moderation-response\":\n case \"trigger-message\":\n case \"update-template-keys\":\n case \"update-dynamic-info\":\n case \"interrupt-bot\":\n break;\n }\n } catch (error) {\n // Silently handle parse errors\n }\n }\n\n private _handleActionResponse(\n actions: ConvaiAction[],\n messageId: string,\n timestamp: string,\n ): void {\n this.emit(\"actionResponse\", { actions });\n const label = actions.length === 0\n ? \"No action\"\n : actions.map((a) => (a.target ? `${a.name} → ${a.target}` : a.name)).join(\", \");\n const actionMessage: ChatMessage = {\n id: messageId,\n type: \"action\",\n content: label,\n timestamp,\n };\n this.chatMessages.push(actionMessage);\n this.emit(\"messagesChange\", this.chatMessages);\n }\n\n private lifecycleOwner(\n data: LifecycleOwnerPayload | undefined,\n ): BlendshapeChunkMetadata {\n if (!data) {\n return {};\n }\n\n return {\n responseId: data.response_id,\n neurosyncTurnId: data.neurosync_turn_id ?? data.turn_id,\n epoch: data.epoch,\n fps: this.numberOrUndefined((data as { fps?: number }).fps),\n startFrameIndex: this.numberOrUndefined(\n (data as { start_frame_index?: number }).start_frame_index,\n ),\n };\n }\n\n private numberOrUndefined(value: unknown): number | undefined {\n return typeof value === \"number\" && Number.isFinite(value)\n ? value\n : undefined;\n }\n\n /**\n * Public entry point for WebSocket transport to inject messages into the same pipeline.\n */\n handleDataReceivedPublic(payload: Uint8Array): void {\n this.handleDataReceived(payload, null, \"websocket\");\n }\n\n /**\n * Reset message state\n */\n reset(): void {\n this.chatMessages = [];\n this.activeBotLlmMessageId = null;\n this.userTranscription = \"\";\n this.isBotResponding = false;\n this.isSpeaking = false;\n this.isListening = false;\n this.totalBlendshapesReceived = 0;\n this._currentEmotion = null;\n this.blendshapeQueue.reset();\n this.emit(\"messagesChange\", this.chatMessages);\n this.emit(\"userTranscriptionChange\", \"\");\n this.emit(\"botRespondingChange\", false);\n this.emit(\"speakingChange\", false);\n this.emit(\"listeningChange\", false);\n this.emit(\"emotionChange\", null);\n }\n}\n"]}
@@ -0,0 +1,44 @@
1
+ import type { ConvaiConfig } from "./types";
2
+ export interface SSESessionOptions {
3
+ interactionApiUrl: string;
4
+ authorization: string;
5
+ characterId: string;
6
+ getCharacterSessionId: () => string | null;
7
+ onCharacterSessionId: (characterSessionId: string) => void;
8
+ endUserId?: string;
9
+ endUserMetadata?: Record<string, unknown>;
10
+ takeStateOfMind: () => string | null;
11
+ enableEmotion?: ConvaiConfig["enableEmotion"];
12
+ emotionConfig?: ConvaiConfig["emotionConfig"];
13
+ actionConfig?: ConvaiConfig["actionConfig"];
14
+ debug?: boolean;
15
+ onMessage: (payload: Uint8Array) => void;
16
+ onError: (error: unknown) => void;
17
+ }
18
+ export interface SSEMessage {
19
+ type: string;
20
+ data: unknown;
21
+ id?: string;
22
+ }
23
+ /** Text-only interaction transport. One POST/SSE stream is used per message. */
24
+ export declare class SSESession {
25
+ private readonly options;
26
+ private static readonly BOT_LLM_TEXT_FLUSH_MS;
27
+ private connected;
28
+ private abortController;
29
+ private queue;
30
+ private pendingBotLlmText;
31
+ private botLlmTextFlushTimer;
32
+ constructor(options: SSESessionOptions);
33
+ get isConnected(): boolean;
34
+ connect(): void;
35
+ sendMessage(type: string, data: unknown, id?: string): void;
36
+ sendMessages(messages: SSEMessage[]): void;
37
+ disconnect(): Promise<void>;
38
+ private sendInteraction;
39
+ private readEvents;
40
+ private queueBotLlmText;
41
+ private flushBotLlmText;
42
+ private clearPendingBotLlmText;
43
+ }
44
+ //# sourceMappingURL=SSESession.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SSESession.d.ts","sourceRoot":"","sources":["../../src/core/SSESession.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAM5C,MAAM,WAAW,iBAAiB;IAChC,iBAAiB,EAAE,MAAM,CAAC;IAC1B,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,qBAAqB,EAAE,MAAM,MAAM,GAAG,IAAI,CAAC;IAC3C,oBAAoB,EAAE,CAAC,kBAAkB,EAAE,MAAM,KAAK,IAAI,CAAC;IAC3D,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC1C,eAAe,EAAE,MAAM,MAAM,GAAG,IAAI,CAAC;IACrC,aAAa,CAAC,EAAE,YAAY,CAAC,eAAe,CAAC,CAAC;IAC9C,aAAa,CAAC,EAAE,YAAY,CAAC,eAAe,CAAC,CAAC;IAC9C,YAAY,CAAC,EAAE,YAAY,CAAC,cAAc,CAAC,CAAC;IAC5C,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,SAAS,EAAE,CAAC,OAAO,EAAE,UAAU,KAAK,IAAI,CAAC;IACzC,OAAO,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;CACnC;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,OAAO,CAAC;IACd,EAAE,CAAC,EAAE,MAAM,CAAC;CACb;AAED,gFAAgF;AAChF,qBAAa,UAAU;IAQT,OAAO,CAAC,QAAQ,CAAC,OAAO;IAPpC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,qBAAqB,CAAM;IACnD,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,eAAe,CAAgC;IACvD,OAAO,CAAC,KAAK,CAAoC;IACjD,OAAO,CAAC,iBAAiB,CAAM;IAC/B,OAAO,CAAC,oBAAoB,CAA8C;gBAE7C,OAAO,EAAE,iBAAiB;IAEvD,IAAI,WAAW,IAAI,OAAO,CAEzB;IAED,OAAO,IAAI,IAAI;IAIf,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,CAAC,EAAE,MAAM,GAAG,IAAI;IAI3D,YAAY,CAAC,QAAQ,EAAE,UAAU,EAAE,GAAG,IAAI;IAYpC,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;YAQnB,eAAe;YA4Df,UAAU;IAqExB,OAAO,CAAC,eAAe;IASvB,OAAO,CAAC,eAAe;IAevB,OAAO,CAAC,sBAAsB;CAO/B"}
@@ -0,0 +1,200 @@
1
+ import { buildActionConnectConfig, buildEmotionConnectConfig, } from "./connectRequest";
2
+ /** Text-only interaction transport. One POST/SSE stream is used per message. */
3
+ export class SSESession {
4
+ constructor(options) {
5
+ this.options = options;
6
+ this.connected = false;
7
+ this.abortController = null;
8
+ this.queue = Promise.resolve();
9
+ this.pendingBotLlmText = "";
10
+ this.botLlmTextFlushTimer = null;
11
+ }
12
+ get isConnected() {
13
+ return this.connected;
14
+ }
15
+ connect() {
16
+ this.connected = true;
17
+ }
18
+ sendMessage(type, data, id) {
19
+ this.sendMessages([{ type, data, ...(id !== undefined ? { id } : {}) }]);
20
+ }
21
+ sendMessages(messages) {
22
+ if (messages.length === 0)
23
+ return;
24
+ this.queue = this.queue
25
+ .then(() => {
26
+ if (!this.connected)
27
+ return;
28
+ return this.sendInteraction(messages, this.options.takeStateOfMind());
29
+ })
30
+ .catch((error) => {
31
+ if (!isAbortError(error))
32
+ this.options.onError(error);
33
+ });
34
+ }
35
+ async disconnect() {
36
+ this.connected = false;
37
+ this.abortController?.abort();
38
+ await this.queue;
39
+ this.clearPendingBotLlmText();
40
+ this.abortController = null;
41
+ }
42
+ async sendInteraction(messages, stateOfMind) {
43
+ const controller = new AbortController();
44
+ this.abortController = controller;
45
+ try {
46
+ const characterSessionId = this.options.getCharacterSessionId();
47
+ const response = await fetch(this.options.interactionApiUrl, {
48
+ method: "POST",
49
+ headers: {
50
+ Authorization: `Bearer ${this.options.authorization}`,
51
+ Accept: "text/event-stream",
52
+ "Content-Type": "application/json",
53
+ },
54
+ body: JSON.stringify({
55
+ character_id: this.options.characterId,
56
+ ...(stateOfMind ? { state_of_mind: stateOfMind } : {}),
57
+ ...(characterSessionId && characterSessionId !== "-1"
58
+ ? { character_session_id: characterSessionId }
59
+ : {}),
60
+ ...(this.options.endUserId
61
+ ? { end_user_id: this.options.endUserId }
62
+ : {}),
63
+ ...(this.options.endUserMetadata
64
+ ? { end_user_metadata: this.options.endUserMetadata }
65
+ : {}),
66
+ ...(buildEmotionConnectConfig(this.options) && {
67
+ emotion_config: buildEmotionConnectConfig(this.options),
68
+ }),
69
+ ...(buildActionConnectConfig(this.options) && {
70
+ action_config: buildActionConnectConfig(this.options),
71
+ }),
72
+ ...(this.options.debug !== undefined
73
+ ? { debug: this.options.debug }
74
+ : {}),
75
+ messages: messages.map(({ type, data, id }) => ({
76
+ label: "rtvi-ai",
77
+ type,
78
+ ...(id !== undefined ? { id } : {}),
79
+ data,
80
+ })),
81
+ }),
82
+ signal: controller.signal,
83
+ });
84
+ if (!response.ok) {
85
+ const text = await response.text();
86
+ throw new Error(`Interaction API HTTP ${response.status}${text ? `: ${text}` : ""}`);
87
+ }
88
+ if (!response.body)
89
+ throw new Error("Interaction API returned no SSE body");
90
+ await this.readEvents(response.body, controller.signal);
91
+ }
92
+ finally {
93
+ if (this.abortController === controller)
94
+ this.abortController = null;
95
+ }
96
+ }
97
+ async readEvents(body, signal) {
98
+ const reader = body.getReader();
99
+ const decoder = new TextDecoder();
100
+ let buffer = "";
101
+ let eventType = "message";
102
+ let eventData = [];
103
+ const dispatch = () => {
104
+ if (eventData.length === 0)
105
+ return;
106
+ const dataText = eventData.join("\n");
107
+ let data = dataText;
108
+ try {
109
+ data = JSON.parse(dataText);
110
+ }
111
+ catch {
112
+ // SSE data is JSON for the interaction API; preserve malformed data for diagnostics.
113
+ }
114
+ if (eventType === "bot-llm-text" &&
115
+ typeof data === "object" &&
116
+ data !== null &&
117
+ typeof data.text === "string") {
118
+ this.queueBotLlmText(data.text);
119
+ eventType = "message";
120
+ eventData = [];
121
+ return;
122
+ }
123
+ this.flushBotLlmText();
124
+ if (eventType === "session" || eventType === "done") {
125
+ const sessionId = data
126
+ ?.character_session_id;
127
+ if (typeof sessionId === "string")
128
+ this.options.onCharacterSessionId(sessionId);
129
+ }
130
+ else {
131
+ if (eventType === "error")
132
+ this.options.onError(data);
133
+ this.options.onMessage(new TextEncoder().encode(JSON.stringify({ type: eventType, data })));
134
+ }
135
+ eventType = "message";
136
+ eventData = [];
137
+ };
138
+ while (!signal.aborted) {
139
+ const { done, value } = await reader.read();
140
+ buffer += decoder.decode(value, { stream: !done });
141
+ const lines = buffer.split(/\r?\n/);
142
+ buffer = lines.pop() ?? "";
143
+ for (const line of lines) {
144
+ if (!line)
145
+ dispatch();
146
+ else if (line.startsWith("event:"))
147
+ eventType = line.slice(6).trim();
148
+ else if (line.startsWith("data:")) {
149
+ eventData.push(line.slice(5).trimStart());
150
+ }
151
+ }
152
+ if (done) {
153
+ if (buffer) {
154
+ if (buffer.startsWith("event:"))
155
+ eventType = buffer.slice(6).trim();
156
+ else if (buffer.startsWith("data:"))
157
+ eventData.push(buffer.slice(5).trimStart());
158
+ }
159
+ dispatch();
160
+ this.flushBotLlmText();
161
+ return;
162
+ }
163
+ }
164
+ }
165
+ queueBotLlmText(text) {
166
+ this.pendingBotLlmText += text;
167
+ if (this.botLlmTextFlushTimer !== null)
168
+ return;
169
+ this.botLlmTextFlushTimer = setTimeout(() => {
170
+ this.botLlmTextFlushTimer = null;
171
+ this.flushBotLlmText();
172
+ }, SSESession.BOT_LLM_TEXT_FLUSH_MS);
173
+ }
174
+ flushBotLlmText() {
175
+ if (this.botLlmTextFlushTimer !== null) {
176
+ clearTimeout(this.botLlmTextFlushTimer);
177
+ this.botLlmTextFlushTimer = null;
178
+ }
179
+ if (!this.pendingBotLlmText)
180
+ return;
181
+ const text = this.pendingBotLlmText;
182
+ this.pendingBotLlmText = "";
183
+ this.options.onMessage(new TextEncoder().encode(JSON.stringify({ type: "bot-llm-text", data: { text } })));
184
+ }
185
+ clearPendingBotLlmText() {
186
+ if (this.botLlmTextFlushTimer !== null) {
187
+ clearTimeout(this.botLlmTextFlushTimer);
188
+ this.botLlmTextFlushTimer = null;
189
+ }
190
+ this.pendingBotLlmText = "";
191
+ }
192
+ }
193
+ SSESession.BOT_LLM_TEXT_FLUSH_MS = 16;
194
+ function isAbortError(error) {
195
+ return (typeof error === "object" &&
196
+ error !== null &&
197
+ "name" in error &&
198
+ error.name === "AbortError");
199
+ }
200
+ //# sourceMappingURL=SSESession.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SSESession.js","sourceRoot":"","sources":["../../src/core/SSESession.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ConvaiConfig } from \"./types\";\nimport {\n buildActionConnectConfig,\n buildEmotionConnectConfig,\n} from \"./connectRequest\";\n\nexport interface SSESessionOptions {\n interactionApiUrl: string;\n authorization: string;\n characterId: string;\n getCharacterSessionId: () => string | null;\n onCharacterSessionId: (characterSessionId: string) => void;\n endUserId?: string;\n endUserMetadata?: Record<string, unknown>;\n takeStateOfMind: () => string | null;\n enableEmotion?: ConvaiConfig[\"enableEmotion\"];\n emotionConfig?: ConvaiConfig[\"emotionConfig\"];\n actionConfig?: ConvaiConfig[\"actionConfig\"];\n debug?: boolean;\n onMessage: (payload: Uint8Array) => void;\n onError: (error: unknown) => void;\n}\n\nexport interface SSEMessage {\n type: string;\n data: unknown;\n id?: string;\n}\n\n/** Text-only interaction transport. One POST/SSE stream is used per message. */\nexport class SSESession {\n private static readonly BOT_LLM_TEXT_FLUSH_MS = 16;\n private connected = false;\n private abortController: AbortController | null = null;\n private queue: Promise<void> = Promise.resolve();\n private pendingBotLlmText = \"\";\n private botLlmTextFlushTimer: ReturnType<typeof setTimeout> | null = null;\n\n constructor(private readonly options: SSESessionOptions) {}\n\n get isConnected(): boolean {\n return this.connected;\n }\n\n connect(): void {\n this.connected = true;\n }\n\n sendMessage(type: string, data: unknown, id?: string): void {\n this.sendMessages([{ type, data, ...(id !== undefined ? { id } : {}) }]);\n }\n\n sendMessages(messages: SSEMessage[]): void {\n if (messages.length === 0) return;\n this.queue = this.queue\n .then(() => {\n if (!this.connected) return;\n return this.sendInteraction(messages, this.options.takeStateOfMind());\n })\n .catch((error: unknown) => {\n if (!isAbortError(error)) this.options.onError(error);\n });\n }\n\n async disconnect(): Promise<void> {\n this.connected = false;\n this.abortController?.abort();\n await this.queue;\n this.clearPendingBotLlmText();\n this.abortController = null;\n }\n\n private async sendInteraction(\n messages: SSEMessage[],\n stateOfMind: string | null,\n ): Promise<void> {\n const controller = new AbortController();\n this.abortController = controller;\n try {\n const characterSessionId = this.options.getCharacterSessionId();\n const response = await fetch(this.options.interactionApiUrl, {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${this.options.authorization}`,\n Accept: \"text/event-stream\",\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({\n character_id: this.options.characterId,\n ...(stateOfMind ? { state_of_mind: stateOfMind } : {}),\n ...(characterSessionId && characterSessionId !== \"-1\"\n ? { character_session_id: characterSessionId }\n : {}),\n ...(this.options.endUserId\n ? { end_user_id: this.options.endUserId }\n : {}),\n ...(this.options.endUserMetadata\n ? { end_user_metadata: this.options.endUserMetadata }\n : {}),\n ...(buildEmotionConnectConfig(this.options) && {\n emotion_config: buildEmotionConnectConfig(this.options),\n }),\n ...(buildActionConnectConfig(this.options) && {\n action_config: buildActionConnectConfig(this.options),\n }),\n ...(this.options.debug !== undefined\n ? { debug: this.options.debug }\n : {}),\n messages: messages.map(({ type, data, id }) => ({\n label: \"rtvi-ai\",\n type,\n ...(id !== undefined ? { id } : {}),\n data,\n })),\n }),\n signal: controller.signal,\n });\n\n if (!response.ok) {\n const text = await response.text();\n throw new Error(\n `Interaction API HTTP ${response.status}${text ? `: ${text}` : \"\"}`,\n );\n }\n if (!response.body) throw new Error(\"Interaction API returned no SSE body\");\n\n await this.readEvents(response.body, controller.signal);\n } finally {\n if (this.abortController === controller) this.abortController = null;\n }\n }\n\n private async readEvents(\n body: ReadableStream<Uint8Array>,\n signal: AbortSignal,\n ): Promise<void> {\n const reader = body.getReader();\n const decoder = new TextDecoder();\n let buffer = \"\";\n let eventType = \"message\";\n let eventData: string[] = [];\n\n const dispatch = () => {\n if (eventData.length === 0) return;\n const dataText = eventData.join(\"\\n\");\n let data: unknown = dataText;\n try {\n data = JSON.parse(dataText);\n } catch {\n // SSE data is JSON for the interaction API; preserve malformed data for diagnostics.\n }\n if (\n eventType === \"bot-llm-text\" &&\n typeof data === \"object\" &&\n data !== null &&\n typeof (data as { text?: unknown }).text === \"string\"\n ) {\n this.queueBotLlmText((data as { text: string }).text);\n eventType = \"message\";\n eventData = [];\n return;\n }\n this.flushBotLlmText();\n if (eventType === \"session\" || eventType === \"done\") {\n const sessionId = (data as { character_session_id?: unknown })\n ?.character_session_id;\n if (typeof sessionId === \"string\") this.options.onCharacterSessionId(sessionId);\n } else {\n if (eventType === \"error\") this.options.onError(data);\n this.options.onMessage(\n new TextEncoder().encode(JSON.stringify({ type: eventType, data })),\n );\n }\n eventType = \"message\";\n eventData = [];\n };\n\n while (!signal.aborted) {\n const { done, value } = await reader.read();\n buffer += decoder.decode(value, { stream: !done });\n const lines = buffer.split(/\\r?\\n/);\n buffer = lines.pop() ?? \"\";\n for (const line of lines) {\n if (!line) dispatch();\n else if (line.startsWith(\"event:\")) eventType = line.slice(6).trim();\n else if (line.startsWith(\"data:\")) {\n eventData.push(line.slice(5).trimStart());\n }\n }\n if (done) {\n if (buffer) {\n if (buffer.startsWith(\"event:\")) eventType = buffer.slice(6).trim();\n else if (buffer.startsWith(\"data:\")) eventData.push(buffer.slice(5).trimStart());\n }\n dispatch();\n this.flushBotLlmText();\n return;\n }\n }\n }\n\n private queueBotLlmText(text: string): void {\n this.pendingBotLlmText += text;\n if (this.botLlmTextFlushTimer !== null) return;\n this.botLlmTextFlushTimer = setTimeout(() => {\n this.botLlmTextFlushTimer = null;\n this.flushBotLlmText();\n }, SSESession.BOT_LLM_TEXT_FLUSH_MS);\n }\n\n private flushBotLlmText(): void {\n if (this.botLlmTextFlushTimer !== null) {\n clearTimeout(this.botLlmTextFlushTimer);\n this.botLlmTextFlushTimer = null;\n }\n if (!this.pendingBotLlmText) return;\n const text = this.pendingBotLlmText;\n this.pendingBotLlmText = \"\";\n this.options.onMessage(\n new TextEncoder().encode(\n JSON.stringify({ type: \"bot-llm-text\", data: { text } }),\n ),\n );\n }\n\n private clearPendingBotLlmText(): void {\n if (this.botLlmTextFlushTimer !== null) {\n clearTimeout(this.botLlmTextFlushTimer);\n this.botLlmTextFlushTimer = null;\n }\n this.pendingBotLlmText = \"\";\n }\n}\n\nfunction isAbortError(error: unknown): boolean {\n return (\n typeof error === \"object\" &&\n error !== null &&\n \"name\" in error &&\n error.name === \"AbortError\"\n );\n}\n"]}
@@ -19,4 +19,6 @@ export interface BlendshapeConnectRequestConfig {
19
19
  * to the legacy paced path with deliver_chunks_ahead: false.
20
20
  */
21
21
  export declare function buildBlendshapeConnectConfig(config: Pick<ConvaiConfig, "enableLipsync" | "blendshapeConfig">): BlendshapeConnectRequestConfig;
22
+ export declare function buildEmotionConnectConfig(config: Pick<ConvaiConfig, "enableEmotion" | "emotionConfig">): Record<string, unknown> | undefined;
23
+ export declare function buildActionConnectConfig(config: Pick<ConvaiConfig, "actionConfig">): ConvaiConfig["actionConfig"] | undefined;
22
24
  //# sourceMappingURL=connectRequest.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"connectRequest.d.ts","sourceRoot":"","sources":["../../src/core/connectRequest.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAE5C,MAAM,WAAW,8BAA8B;IAC7C,mBAAmB,EAAE,WAAW,GAAG,cAAc,CAAC;IAClD,iBAAiB,EAAE;QACjB,eAAe,EAAE,IAAI,CAAC;QACtB,UAAU,EAAE,MAAM,CAAC;QACnB,MAAM,EAAE,OAAO,GAAG,KAAK,GAAG,cAAc,GAAG,QAAQ,GAAG,SAAS,CAAC;QAChE,sBAAsB,EAAE,MAAM,CAAC;QAC/B,UAAU,EAAE,MAAM,CAAC;QACnB,oBAAoB,CAAC,EAAE,IAAI,CAAC;KAC7B,CAAC;CACH;AAED;;;;;;;GAOG;AACH,wBAAgB,4BAA4B,CAC1C,MAAM,EAAE,IAAI,CAAC,YAAY,EAAE,eAAe,GAAG,kBAAkB,CAAC,GAC/D,8BAA8B,CAuBhC"}
1
+ {"version":3,"file":"connectRequest.d.ts","sourceRoot":"","sources":["../../src/core/connectRequest.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAE5C,MAAM,WAAW,8BAA8B;IAC7C,mBAAmB,EAAE,WAAW,GAAG,cAAc,CAAC;IAClD,iBAAiB,EAAE;QACjB,eAAe,EAAE,IAAI,CAAC;QACtB,UAAU,EAAE,MAAM,CAAC;QACnB,MAAM,EAAE,OAAO,GAAG,KAAK,GAAG,cAAc,GAAG,QAAQ,GAAG,SAAS,CAAC;QAChE,sBAAsB,EAAE,MAAM,CAAC;QAC/B,UAAU,EAAE,MAAM,CAAC;QACnB,oBAAoB,CAAC,EAAE,IAAI,CAAC;KAC7B,CAAC;CACH;AAED;;;;;;;GAOG;AACH,wBAAgB,4BAA4B,CAC1C,MAAM,EAAE,IAAI,CAAC,YAAY,EAAE,eAAe,GAAG,kBAAkB,CAAC,GAC/D,8BAA8B,CAuBhC;AAED,wBAAgB,yBAAyB,CACvC,MAAM,EAAE,IAAI,CAAC,YAAY,EAAE,eAAe,GAAG,eAAe,CAAC,GAC5D,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAYrC;AAED,wBAAgB,wBAAwB,CACtC,MAAM,EAAE,IAAI,CAAC,YAAY,EAAE,cAAc,CAAC,GACzC,YAAY,CAAC,cAAc,CAAC,GAAG,SAAS,CAW1C"}
@@ -27,4 +27,31 @@ export function buildBlendshapeConnectConfig(config) {
27
27
  },
28
28
  };
29
29
  }
30
+ export function buildEmotionConnectConfig(config) {
31
+ if (config.enableEmotion !== true)
32
+ return undefined;
33
+ const emotionConfig = config.emotionConfig;
34
+ if (emotionConfig?.provider === "nrclex") {
35
+ return {
36
+ provider: emotionConfig.provider,
37
+ min_word_threshold: emotionConfig.min_word_threshold ?? 3,
38
+ low_intensity_threshold: emotionConfig.low_intensity_threshold ?? 0.33,
39
+ high_intensity_threshold: emotionConfig.high_intensity_threshold ?? 0.66,
40
+ };
41
+ }
42
+ return { provider: emotionConfig?.provider ?? "llm" };
43
+ }
44
+ export function buildActionConnectConfig(config) {
45
+ const actionConfig = config.actionConfig;
46
+ if (!actionConfig)
47
+ return undefined;
48
+ return {
49
+ actions: actionConfig.actions,
50
+ objects: actionConfig.objects,
51
+ characters: actionConfig.characters,
52
+ ...(actionConfig.current_attention_object && {
53
+ current_attention_object: actionConfig.current_attention_object,
54
+ }),
55
+ };
56
+ }
30
57
  //# sourceMappingURL=connectRequest.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"connectRequest.js","sourceRoot":"","sources":["../../src/core/connectRequest.ts"],"names":[],"mappings":"AAcA;;;;;;;GAOG;AACH,MAAM,UAAU,4BAA4B,CAC1C,MAAgE;IAEhE,MAAM,kBAAkB,GACtB,MAAM,CAAC,aAAa,KAAK,IAAI;QAC7B,MAAM,CAAC,gBAAgB,EAAE,oBAAoB,KAAK,KAAK,CAAC;IAE1D,OAAO;QACL,mBAAmB,EAAE,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,cAAc;QACxE,iBAAiB,EAAE;YACjB,eAAe,EAAE,IAAI;YACrB,UAAU,EAAE,EAAE;YACd,MAAM,EAAE,MAAM,CAAC,gBAAgB,EAAE,MAAM,IAAI,KAAK;YAChD,sBAAsB,EACpB,MAAM,CAAC,gBAAgB,EAAE,sBAAsB,IAAI,GAAG;YACxD,yEAAyE;YACzE,qEAAqE;YACrE,wEAAwE;YACxE,gBAAgB;YAChB,UAAU,EAAE,kBAAkB;gBAC5B,CAAC,CAAC,MAAM,CAAC,gBAAgB,EAAE,UAAU,IAAI,EAAE;gBAC3C,CAAC,CAAC,EAAE;YACN,GAAG,CAAC,kBAAkB,CAAC,CAAC,CAAC,EAAE,oBAAoB,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SAC9D;KACF,CAAC;AACJ,CAAC","sourcesContent":["import type { ConvaiConfig } from \"./types\";\n\nexport interface BlendshapeConnectRequestConfig {\n blendshape_provider: \"neurosync\" | \"not_provided\";\n blendshape_config: {\n enable_chunking: true;\n chunk_size: number;\n format: \"arkit\" | \"mha\" | \"cc4_extended\" | \"cc5_hd\" | \"visemes\";\n frames_buffer_duration: number;\n output_fps: number;\n deliver_chunks_ahead?: true;\n };\n}\n\n/**\n * Build the lipsync part of the /connect request.\n *\n * Ahead-delivery changes the client contract because frames can arrive before\n * bot-started-speaking and cancellation must be handled with owner metadata.\n * It is the default now that server support is verified; callers can fall back\n * to the legacy paced path with deliver_chunks_ahead: false.\n */\nexport function buildBlendshapeConnectConfig(\n config: Pick<ConvaiConfig, \"enableLipsync\" | \"blendshapeConfig\">,\n): BlendshapeConnectRequestConfig {\n const deliverChunksAhead =\n config.enableLipsync === true &&\n config.blendshapeConfig?.deliver_chunks_ahead !== false;\n\n return {\n blendshape_provider: config.enableLipsync ? \"neurosync\" : \"not_provided\",\n blendshape_config: {\n enable_chunking: true,\n chunk_size: 10,\n format: config.blendshapeConfig?.format || \"mha\",\n frames_buffer_duration:\n config.blendshapeConfig?.frames_buffer_duration ?? 0.1,\n // In the legacy paced path, output_fps is a delivery cadence and the SDK\n // player keeps its 60fps visual timeline. Only ahead-delivery treats\n // output_fps as a client-visible timeline override because chunks carry\n // fps metadata.\n output_fps: deliverChunksAhead\n ? config.blendshapeConfig?.output_fps ?? 60\n : 90,\n ...(deliverChunksAhead ? { deliver_chunks_ahead: true } : {}),\n },\n };\n}\n"]}
1
+ {"version":3,"file":"connectRequest.js","sourceRoot":"","sources":["../../src/core/connectRequest.ts"],"names":[],"mappings":"AAcA;;;;;;;GAOG;AACH,MAAM,UAAU,4BAA4B,CAC1C,MAAgE;IAEhE,MAAM,kBAAkB,GACtB,MAAM,CAAC,aAAa,KAAK,IAAI;QAC7B,MAAM,CAAC,gBAAgB,EAAE,oBAAoB,KAAK,KAAK,CAAC;IAE1D,OAAO;QACL,mBAAmB,EAAE,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,cAAc;QACxE,iBAAiB,EAAE;YACjB,eAAe,EAAE,IAAI;YACrB,UAAU,EAAE,EAAE;YACd,MAAM,EAAE,MAAM,CAAC,gBAAgB,EAAE,MAAM,IAAI,KAAK;YAChD,sBAAsB,EACpB,MAAM,CAAC,gBAAgB,EAAE,sBAAsB,IAAI,GAAG;YACxD,yEAAyE;YACzE,qEAAqE;YACrE,wEAAwE;YACxE,gBAAgB;YAChB,UAAU,EAAE,kBAAkB;gBAC5B,CAAC,CAAC,MAAM,CAAC,gBAAgB,EAAE,UAAU,IAAI,EAAE;gBAC3C,CAAC,CAAC,EAAE;YACN,GAAG,CAAC,kBAAkB,CAAC,CAAC,CAAC,EAAE,oBAAoB,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SAC9D;KACF,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,yBAAyB,CACvC,MAA6D;IAE7D,IAAI,MAAM,CAAC,aAAa,KAAK,IAAI;QAAE,OAAO,SAAS,CAAC;IACpD,MAAM,aAAa,GAAG,MAAM,CAAC,aAAa,CAAC;IAC3C,IAAI,aAAa,EAAE,QAAQ,KAAK,QAAQ,EAAE,CAAC;QACzC,OAAO;YACL,QAAQ,EAAE,aAAa,CAAC,QAAQ;YAChC,kBAAkB,EAAE,aAAa,CAAC,kBAAkB,IAAI,CAAC;YACzD,uBAAuB,EAAE,aAAa,CAAC,uBAAuB,IAAI,IAAI;YACtE,wBAAwB,EAAE,aAAa,CAAC,wBAAwB,IAAI,IAAI;SACzE,CAAC;IACJ,CAAC;IACD,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,QAAQ,IAAI,KAAK,EAAE,CAAC;AACxD,CAAC;AAED,MAAM,UAAU,wBAAwB,CACtC,MAA0C;IAE1C,MAAM,YAAY,GAAG,MAAM,CAAC,YAAY,CAAC;IACzC,IAAI,CAAC,YAAY;QAAE,OAAO,SAAS,CAAC;IACpC,OAAO;QACL,OAAO,EAAE,YAAY,CAAC,OAAO;QAC7B,OAAO,EAAE,YAAY,CAAC,OAAO;QAC7B,UAAU,EAAE,YAAY,CAAC,UAAU;QACnC,GAAG,CAAC,YAAY,CAAC,wBAAwB,IAAI;YAC3C,wBAAwB,EAAE,YAAY,CAAC,wBAAwB;SAChE,CAAC;KACH,CAAC;AACJ,CAAC","sourcesContent":["import type { ConvaiConfig } from \"./types\";\n\nexport interface BlendshapeConnectRequestConfig {\n blendshape_provider: \"neurosync\" | \"not_provided\";\n blendshape_config: {\n enable_chunking: true;\n chunk_size: number;\n format: \"arkit\" | \"mha\" | \"cc4_extended\" | \"cc5_hd\" | \"visemes\";\n frames_buffer_duration: number;\n output_fps: number;\n deliver_chunks_ahead?: true;\n };\n}\n\n/**\n * Build the lipsync part of the /connect request.\n *\n * Ahead-delivery changes the client contract because frames can arrive before\n * bot-started-speaking and cancellation must be handled with owner metadata.\n * It is the default now that server support is verified; callers can fall back\n * to the legacy paced path with deliver_chunks_ahead: false.\n */\nexport function buildBlendshapeConnectConfig(\n config: Pick<ConvaiConfig, \"enableLipsync\" | \"blendshapeConfig\">,\n): BlendshapeConnectRequestConfig {\n const deliverChunksAhead =\n config.enableLipsync === true &&\n config.blendshapeConfig?.deliver_chunks_ahead !== false;\n\n return {\n blendshape_provider: config.enableLipsync ? \"neurosync\" : \"not_provided\",\n blendshape_config: {\n enable_chunking: true,\n chunk_size: 10,\n format: config.blendshapeConfig?.format || \"mha\",\n frames_buffer_duration:\n config.blendshapeConfig?.frames_buffer_duration ?? 0.1,\n // In the legacy paced path, output_fps is a delivery cadence and the SDK\n // player keeps its 60fps visual timeline. Only ahead-delivery treats\n // output_fps as a client-visible timeline override because chunks carry\n // fps metadata.\n output_fps: deliverChunksAhead\n ? config.blendshapeConfig?.output_fps ?? 60\n : 90,\n ...(deliverChunksAhead ? { deliver_chunks_ahead: true } : {}),\n },\n };\n}\n\nexport function buildEmotionConnectConfig(\n config: Pick<ConvaiConfig, \"enableEmotion\" | \"emotionConfig\">,\n): Record<string, unknown> | undefined {\n if (config.enableEmotion !== true) return undefined;\n const emotionConfig = config.emotionConfig;\n if (emotionConfig?.provider === \"nrclex\") {\n return {\n provider: emotionConfig.provider,\n min_word_threshold: emotionConfig.min_word_threshold ?? 3,\n low_intensity_threshold: emotionConfig.low_intensity_threshold ?? 0.33,\n high_intensity_threshold: emotionConfig.high_intensity_threshold ?? 0.66,\n };\n }\n return { provider: emotionConfig?.provider ?? \"llm\" };\n}\n\nexport function buildActionConnectConfig(\n config: Pick<ConvaiConfig, \"actionConfig\">,\n): ConvaiConfig[\"actionConfig\"] | undefined {\n const actionConfig = config.actionConfig;\n if (!actionConfig) return undefined;\n return {\n actions: actionConfig.actions,\n objects: actionConfig.objects,\n characters: actionConfig.characters,\n ...(actionConfig.current_attention_object && {\n current_attention_object: actionConfig.current_attention_object,\n }),\n };\n}\n"]}
@@ -0,0 +1,5 @@
1
+ /** Maximum wire size for a logical turn identifier, in UTF-8 bytes. */
2
+ export declare const LOGICAL_TURN_ID_MAX_UTF8_BYTES = 128;
3
+ /** Return whether a logical turn identifier is safe to place on the wire. */
4
+ export declare function isValidLogicalTurnId(value: unknown): value is string;
5
+ //# sourceMappingURL=logicalTurn.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logicalTurn.d.ts","sourceRoot":"","sources":["../../src/core/logicalTurn.ts"],"names":[],"mappings":"AAAA,uEAAuE;AACvE,eAAO,MAAM,8BAA8B,MAAM,CAAC;AAElD,6EAA6E;AAC7E,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,MAAM,CAOpE"}
@@ -0,0 +1,10 @@
1
+ /** Maximum wire size for a logical turn identifier, in UTF-8 bytes. */
2
+ export const LOGICAL_TURN_ID_MAX_UTF8_BYTES = 128;
3
+ /** Return whether a logical turn identifier is safe to place on the wire. */
4
+ export function isValidLogicalTurnId(value) {
5
+ return (typeof value === "string" &&
6
+ value.trim().length > 0 &&
7
+ value.length <= LOGICAL_TURN_ID_MAX_UTF8_BYTES &&
8
+ new TextEncoder().encode(value).byteLength <= LOGICAL_TURN_ID_MAX_UTF8_BYTES);
9
+ }
10
+ //# sourceMappingURL=logicalTurn.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logicalTurn.js","sourceRoot":"","sources":["../../src/core/logicalTurn.ts"],"names":[],"mappings":"AAAA,uEAAuE;AACvE,MAAM,CAAC,MAAM,8BAA8B,GAAG,GAAG,CAAC;AAElD,6EAA6E;AAC7E,MAAM,UAAU,oBAAoB,CAAC,KAAc;IACjD,OAAO,CACL,OAAO,KAAK,KAAK,QAAQ;QACzB,KAAK,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC;QACvB,KAAK,CAAC,MAAM,IAAI,8BAA8B;QAC9C,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,UAAU,IAAI,8BAA8B,CAC7E,CAAC;AACJ,CAAC","sourcesContent":["/** Maximum wire size for a logical turn identifier, in UTF-8 bytes. */\nexport const LOGICAL_TURN_ID_MAX_UTF8_BYTES = 128;\n\n/** Return whether a logical turn identifier is safe to place on the wire. */\nexport function isValidLogicalTurnId(value: unknown): value is string {\n return (\n typeof value === \"string\" &&\n value.trim().length > 0 &&\n value.length <= LOGICAL_TURN_ID_MAX_UTF8_BYTES &&\n new TextEncoder().encode(value).byteLength <= LOGICAL_TURN_ID_MAX_UTF8_BYTES\n );\n}\n"]}