@applica-software-guru/persona-sdk 0.1.83 → 0.1.85

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 (68) hide show
  1. package/README.md +104 -0
  2. package/dist/bundle.cjs.js +18 -30
  3. package/dist/bundle.cjs.js.map +1 -1
  4. package/dist/bundle.es.js +3506 -7033
  5. package/dist/bundle.es.js.map +1 -1
  6. package/dist/bundle.iife.js +18 -30
  7. package/dist/bundle.iife.js.map +1 -1
  8. package/dist/bundle.umd.js +17 -29
  9. package/dist/bundle.umd.js.map +1 -1
  10. package/dist/index.d.ts +1 -0
  11. package/dist/index.d.ts.map +1 -1
  12. package/dist/messages.d.ts +2 -0
  13. package/dist/messages.d.ts.map +1 -1
  14. package/dist/protocol/webrtc.d.ts.map +1 -1
  15. package/dist/protocol/websocket.d.ts.map +1 -1
  16. package/dist/runtime/context.d.ts +34 -0
  17. package/dist/runtime/context.d.ts.map +1 -0
  18. package/dist/runtime/handlers.d.ts +21 -0
  19. package/dist/runtime/handlers.d.ts.map +1 -0
  20. package/dist/runtime/listeners.d.ts +6 -0
  21. package/dist/runtime/listeners.d.ts.map +1 -0
  22. package/dist/runtime/protocols.d.ts +17 -0
  23. package/dist/runtime/protocols.d.ts.map +1 -0
  24. package/dist/runtime/threads.d.ts +35 -0
  25. package/dist/runtime/threads.d.ts.map +1 -0
  26. package/dist/runtime/utils.d.ts +10 -0
  27. package/dist/runtime/utils.d.ts.map +1 -0
  28. package/dist/runtime.d.ts +4 -22
  29. package/dist/runtime.d.ts.map +1 -1
  30. package/dist/storage/base.d.ts +19 -0
  31. package/dist/storage/base.d.ts.map +1 -0
  32. package/dist/storage/index.d.ts +3 -0
  33. package/dist/storage/index.d.ts.map +1 -0
  34. package/dist/storage/persona.d.ts +30 -0
  35. package/dist/storage/persona.d.ts.map +1 -0
  36. package/dist/types.d.ts +51 -1
  37. package/dist/types.d.ts.map +1 -1
  38. package/package.json +16 -10
  39. package/playground/src/chat.tsx +51 -66
  40. package/playground/src/components/assistant-ui/thread-list.tsx +45 -12
  41. package/playground/src/components/assistant-ui/thread.tsx +34 -96
  42. package/playground/src/components/assistant-ui/threadlist-sidebar.tsx +59 -0
  43. package/playground/src/components/chat/logging.tsx +53 -0
  44. package/playground/src/components/ui/input.tsx +21 -0
  45. package/playground/src/components/ui/separator.tsx +26 -0
  46. package/playground/src/components/ui/sheet.tsx +139 -0
  47. package/playground/src/components/ui/sidebar.tsx +619 -0
  48. package/playground/src/components/ui/skeleton.tsx +13 -0
  49. package/playground/src/components/ui/tooltip.tsx +0 -2
  50. package/playground/src/hooks/theme.ts +70 -0
  51. package/playground/src/hooks/use-mobile.ts +19 -0
  52. package/src/index.ts +1 -0
  53. package/src/messages.ts +98 -8
  54. package/src/protocol/webrtc.ts +1 -0
  55. package/src/protocol/websocket.ts +5 -2
  56. package/src/runtime/context.ts +88 -0
  57. package/src/runtime/handlers.ts +276 -0
  58. package/src/runtime/index.ts +6 -0
  59. package/src/runtime/listeners.ts +79 -0
  60. package/src/runtime/protocols.ts +169 -0
  61. package/src/runtime/threads.ts +120 -0
  62. package/src/runtime/utils.ts +46 -0
  63. package/src/runtime.tsx +226 -326
  64. package/src/storage/base.ts +21 -0
  65. package/src/storage/index.ts +2 -0
  66. package/src/storage/persona.ts +132 -0
  67. package/src/types.ts +64 -2
  68. package/vite.config.ts +11 -1
