@applica-software-guru/persona-sdk 0.0.1-preview2 → 0.0.1-preview4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (76) hide show
  1. package/dist/bundle.cjs.js.map +1 -1
  2. package/dist/bundle.es.js.map +1 -1
  3. package/dist/bundle.iife.js.map +1 -1
  4. package/dist/bundle.umd.js.map +1 -1
  5. package/dist/playground/src/app.d.ts +3 -0
  6. package/dist/playground/src/app.d.ts.map +1 -0
  7. package/dist/playground/src/app.js +5 -0
  8. package/dist/playground/src/chat.d.ts +3 -0
  9. package/dist/playground/src/chat.d.ts.map +1 -0
  10. package/dist/playground/src/chat.js +33 -0
  11. package/dist/playground/src/components/assistant-ui/assistant-modal.d.ts +3 -0
  12. package/dist/playground/src/components/assistant-ui/assistant-modal.d.ts.map +1 -0
  13. package/dist/playground/src/components/assistant-ui/assistant-modal.js +15 -0
  14. package/dist/playground/src/components/assistant-ui/markdown-text.d.ts +3 -0
  15. package/dist/playground/src/components/assistant-ui/markdown-text.d.ts.map +1 -0
  16. package/dist/playground/src/components/assistant-ui/markdown-text.js +59 -0
  17. package/dist/playground/src/components/assistant-ui/thread-list.d.ts +3 -0
  18. package/dist/playground/src/components/assistant-ui/thread-list.d.ts.map +1 -0
  19. package/dist/playground/src/components/assistant-ui/thread-list.js +23 -0
  20. package/dist/playground/src/components/assistant-ui/thread.d.ts +3 -0
  21. package/dist/playground/src/components/assistant-ui/thread.d.ts.map +1 -0
  22. package/dist/playground/src/components/assistant-ui/thread.js +75 -0
  23. package/dist/playground/src/components/assistant-ui/tool-fallback.d.ts +3 -0
  24. package/dist/playground/src/components/assistant-ui/tool-fallback.d.ts.map +1 -0
  25. package/dist/playground/src/components/assistant-ui/tool-fallback.js +8 -0
  26. package/dist/playground/src/components/assistant-ui/tooltip-icon-button.d.ts +11 -0
  27. package/dist/playground/src/components/assistant-ui/tooltip-icon-button.d.ts.map +1 -0
  28. package/dist/playground/src/components/assistant-ui/tooltip-icon-button.js +13 -0
  29. package/dist/playground/src/components/ui/avatar.d.ts +7 -0
  30. package/dist/playground/src/components/ui/avatar.d.ts.map +1 -0
  31. package/dist/playground/src/components/ui/avatar.js +12 -0
  32. package/dist/playground/src/components/ui/button.d.ts +12 -0
  33. package/dist/playground/src/components/ui/button.d.ts.map +1 -0
  34. package/dist/playground/src/components/ui/button.js +33 -0
  35. package/dist/playground/src/components/ui/tooltip.d.ts +8 -0
  36. package/dist/playground/src/components/ui/tooltip.d.ts.map +1 -0
  37. package/dist/playground/src/components/ui/tooltip.js +11 -0
  38. package/dist/playground/src/lib/utils.d.ts +3 -0
  39. package/dist/playground/src/lib/utils.d.ts.map +1 -0
  40. package/dist/playground/src/lib/utils.js +5 -0
  41. package/dist/playground/src/main.d.ts +2 -0
  42. package/dist/playground/src/main.d.ts.map +1 -0
  43. package/dist/playground/src/main.js +5 -0
  44. package/dist/runtime.d.ts.map +1 -1
  45. package/dist/src/index.d.ts +5 -0
  46. package/dist/src/index.d.ts.map +1 -0
  47. package/dist/src/index.js +4 -0
  48. package/dist/src/logging.d.ts +18 -0
  49. package/dist/src/logging.d.ts.map +1 -0
  50. package/dist/src/logging.js +19 -0
  51. package/dist/src/messages.d.ts +7 -0
  52. package/dist/src/messages.d.ts.map +1 -0
  53. package/dist/src/messages.js +73 -0
  54. package/dist/src/protocol/base.d.ts +23 -0
  55. package/dist/src/protocol/base.d.ts.map +1 -0
  56. package/dist/src/protocol/base.js +37 -0
  57. package/dist/src/protocol/index.d.ts +5 -0
  58. package/dist/src/protocol/index.d.ts.map +1 -0
  59. package/dist/src/protocol/index.js +4 -0
  60. package/dist/src/protocol/rest.d.ts +22 -0
  61. package/dist/src/protocol/rest.d.ts.map +1 -0
  62. package/dist/src/protocol/rest.js +48 -0
  63. package/dist/src/protocol/webrtc.d.ts +56 -0
  64. package/dist/src/protocol/webrtc.d.ts.map +1 -0
  65. package/dist/src/protocol/webrtc.js +267 -0
  66. package/dist/src/protocol/websocket.d.ts +22 -0
  67. package/dist/src/protocol/websocket.d.ts.map +1 -0
  68. package/dist/src/protocol/websocket.js +84 -0
  69. package/dist/src/runtime.d.ts +21 -0
  70. package/dist/src/runtime.d.ts.map +1 -0
  71. package/dist/src/runtime.js +160 -0
  72. package/dist/src/types.d.ts +79 -0
  73. package/dist/src/types.d.ts.map +1 -0
  74. package/dist/src/types.js +1 -0
  75. package/package.json +3 -5
  76. package/src/runtime.tsx +3 -0