@@ -0,0 +1,79 @@
1
+ import { PersonaPacket, PersonaMessage, PersonaReasoning, PersonaTransaction, PersonaProtocol, TransformMessages } from '../types';
2
+ import { parseMessages } from '../messages';
3
+
4
+ /**
5
+ * Creates packet listener for a protocol
6
+ */
7
+ export function createPacketListener(
8
+ protocol: PersonaProtocol,
9
+ setMessages: React.Dispatch<React.SetStateAction<PersonaMessage[]>>,
10
+ setIsRunning: React.Dispatch<React.SetStateAction<boolean>>,
11
+ protocols: PersonaProtocol[],
12
+ transformMessages?: TransformMessages,
13
+ ) {
14
+ return (message: PersonaPacket) => {
15
+ if (message.type === 'message') {
16
+ handleMessagePacket(message.payload as PersonaMessage, protocol, setMessages, setIsRunning, transformMessages);
17
+ } else if (message.type === 'reasoning') {
18
+ handleReasoningPacket(message.payload as PersonaReasoning, protocol, setMessages, transformMessages);
19
+ } else if (message.type === 'transaction') {
20
+ handleTransactionPacket(message.payload as PersonaTransaction, protocol, protocols);
21
+ }
22
+ };
23
+ }
24
+
25
+ function handleMessagePacket(
26
+ personaMessage: PersonaMessage,
27
+ protocol: PersonaProtocol,
28
+ setMessages: React.Dispatch<React.SetStateAction<PersonaMessage[]>>,
29
+ setIsRunning: React.Dispatch<React.SetStateAction<boolean>>,
30
+ transformMessages?: TransformMessages,
31
+ ) {
32
+ // Ensure message has proper timestamp
33
+ if (!personaMessage.createdAt) {
34
+ personaMessage.createdAt = new Date();
35
+ }
36
+
37
+ // Handle finish reason and update isRunning state
38
+ if (personaMessage?.finishReason === 'stop' && !personaMessage?.functionResponse && !personaMessage?.thought) {
39
+ setIsRunning(false);
40
+ }
41
+
42
+ // Convert thought to reasoning type
43
+ if (personaMessage.thought) {
44
+ personaMessage.type = 'reasoning';
45
+ }
46
+
47
+ // Add protocol information
48
+ personaMessage.protocol = protocol.getName();
49
+
50
+ setMessages((currentConversation) => {
51
+ const newMessages = parseMessages([...currentConversation, personaMessage]);
52
+ return transformMessages ? transformMessages(newMessages) : newMessages;
53
+ });
54
+ }
55
+
56
+ function handleReasoningPacket(
57
+ reasoning: PersonaReasoning,
58
+ protocol: PersonaProtocol,
59
+ setMessages: React.Dispatch<React.SetStateAction<PersonaMessage[]>>,
60
+ transformMessages?: TransformMessages,
61
+ ) {
62
+ const personaMessage: PersonaMessage = {
63
+ type: 'reasoning',
64
+ text: reasoning.thought,
65
+ role: 'assistant',
66
+ finishReason: 'stop',
67
+ protocol: protocol.getName(),
68
+ createdAt: new Date(),
69
+ };
70
+
71
+ setMessages((currentConversation) => {
72
+ const newMessages = parseMessages([...currentConversation, personaMessage]);
73
+ return transformMessages ? transformMessages(newMessages) : newMessages;
74
+ });
75
+ }
76
+
77
+ function handleTransactionPacket(transaction: PersonaTransaction, currentProtocol: PersonaProtocol, protocols: PersonaProtocol[]) {
78
+ protocols.filter((p) => p !== currentProtocol).forEach((p) => p.onTransaction(transaction));
79
+ }
@@ -0,0 +1,169 @@
1
+ import { PersonaProtocol, PersonaProtocolBaseConfig, PersonaConfig } from '../types';
2
+ import type { PersonaLogger } from '../logging';
3
+ import {
4
+ PersonaRESTProtocol,
5
+ PersonaRESTProtocolConfig,
6
+ PersonaTransactionProtocol,
7
+ PersonaWebRTCProtocol,
8
+ PersonaWebRTCProtocolConfig,
9
+ PersonaWebSocketProtocol,
10
+ PersonaWebSocketProtocolConfig,
11
+ } from '../protocol';
12
+
13
+ type ProtocolsConfig = PersonaConfig['protocols'];
14
+
15
+ /**
16
+ * Initializes protocols based on configuration
17
+ */
18
+ export function initializeProtocols(
19
+ _protocols: ProtocolsConfig,
20
+ config: {
21
+ dev: boolean;
22
+ baseUrl?: string;
23
+ apiKey: string;
24
+ agentId: string;
25
+ userId?: string;
26
+ tools?: PersonaConfig['tools'];
27
+ logger?: PersonaLogger;
28
+ },
29
+ ): PersonaProtocol[] {
30
+ if (Array.isArray(_protocols)) {
31
+ return _protocols;
32
+ }
33
+
34
+ if (typeof _protocols === 'object' && _protocols !== null) {
35
+ const baseEndpoint = config.dev ? 'localhost:8000' : config.baseUrl || 'persona.applica.guru/api';
36
+ const baseEndpointProtocol = config.dev ? 'http' : 'https';
37
+ const baseWebSocketProtocol = config.dev ? 'ws' : 'wss';
38
+
39
+ let availableProtocols = Object.keys(_protocols)
40
+ .map((key) => {
41
+ switch (key) {
42
+ case 'rest':
43
+ return createRESTProtocol(_protocols[key], {
44
+ baseEndpointProtocol,
45
+ baseEndpoint,
46
+ apiKey: config.apiKey,
47
+ agentId: config.agentId,
48
+ userId: config.userId,
49
+ logger: config.logger,
50
+ });
51
+
52
+ case 'webrtc':
53
+ return createWebRTCProtocol(_protocols[key], {
54
+ baseWebSocketProtocol,
55
+ baseEndpoint,
56
+ apiKey: config.apiKey,
57
+ agentId: config.agentId,
58
+ userId: config.userId,
59
+ logger: config.logger,
60
+ });
61
+
62
+ case 'websocket':
63
+ return createWebSocketProtocol(_protocols[key], {
64
+ baseWebSocketProtocol,
65
+ baseEndpoint,
66
+ apiKey: config.apiKey,
67
+ agentId: config.agentId,
68
+ userId: config.userId,
69
+ logger: config.logger,
70
+ });
71
+
72
+ default:
73
+ throw new Error(`Unknown protocol: ${key}`);
74
+ }
75
+ })
76
+ .filter((protocol) => protocol !== null) as PersonaProtocol[];
77
+
78
+ if (config.tools) {
79
+ availableProtocols.push(
80
+ new PersonaTransactionProtocol({
81
+ apiUrl: `${baseEndpointProtocol}://${baseEndpoint}`,
82
+ apiKey: config.apiKey,
83
+ agentId: config.agentId,
84
+ tools: config.tools,
85
+ logger: config.logger,
86
+ }),
87
+ );
88
+ }
89
+
90
+ return availableProtocols;
91
+ }
92
+
93
+ throw new Error('Invalid protocols configuration');
94
+ }
95
+
96
+ function createRESTProtocol(
97
+ config: PersonaProtocolBaseConfig | boolean | undefined,
98
+ baseConfig: {
99
+ baseEndpointProtocol: string;
100
+ baseEndpoint: string;
101
+ apiKey: string;
102
+ agentId: string;
103
+ userId?: string;
104
+ logger?: PersonaLogger;
105
+ },
106
+ ): PersonaRESTProtocol | null {
107
+ if (config === true) {
108
+ return new PersonaRESTProtocol({
109
+ apiUrl: `${baseConfig.baseEndpointProtocol}://${baseConfig.baseEndpoint}`,
110
+ apiKey: baseConfig.apiKey,
111
+ agentId: baseConfig.agentId,
112
+ userId: baseConfig.userId,
113
+ logger: baseConfig.logger,
114
+ });
115
+ } else if (typeof config === 'object' && config !== null) {
116
+ return new PersonaRESTProtocol(config as PersonaRESTProtocolConfig);
117
+ }
118
+ return null;
119
+ }
120
+
121
+ function createWebRTCProtocol(
122
+ config: PersonaProtocolBaseConfig | boolean | undefined,
123
+ baseConfig: {
124
+ baseWebSocketProtocol: string;
125
+ baseEndpoint: string;
126
+ apiKey: string;
127
+ agentId: string;
128
+ userId?: string;
129
+ logger?: PersonaLogger;
130
+ },
131
+ ): PersonaWebRTCProtocol | null {
132
+ if (config === true) {
133
+ return new PersonaWebRTCProtocol({
134
+ webrtcUrl: `${baseConfig.baseWebSocketProtocol}://${baseConfig.baseEndpoint}/webrtc`,
135
+ apiKey: baseConfig.apiKey,
136
+ agentId: baseConfig.agentId,
137
+ userId: baseConfig.userId,
138
+ logger: baseConfig.logger,
139
+ });
140
+ } else if (typeof config === 'object' && config !== null) {
141
+ return new PersonaWebRTCProtocol(config as PersonaWebRTCProtocolConfig);
142
+ }
143
+ return null;
144
+ }
145
+
146
+ function createWebSocketProtocol(
147
+ config: PersonaProtocolBaseConfig | boolean | undefined,
148
+ baseConfig: {
149
+ baseWebSocketProtocol: string;
150
+ baseEndpoint: string;
151
+ apiKey: string;
152
+ agentId: string;
153
+ userId?: string;
154
+ logger?: PersonaLogger;
155
+ },
156
+ ): PersonaWebSocketProtocol | null {
157
+ if (config === true) {
158
+ return new PersonaWebSocketProtocol({
159
+ webSocketUrl: `${baseConfig.baseWebSocketProtocol}://${baseConfig.baseEndpoint}/websocket`,
160
+ apiKey: baseConfig.apiKey,
161
+ agentId: baseConfig.agentId,
162
+ userId: baseConfig.userId,
163
+ logger: baseConfig.logger,
164
+ });
165
+ } else if (typeof config === 'object' && config !== null) {
166
+ return new PersonaWebSocketProtocol(config as PersonaWebSocketProtocolConfig);
167
+ }
168
+ return null;
169
+ }
@@ -0,0 +1,120 @@
1
+ import { ThreadData } from '../types';
2
+ import type { PersonaLogger } from '../logging';
3
+ import type { SessionStorage } from '../storage';
4
+
5
+ /**
6
+ * Generates a new session ID
7
+ */
8
+ export function generateSessionId(): string {
9
+ const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
10
+ let sid = '';
11
+ for (let i = 0; i < 16; i++) {
12
+ sid += chars.charAt(Math.floor(Math.random() * chars.length));
13
+ }
14
+ return sid;
15
+ }
16
+
17
+ /**
18
+ * Creates the thread list adapter for multi-thread support
19
+ */
20
+ export function createThreadListAdapter(
21
+ currentThreadId: string,
22
+ threadList: ThreadData[],
23
+ setCurrentThreadId: (id: string) => void,
24
+ setThreadList: React.Dispatch<React.SetStateAction<ThreadData[]>>,
25
+ storage: SessionStorage,
26
+ onThreadCreate?: (threadId: string) => void,
27
+ onThreadSwitch?: (threadId: string) => void,
28
+ onThreadArchive?: (threadId: string) => void,
29
+ onThreadUnarchive?: (threadId: string) => void,
30
+ onThreadDelete?: (threadId: string) => void,
31
+ logger?: PersonaLogger,
32
+ ) {
33
+ return {
34
+ threadId: currentThreadId,
35
+ threads: threadList
36
+ .filter((t) => t.status === 'regular')
37
+ .map((t) => ({
38
+ id: t.threadId,
39
+ threadId: t.threadId,
40
+ title: t.title || `Chat ${t.threadId}`,
41
+ status: t.status as 'regular',
42
+ })),
43
+ archivedThreads: threadList
44
+ .filter((t) => t.status === 'archived')
45
+ .map((t) => ({
46
+ id: t.threadId,
47
+ threadId: t.threadId,
48
+ title: t.title || `Archived Chat ${t.threadId}`,
49
+ status: t.status as 'archived',
50
+ })),
51
+
52
+ onSwitchToNewThread: () => {
53
+ const newId = generateSessionId();
54
+ logger?.debug('Creating new thread:', newId);
55
+
56
+ const newThread = {
57
+ threadId: newId,
58
+ status: 'regular' as const,
59
+ title: 'New Chat',
60
+ };
61
+
62
+ setThreadList((prev) => [newThread, ...prev]);
63
+ setCurrentThreadId(newId);
64
+
65
+ onThreadCreate?.(newId);
66
+ },
67
+
68
+ onSwitchToThread: (threadId: string) => {
69
+ logger?.debug('Switching to thread:', threadId);
70
+ setCurrentThreadId(threadId);
71
+ // Messages will be synced by the useEffect in runtime.tsx
72
+
73
+ onThreadSwitch?.(threadId);
74
+ },
75
+
76
+ onArchive: (threadId: string) => {
77
+ logger?.debug('Archiving thread:', threadId);
78
+ setThreadList((prev) => prev.map((t) => (t.threadId === threadId ? { ...t, status: 'archived' as const } : t)));
79
+
80
+ onThreadArchive?.(threadId);
81
+ },
82
+
83
+ onUnarchive: (threadId: string) => {
84
+ logger?.debug('Unarchiving thread:', threadId);
85
+ setThreadList((prev) => prev.map((t) => (t.threadId === threadId ? { ...t, status: 'regular' as const } : t)));
86
+
87
+ onThreadUnarchive?.(threadId);
88
+ },
89
+
90
+ onDelete: async (threadId: string) => {
91
+ logger?.debug('Deleting thread:', threadId);
92
+
93
+ // Remove from list
94
+ setThreadList((prev) => prev.filter((t) => t.threadId !== threadId));
95
+
96
+ // Switch to another thread if deleting current
97
+ if (currentThreadId === threadId) {
98
+ const remaining = threadList.filter((t) => t.threadId !== threadId && t.status === 'regular');
99
+ if (remaining.length > 0) {
100
+ setCurrentThreadId(remaining[0].threadId);
101
+ }
102
+ }
103
+
104
+ // Delete from backend (threadId = sessionId)
105
+ storage
106
+ .remove(threadId)
107
+ .then(() => logger?.debug('Thread deleted from backend'))
108
+ .catch((error) => logger?.error('Failed to delete thread:', error));
109
+
110
+ onThreadDelete?.(threadId);
111
+ },
112
+ };
113
+ }
114
+
115
+ /**
116
+ * Generates a default thread ID
117
+ */
118
+ export function generateDefaultThreadId(): string {
119
+ return `thread-${Date.now()}`;
120
+ }
@@ -0,0 +1,46 @@
1
+ import type { PersonaProtocol } from '../types';
2
+ import { PersonaRESTProtocol, PersonaWebRTCProtocol, PersonaWebSocketProtocol } from '../protocol';
3
+
4
+ /**
5
+ * Converts a File object to a base64 string
6
+ */
7
+ export function fileToBase64(file: File): Promise<string> {
8
+ return new Promise((resolve, reject) => {
9
+ const reader = new FileReader();
10
+ reader.readAsDataURL(file);
11
+
12
+ reader.onload = () => {
13
+ const base64 = reader.result as string;
14
+ const base64WithoutPrefix = base64.split(';base64,')[1];
15
+ resolve(base64WithoutPrefix);
16
+ };
17
+
18
+ reader.onerror = (error) => {
19
+ reject(error);
20
+ };
21
+ });
22
+ }
23
+
24
+ /**
25
+ * Extracts the first available protocol endpoint URL
26
+ */
27
+ export function getFirstAvailableProtocolEndpoint(protocols: PersonaProtocol[]): string | null {
28
+ const extractors: { [key: string]: (protocol: PersonaProtocol) => string } = {
29
+ rest: (protocol) => (protocol as PersonaRESTProtocol).config.apiUrl,
30
+ webrtc: (protocol) =>
31
+ (protocol as PersonaWebRTCProtocol).config.webrtcUrl.replace('/webrtc', '').replace('ws://', 'http://').replace('wss://', 'https://'),
32
+ websocket: (protocol) =>
33
+ (protocol as PersonaWebSocketProtocol).config.webSocketUrl
34
+ .replace('/websocket', '')
35
+ .replace('ws://', 'http://')
36
+ .replace('wss://', 'https://'),
37
+ };
38
+
39
+ for (const protocol of protocols) {
40
+ const extractor = extractors[protocol.getName()];
41
+ if (extractor) {
42
+ return extractor(protocol);
43
+ }
44
+ }
45
+ return null;
46
+ }