@@ -0,0 +1,73 @@
1
+ function removeEmptyMessages(messages) {
2
+ return messages.filter((message) => {
3
+ if (message.finishReason === 'stop') {
4
+ return message.text !== null && message.text?.trim() !== '';
5
+ }
6
+ return true;
7
+ });
8
+ }
9
+ function parseMessages(messages) {
10
+ const outputMessages = [];
11
+ let currentMessage = null;
12
+ for (const message of messages) {
13
+ if (message.type === 'reasoning') {
14
+ if (currentMessage != null) {
15
+ outputMessages.push(currentMessage);
16
+ currentMessage = null;
17
+ }
18
+ outputMessages.push(message);
19
+ }
20
+ else if (message.functionCalls) {
21
+ if (currentMessage) {
22
+ outputMessages.push(currentMessage);
23
+ }
24
+ outputMessages.push(message);
25
+ currentMessage = null;
26
+ }
27
+ else if (message.functionResponse) {
28
+ outputMessages[outputMessages.length - 1] = {
29
+ ...outputMessages[outputMessages.length - 1],
30
+ functionResponse: message.functionResponse,
31
+ };
32
+ }
33
+ else if (currentMessage &&
34
+ message.protocol === currentMessage.protocol &&
35
+ (currentMessage.role === message.role || message.finishReason === 'stop')) {
36
+ currentMessage.text += message.text;
37
+ }
38
+ else {
39
+ if (currentMessage) {
40
+ outputMessages.push(currentMessage);
41
+ }
42
+ currentMessage = {
43
+ ...message,
44
+ };
45
+ }
46
+ }
47
+ if (currentMessage) {
48
+ outputMessages.push(currentMessage);
49
+ }
50
+ return removeEmptyMessages(outputMessages);
51
+ }
52
+ function convertMessage(message) {
53
+ if (message.role === 'function') {
54
+ return {
55
+ id: message.id,
56
+ role: 'assistant',
57
+ status: message?.functionResponse === null ? { type: 'running' } : { type: 'complete', reason: 'stop' },
58
+ content: message.functionCalls?.map((call) => ({
59
+ type: 'tool-call',
60
+ toolName: call.name,
61
+ toolCallId: call.id,
62
+ args: call.args,
63
+ result: message.functionResponse?.result,
64
+ })) ?? [],
65
+ };
66
+ }
67
+ return {
68
+ id: message.id,
69
+ role: message.role,
70
+ content: message.type === 'reasoning' ? [{ type: 'reasoning', text: message.text }] : [{ type: 'text', text: message.text }],
71
+ };
72
+ }
73
+ export { parseMessages, convertMessage, removeEmptyMessages };
@@ -0,0 +1,23 @@
1
+ import { Message, MessageListenerCallback, PersonaMessage, PersonaProtocol, ProtocolStatus, Session, StatusChangeCallback } from '../types';
2
+ declare abstract class PersonaProtocolBase implements PersonaProtocol {
3
+ abstract status: ProtocolStatus;
4
+ abstract session: Session;
5
+ abstract autostart: boolean;
6
+ private statusChangeCallbacks;
7
+ private messageCallbacks;
8
+ addStatusChangeListener(callback: StatusChangeCallback): void;
9
+ addMessageListener(callback: MessageListenerCallback): void;
10
+ syncSession(session: Session): Promise<void>;
11
+ notifyMessage(message: PersonaMessage): Promise<void>;
12
+ notifyMessages(messages: PersonaMessage[]): Promise<void>;
13
+ setSession(session: Session): Promise<void>;
14
+ setStatus(status: ProtocolStatus): Promise<void>;
15
+ clearListeners(): void;
16
+ abstract getName(): string;
17
+ abstract getPriority(): number;
18
+ abstract connect(session?: Session): Promise<Session>;
19
+ abstract disconnect(): Promise<void>;
20
+ abstract send(message: Message): Promise<void>;
21
+ }
22
+ export { PersonaProtocolBase };
23
+ //# sourceMappingURL=base.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"base.d.ts","sourceRoot":"","sources":["../../../src/protocol/base.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,uBAAuB,EAAE,cAAc,EAAE,eAAe,EAAE,cAAc,EAAE,OAAO,EAAE,oBAAoB,EAAE,MAAM,UAAU,CAAC;AAE5I,uBAAe,mBAAoB,YAAW,eAAe;IAC3D,QAAQ,CAAC,MAAM,EAAE,cAAc,CAAC;IAChC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;IAE5B,OAAO,CAAC,qBAAqB,CAA8B;IAC3D,OAAO,CAAC,gBAAgB,CAAiC;IAElD,uBAAuB,CAAC,QAAQ,EAAE,oBAAoB;IAItD,kBAAkB,CAAC,QAAQ,EAAE,uBAAuB;IAG9C,WAAW,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAI5C,aAAa,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;IAGrD,cAAc,CAAC,QAAQ,EAAE,cAAc,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAMzD,UAAU,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAG3C,SAAS,CAAC,MAAM,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;IAStD,cAAc,IAAI,IAAI;IAK7B,QAAQ,CAAC,OAAO,IAAI,MAAM;IAC1B,QAAQ,CAAC,WAAW,IAAI,MAAM;IAC9B,QAAQ,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC;IACrD,QAAQ,CAAC,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IACpC,QAAQ,CAAC,IAAI,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;CAC/C;AAED,OAAO,EAAE,mBAAmB,EAAE,CAAC"}
@@ -0,0 +1,37 @@
1
+ class PersonaProtocolBase {
2
+ statusChangeCallbacks = [];
3
+ messageCallbacks = [];
4
+ addStatusChangeListener(callback) {
5
+ this.statusChangeCallbacks.push(callback);
6
+ }
7
+ addMessageListener(callback) {
8
+ this.messageCallbacks.push(callback);
9
+ }
10
+ async syncSession(session) {
11
+ this.session = session;
12
+ }
13
+ async notifyMessage(message) {
14
+ this.messageCallbacks.forEach((callback) => callback(message));
15
+ }
16
+ async notifyMessages(messages) {
17
+ messages.forEach((message) => {
18
+ this.messageCallbacks.forEach((callback) => callback(message));
19
+ });
20
+ }
21
+ async setSession(session) {
22
+ this.session = session;
23
+ }
24
+ async setStatus(status) {
25
+ const notify = this.status !== status;
26
+ this.status = status;
27
+ if (!notify) {
28
+ return;
29
+ }
30
+ this.statusChangeCallbacks.forEach((callback) => callback(status));
31
+ }
32
+ clearListeners() {
33
+ this.statusChangeCallbacks = [];
34
+ this.messageCallbacks = [];
35
+ }
36
+ }
37
+ export { PersonaProtocolBase };
@@ -0,0 +1,5 @@
1
+ export * from './rest';
2
+ export * from './base';
3
+ export * from './websocket';
4
+ export * from './webrtc';
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/protocol/index.ts"],"names":[],"mappings":"AAAA,cAAc,QAAQ,CAAC;AACvB,cAAc,QAAQ,CAAC;AACvB,cAAc,aAAa,CAAC;AAC5B,cAAc,UAAU,CAAC"}
@@ -0,0 +1,4 @@
1
+ export * from './rest';
2
+ export * from './base';
3
+ export * from './websocket';
4
+ export * from './webrtc';
@@ -0,0 +1,22 @@
1
+ import { PersonaProtocolBase } from './base';
2
+ import { Message, Session, ProtocolStatus, PersonaProtocolBaseConfig } from '../types';
3
+ type PersonaRESTProtocolConfig = PersonaProtocolBaseConfig & {
4
+ apiUrl: string;
5
+ };
6
+ declare class PersonaRESTProtocol extends PersonaProtocolBase {
7
+ status: ProtocolStatus;
8
+ autostart: boolean;
9
+ session: Session;
10
+ config: PersonaRESTProtocolConfig;
11
+ notify: boolean;
12
+ constructor(config: PersonaRESTProtocolConfig);
13
+ getName(): string;
14
+ getPriority(): number;
15
+ connect(session: Session): Promise<Session>;
16
+ disconnect(): Promise<void>;
17
+ syncSession(session: Session): Promise<void>;
18
+ send(message: Message): Promise<void>;
19
+ }
20
+ export { PersonaRESTProtocol };
21
+ export type { PersonaRESTProtocolConfig };
22
+ //# sourceMappingURL=rest.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rest.d.ts","sourceRoot":"","sources":["../../../src/protocol/rest.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,QAAQ,CAAC;AAC7C,OAAO,EAAE,OAAO,EAAmB,OAAO,EAAE,cAAc,EAAE,yBAAyB,EAAE,MAAM,UAAU,CAAC;AAExG,KAAK,yBAAyB,GAAG,yBAAyB,GAAG;IAC3D,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,cAAM,mBAAoB,SAAQ,mBAAmB;IACnD,MAAM,EAAE,cAAc,CAAC;IACvB,SAAS,EAAE,OAAO,CAAC;IACnB,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,yBAAyB,CAAC;IAClC,MAAM,EAAE,OAAO,CAAQ;gBAEX,MAAM,EAAE,yBAAyB;IAOtC,OAAO,IAAI,MAAM;IAIjB,WAAW,IAAI,MAAM;IAIf,OAAO,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC;IAK3C,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAK3B,WAAW,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAI5C,IAAI,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;CAiBnD;AAED,OAAO,EAAE,mBAAmB,EAAE,CAAC;AAC/B,YAAY,EAAE,yBAAyB,EAAE,CAAC"}
@@ -0,0 +1,48 @@
1
+ import { PersonaProtocolBase } from './base';
2
+ class PersonaRESTProtocol extends PersonaProtocolBase {
3
+ status;
4
+ autostart;
5
+ session;
6
+ config;
7
+ notify = true;
8
+ constructor(config) {
9
+ super();
10
+ this.config = config;
11
+ this.status = 'disconnected';
12
+ this.autostart = true;
13
+ }
14
+ getName() {
15
+ return 'rest';
16
+ }
17
+ getPriority() {
18
+ return 0;
19
+ }
20
+ async connect(session) {
21
+ this.setStatus('connected');
22
+ return session;
23
+ }
24
+ async disconnect() {
25
+ this.setStatus('disconnected');
26
+ this.session = null;
27
+ }
28
+ async syncSession(session) {
29
+ this.session = session;
30
+ }
31
+ async send(message) {
32
+ const { apiUrl, apiKey, agentId } = this.config;
33
+ const sessionId = this.session ?? 'new';
34
+ const input = message;
35
+ const response = await fetch(`${apiUrl}/agents/${agentId}/sessions/${sessionId}/messages`, {
36
+ body: JSON.stringify({ userMessage: input }),
37
+ method: 'POST',
38
+ headers: {
39
+ 'Content-Type': 'application/json',
40
+ 'x-fox-apikey': apiKey,
41
+ 'x-persona-apikey': apiKey,
42
+ },
43
+ });
44
+ const personaResponse = (await response.json());
45
+ this.notifyMessages(personaResponse.response.messages);
46
+ }
47
+ }
48
+ export { PersonaRESTProtocol };
@@ -0,0 +1,56 @@
1
+ import { PersonaProtocolBase } from './base';
2
+ import { Message, PersonaProtocolBaseConfig, ProtocolStatus, Session } from '../types';
3
+ type AudioAnalysisData = {
4
+ localAmplitude: number;
5
+ remoteAmplitude: number;
6
+ };
7
+ type AudioVisualizerCallback = (data: AudioAnalysisData) => void;
8
+ type PersonaWebRTCMessageCallback = (data: MessageEvent) => void;
9
+ type PersonaWebRTCConfig = PersonaProtocolBaseConfig & {
10
+ webrtcUrl: string;
11
+ iceServers?: RTCIceServer[];
12
+ };
13
+ declare class PersonaWebRTCClient {
14
+ private config;
15
+ private pc;
16
+ private ws;
17
+ private localStream;
18
+ private remoteStream;
19
+ private audioCtx;
20
+ private localAnalyser;
21
+ private remoteAnalyser;
22
+ private analyzerFrame;
23
+ private dataChannel;
24
+ private isConnected;
25
+ private visualizerCallbacks;
26
+ private messageCallbacks;
27
+ constructor(config: PersonaWebRTCConfig);
28
+ connect(session: Session): Promise<Session>;
29
+ disconnect(): Promise<void>;
30
+ addVisualizerCallback(callback: AudioVisualizerCallback): void;
31
+ addMessageCallback(callback: PersonaWebRTCMessageCallback): void;
32
+ createDataChannel(label?: string): void;
33
+ sendMessage(message: string): void;
34
+ private _startAnalyzers;
35
+ private _stopAnalyzers;
36
+ }
37
+ type PersonaWebRTCProtocolConfig = PersonaWebRTCConfig & {
38
+ autostart?: boolean;
39
+ };
40
+ declare class PersonaWebRTCProtocol extends PersonaProtocolBase {
41
+ status: ProtocolStatus;
42
+ session: Session;
43
+ autostart: boolean;
44
+ config: PersonaWebRTCProtocolConfig;
45
+ webRTCClient: PersonaWebRTCClient;
46
+ constructor(config: PersonaWebRTCProtocolConfig);
47
+ getName(): string;
48
+ getPriority(): number;
49
+ syncSession(session: Session): Promise<void>;
50
+ connect(session?: Session): Promise<Session>;
51
+ disconnect(): Promise<void>;
52
+ send(message: Message): Promise<void>;
53
+ }
54
+ export { PersonaWebRTCProtocol };
55
+ export type { PersonaWebRTCProtocolConfig, AudioVisualizerCallback, AudioAnalysisData };
56
+ //# sourceMappingURL=webrtc.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"webrtc.d.ts","sourceRoot":"","sources":["../../../src/protocol/webrtc.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,QAAQ,CAAC;AAC7C,OAAO,EAAE,OAAO,EAAkB,yBAAyB,EAAE,cAAc,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AAEvG,KAAK,iBAAiB,GAAG;IACvB,cAAc,EAAE,MAAM,CAAC;IACvB,eAAe,EAAE,MAAM,CAAC;CACzB,CAAC;AAEF,KAAK,uBAAuB,GAAG,CAAC,IAAI,EAAE,iBAAiB,KAAK,IAAI,CAAC;AAEjE,KAAK,4BAA4B,GAAG,CAAC,IAAI,EAAE,YAAY,KAAK,IAAI,CAAC;AAEjE,KAAK,mBAAmB,GAAG,yBAAyB,GAAG;IACrD,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,YAAY,EAAE,CAAC;CAC7B,CAAC;AAEF,cAAM,mBAAmB;IACvB,OAAO,CAAC,MAAM,CAAsB;IACpC,OAAO,CAAC,EAAE,CAAkC;IAC5C,OAAO,CAAC,EAAE,CAA0B;IACpC,OAAO,CAAC,WAAW,CAA4B;IAC/C,OAAO,CAAC,YAAY,CAAkC;IACtD,OAAO,CAAC,QAAQ,CAA6B;IAE7C,OAAO,CAAC,aAAa,CAA6B;IAClD,OAAO,CAAC,cAAc,CAA6B;IACnD,OAAO,CAAC,aAAa,CAAuB;IAC5C,OAAO,CAAC,WAAW,CAA+B;IAElD,OAAO,CAAC,WAAW,CAAkB;IACrC,OAAO,CAAC,mBAAmB,CAAiC;IAC5D,OAAO,CAAC,gBAAgB,CAAsC;gBAElD,MAAM,EAAE,mBAAmB;IAI1B,OAAO,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC;IA+G3C,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAoBjC,qBAAqB,CAAC,QAAQ,EAAE,uBAAuB,GAAG,IAAI;IAG9D,kBAAkB,CAAC,QAAQ,EAAE,4BAA4B,GAAG,IAAI;IAIhE,iBAAiB,CAAC,KAAK,SAAa,GAAG,IAAI;IAW3C,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAUzC,OAAO,CAAC,eAAe;IAgDvB,OAAO,CAAC,cAAc;CAQvB;AAED,KAAK,2BAA2B,GAAG,mBAAmB,GAAG;IACvD,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB,CAAC;AAEF,cAAM,qBAAsB,SAAQ,mBAAmB;IACrD,MAAM,EAAE,cAAc,CAAC;IACvB,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,EAAE,OAAO,CAAC;IACnB,MAAM,EAAE,2BAA2B,CAAC;IACpC,YAAY,EAAE,mBAAmB,CAAC;gBAEtB,MAAM,EAAE,2BAA2B;IAgBxC,OAAO,IAAI,MAAM;IAGjB,WAAW,IAAI,MAAM;IAIf,WAAW,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAQ5C,OAAO,CAAC,OAAO,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC;IAgB5C,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAYjC,IAAI,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;CAQ7C;AAED,OAAO,EAAE,qBAAqB,EAAE,CAAC;AACjC,YAAY,EAAE,2BAA2B,EAAE,uBAAuB,EAAE,iBAAiB,EAAE,CAAC"}
@@ -0,0 +1,267 @@
1
+ import { PersonaProtocolBase } from './base';
2
+ class PersonaWebRTCClient {
3
+ config;
4
+ pc = null;
5
+ ws = null;
6
+ localStream = null;
7
+ remoteStream = new MediaStream();
8
+ audioCtx = null;
9
+ localAnalyser = null;
10
+ remoteAnalyser = null;
11
+ analyzerFrame = null;
12
+ dataChannel = null;
13
+ isConnected = false;
14
+ visualizerCallbacks = [];
15
+ messageCallbacks = [];
16
+ constructor(config) {
17
+ this.config = config;
18
+ }
19
+ async connect(session) {
20
+ if (this.isConnected)
21
+ return;
22
+ this.isConnected = true;
23
+ try {
24
+ this.localStream = await navigator.mediaDevices.getUserMedia({ audio: true });
25
+ }
26
+ catch (err) {
27
+ this.config.logger?.error('Error accessing microphone:', err);
28
+ return;
29
+ }
30
+ this.pc = new RTCPeerConnection({
31
+ iceServers: this.config.iceServers || [
32
+ {
33
+ urls: 'stun:34.38.108.251:3478',
34
+ },
35
+ {
36
+ urls: 'turn:34.38.108.251:3478',
37
+ username: 'webrtc',
38
+ credential: 'webrtc',
39
+ },
40
+ ],
41
+ });
42
+ this.localStream.getTracks().forEach((track) => {
43
+ this.pc.addTrack(track, this.localStream);
44
+ });
45
+ this.pc.ontrack = (event) => {
46
+ event.streams[0].getTracks().forEach((track) => {
47
+ this.remoteStream.addTrack(track);
48
+ });
49
+ if (!this.audioCtx) {
50
+ this._startAnalyzers();
51
+ }
52
+ const remoteAudio = new Audio();
53
+ remoteAudio.srcObject = this.remoteStream;
54
+ remoteAudio.play().catch((e) => {
55
+ this.config.logger?.error('Error playing remote audio:', e);
56
+ });
57
+ };
58
+ this.pc.onicecandidate = (event) => {
59
+ if (event.candidate && this.ws?.readyState === WebSocket.OPEN) {
60
+ this.ws.send(JSON.stringify({
61
+ type: 'CANDIDATE',
62
+ src: 'client',
63
+ payload: { candidate: event.candidate },
64
+ }));
65
+ }
66
+ };
67
+ this.pc.ondatachannel = (event) => {
68
+ const channel = event.channel;
69
+ channel.onmessage = (msg) => {
70
+ this.messageCallbacks.forEach((callback) => {
71
+ callback(msg);
72
+ });
73
+ };
74
+ };
75
+ this.ws = new WebSocket(this.config.webrtcUrl || 'wss://persona.applica.guru/api/webrtc');
76
+ this.ws.onopen = async () => {
77
+ const offer = await this.pc.createOffer();
78
+ await this.pc.setLocalDescription(offer);
79
+ const metadata = {
80
+ agentId: this.config.agentId,
81
+ sessionCode: session,
82
+ };
83
+ this.config.logger?.debug('Opening connection to WebRTC server: ', metadata);
84
+ const offerMessage = {
85
+ type: 'OFFER',
86
+ src: crypto.randomUUID?.() || 'client_' + Date.now(),
87
+ payload: {
88
+ sdp: {
89
+ sdp: offer.sdp,
90
+ type: offer.type,
91
+ },
92
+ connectionId: (Date.now() % 1000000).toString(),
93
+ metadata,
94
+ },
95
+ };
96
+ this.ws.send(JSON.stringify(offerMessage));
97
+ };
98
+ this.ws.onmessage = async (event) => {
99
+ const data = JSON.parse(event.data);
100
+ if (data.type === 'ANSWER') {
101
+ await this.pc.setRemoteDescription(new RTCSessionDescription(data.payload.sdp));
102
+ }
103
+ else if (data.type === 'CANDIDATE') {
104
+ try {
105
+ await this.pc.addIceCandidate(new RTCIceCandidate(data.payload.candidate));
106
+ }
107
+ catch (err) {
108
+ this.config.logger?.error('Error adding ICE candidate:', err);
109
+ }
110
+ }
111
+ };
112
+ this.ws.onclose = () => {
113
+ this._stopAnalyzers();
114
+ };
115
+ }
116
+ async disconnect() {
117
+ if (!this.isConnected)
118
+ return;
119
+ this.isConnected = false;
120
+ if (this.ws?.readyState === WebSocket.OPEN)
121
+ this.ws.close();
122
+ if (this.pc)
123
+ this.pc.close();
124
+ if (this.localStream) {
125
+ this.localStream.getTracks().forEach((track) => track.stop());
126
+ }
127
+ this.remoteStream = new MediaStream();
128
+ if (this.audioCtx) {
129
+ await this.audioCtx.close();
130
+ this.audioCtx = null;
131
+ }
132
+ this._stopAnalyzers();
133
+ }
134
+ addVisualizerCallback(callback) {
135
+ this.visualizerCallbacks.push(callback);
136
+ }
137
+ addMessageCallback(callback) {
138
+ this.messageCallbacks.push(callback);
139
+ }
140
+ createDataChannel(label = 'messages') {
141
+ if (!this.pc)
142
+ return;
143
+ this.dataChannel = this.pc.createDataChannel(label);
144
+ this.dataChannel.onopen = () => this.config.logger?.info('Data channel opened');
145
+ this.dataChannel.onmessage = (msg) => {
146
+ this.messageCallbacks.forEach((callback) => {
147
+ callback(msg);
148
+ });
149
+ };
150
+ }
151
+ sendMessage(message) {
152
+ if (!this.dataChannel) {
153
+ this.config.logger?.warn('Data channel is not open, cannot send message');
154
+ return;
155
+ }
156
+ this.dataChannel.send(message);
157
+ this.config.logger?.info('Sent message:', message);
158
+ }
159
+ _startAnalyzers() {
160
+ if (!this.localStream || !this.remoteStream || this.visualizerCallbacks.length === 0) {
161
+ return;
162
+ }
163
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
164
+ this.audioCtx = new (window.AudioContext || window.webkitAudioContext)();
165
+ const localSource = this.audioCtx.createMediaStreamSource(this.localStream);
166
+ const remoteSource = this.audioCtx.createMediaStreamSource(this.remoteStream);
167
+ this.localAnalyser = this.audioCtx.createAnalyser();
168
+ this.remoteAnalyser = this.audioCtx.createAnalyser();
169
+ this.localAnalyser.fftSize = 256;
170
+ this.remoteAnalyser.fftSize = 256;
171
+ localSource.connect(this.localAnalyser);
172
+ remoteSource.connect(this.remoteAnalyser);
173
+ const loop = () => {
174
+ if (!this.localAnalyser || !this.remoteAnalyser || this.visualizerCallbacks.length === 0) {
175
+ return;
176
+ }
177
+ const localArray = new Uint8Array(this.localAnalyser.frequencyBinCount);
178
+ const remoteArray = new Uint8Array(this.remoteAnalyser.frequencyBinCount);
179
+ this.localAnalyser.getByteFrequencyData(localArray);
180
+ this.remoteAnalyser.getByteFrequencyData(remoteArray);
181
+ const localAmp = localArray.reduce((a, b) => a + b, 0) / localArray.length;
182
+ const remoteAmp = remoteArray.reduce((a, b) => a + b, 0) / remoteArray.length;
183
+ if (this.visualizerCallbacks.length > 0) {
184
+ this.visualizerCallbacks.forEach((callback) => {
185
+ callback({
186
+ localAmplitude: localAmp,
187
+ remoteAmplitude: remoteAmp,
188
+ });
189
+ });
190
+ }
191
+ this.analyzerFrame = requestAnimationFrame(loop);
192
+ };
193
+ this.analyzerFrame = requestAnimationFrame(loop);
194
+ }
195
+ _stopAnalyzers() {
196
+ if (this.analyzerFrame) {
197
+ cancelAnimationFrame(this.analyzerFrame);
198
+ this.analyzerFrame = null;
199
+ }
200
+ this.localAnalyser = null;
201
+ this.remoteAnalyser = null;
202
+ }
203
+ }
204
+ class PersonaWebRTCProtocol extends PersonaProtocolBase {
205
+ status;
206
+ session;
207
+ autostart;
208
+ config;
209
+ webRTCClient;
210
+ constructor(config) {
211
+ super();
212
+ this.config = config;
213
+ this.status = 'disconnected';
214
+ this.session = null;
215
+ this.autostart = config?.autostart ?? false;
216
+ this.webRTCClient = new PersonaWebRTCClient(config);
217
+ this.webRTCClient.addMessageCallback((msg) => {
218
+ config.logger?.debug('Received data message:', msg.data);
219
+ const data = JSON.parse(msg.data);
220
+ if (data.type === 'message') {
221
+ this.notifyMessage(data.payload);
222
+ }
223
+ });
224
+ }
225
+ getName() {
226
+ return 'webrtc';
227
+ }
228
+ getPriority() {
229
+ return 10;
230
+ }
231
+ async syncSession(session) {
232
+ super.syncSession(session);
233
+ if (this.status === 'connected') {
234
+ await this.disconnect();
235
+ await this.connect(session);
236
+ }
237
+ }
238
+ async connect(session) {
239
+ if (this.status === 'connected') {
240
+ return Promise.resolve(this.session);
241
+ }
242
+ this.session = session || this.session || 'new';
243
+ this.setStatus('connecting');
244
+ this.config.logger?.debug('Connecting to WebRTC with sessionId:', this.session);
245
+ await this.webRTCClient.connect(this.session);
246
+ this.setStatus('connected');
247
+ await this.webRTCClient.createDataChannel();
248
+ return this.session;
249
+ }
250
+ async disconnect() {
251
+ if (this.status === 'disconnected') {
252
+ this.config.logger?.warn('Already disconnected');
253
+ return Promise.resolve();
254
+ }
255
+ await this.webRTCClient.disconnect();
256
+ this.setStatus('disconnected');
257
+ this.config?.logger?.debug('Disconnected from WebRTC');
258
+ }
259
+ send(message) {
260
+ if (this.status !== 'connected') {
261
+ return Promise.reject(new Error('Not connected'));
262
+ }
263
+ this.webRTCClient.sendMessage(message);
264
+ return Promise.resolve();
265
+ }
266
+ }
267
+ export { PersonaWebRTCProtocol };
@@ -0,0 +1,22 @@
1
+ import { Message, PersonaProtocolBaseConfig, ProtocolStatus, Session } from '../types';
2
+ import { PersonaProtocolBase } from './base';
3
+ type PersonaWebSocketProtocolConfig = PersonaProtocolBaseConfig & {
4
+ webSocketUrl: string;
5
+ };
6
+ declare class PersonaWebSocketProtocol extends PersonaProtocolBase {
7
+ status: ProtocolStatus;
8
+ autostart: boolean;
9
+ session: Session;
10
+ config: PersonaWebSocketProtocolConfig;
11
+ webSocket: WebSocket | null;
12
+ constructor(config: PersonaWebSocketProtocolConfig);
13
+ getName(): string;
14
+ getPriority(): number;
15
+ syncSession(session: Session): Promise<void>;
16
+ connect(session?: Session): Promise<Session>;
17
+ disconnect(): Promise<void>;
18
+ send(message: Message): Promise<void>;
19
+ }
20
+ export { PersonaWebSocketProtocol };
21
+ export type { PersonaWebSocketProtocolConfig };
22
+ //# sourceMappingURL=websocket.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"websocket.d.ts","sourceRoot":"","sources":["../../../src/protocol/websocket.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAkB,yBAAyB,EAAE,cAAc,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AACvG,OAAO,EAAE,mBAAmB,EAAE,MAAM,QAAQ,CAAC;AAE7C,KAAK,8BAA8B,GAAG,yBAAyB,GAAG;IAChE,YAAY,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF,cAAM,wBAAyB,SAAQ,mBAAmB;IACxD,MAAM,EAAE,cAAc,CAAC;IACvB,SAAS,EAAE,OAAO,CAAC;IACnB,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,8BAA8B,CAAC;IACvC,SAAS,EAAE,SAAS,GAAG,IAAI,CAAC;gBAEhB,MAAM,EAAE,8BAA8B;IAS3C,OAAO,IAAI,MAAM;IAIjB,WAAW,IAAI,MAAM;IAIf,WAAW,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IASlD,OAAO,CAAC,OAAO,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC;IA4C5C,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAU3B,IAAI,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;CAQ7C;AAED,OAAO,EAAE,wBAAwB,EAAE,CAAC;AACpC,YAAY,EAAE,8BAA8B,EAAE,CAAC"}
@@ -0,0 +1,84 @@
1
+ import { PersonaProtocolBase } from './base';
2
+ class PersonaWebSocketProtocol extends PersonaProtocolBase {
3
+ status;
4
+ autostart;
5
+ session;
6
+ config;
7
+ webSocket;
8
+ constructor(config) {
9
+ super();
10
+ this.config = config;
11
+ this.status = 'disconnected';
12
+ this.autostart = true;
13
+ this.session = null;
14
+ this.webSocket = null;
15
+ }
16
+ getName() {
17
+ return 'websocket';
18
+ }
19
+ getPriority() {
20
+ return 1;
21
+ }
22
+ async syncSession(session) {
23
+ this.config.logger?.debug('Syncing session with WebSocket protocol:', session);
24
+ this.session = session;
25
+ if (this.webSocket && this.status === 'connected') {
26
+ this.disconnect();
27
+ this.connect(session);
28
+ }
29
+ }
30
+ connect(session) {
31
+ if (this.webSocket !== null && this.status === 'connected') {
32
+ return Promise.resolve(this.session);
33
+ }
34
+ const sid = session || this.session || 'new';
35
+ this.config.logger?.debug('Connecting to WebSocket with sessionId:', sid);
36
+ const apiKey = encodeURIComponent(this.config.apiKey);
37
+ const agentId = this.config.agentId;
38
+ const webSocketUrl = `${this.config.webSocketUrl}?sessionCode=${sid}&agentId=${agentId}&apiKey=${apiKey}`;
39
+ this.setStatus('connecting');
40
+ this.webSocket = new WebSocket(webSocketUrl);
41
+ this.webSocket.addEventListener('open', () => {
42
+ this.setStatus('connected');
43
+ });
44
+ this.webSocket.addEventListener('message', (event) => {
45
+ const data = JSON.parse(event.data);
46
+ if (data.type !== 'message') {
47
+ return;
48
+ }
49
+ const message = data.payload;
50
+ this.notifyMessage(message?.thought ? { role: 'assistant', type: 'reasoning', text: message.thought } : message);
51
+ });
52
+ this.webSocket.addEventListener('close', () => {
53
+ this.setStatus('disconnected');
54
+ this.webSocket = null;
55
+ this.config.logger?.warn('WebSocket connection closed');
56
+ });
57
+ this.webSocket.addEventListener('error', (error) => {
58
+ this.setStatus('disconnected');
59
+ this.webSocket = null;
60
+ this.config.logger?.error('WebSocket error', error);
61
+ // TODO: Implement reconnection logic
62
+ });
63
+ return Promise.resolve(sid);
64
+ }
65
+ disconnect() {
66
+ this.config.logger?.debug('Disconnecting WebSocket');
67
+ if (this.webSocket && this.status === 'connected') {
68
+ this.webSocket.close();
69
+ this.setStatus('disconnected');
70
+ this.webSocket = null;
71
+ }
72
+ return Promise.resolve();
73
+ }
74
+ send(message) {
75
+ if (this.webSocket && this.status === 'connected') {
76
+ this.webSocket.send(JSON.stringify({ type: 'request', payload: message }));
77
+ return Promise.resolve();
78
+ }
79
+ else {
80
+ return Promise.reject(new Error('WebSocket is not connected'));
81
+ }
82
+ }
83
+ }
84
+ export { PersonaWebSocketProtocol };