@applica-software-guru/persona-sdk 0.1.46 → 0.1.47

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.
@@ -0,0 +1,154 @@
1
+ import { PersonaProtocolBase } from './base';
2
+ import {
3
+ Message,
4
+ Session,
5
+ ProtocolStatus,
6
+ PersonaProtocolBaseConfig,
7
+ PersonaTransaction,
8
+ FunctionCall,
9
+ ReadonlyJSONObject,
10
+ } from '../types';
11
+
12
+ type FinishTransactionRequest = {
13
+ success: boolean;
14
+ output: any;
15
+ error: string | null;
16
+ };
17
+
18
+ class PersonaTransactionsManager {
19
+ private config: PersonaTransactionProtocolConfig;
20
+
21
+ constructor(config: PersonaTransactionProtocolConfig) {
22
+ this.config = config;
23
+ }
24
+
25
+ async complete(transaction: PersonaTransaction, request: FinishTransactionRequest): Promise<void> {
26
+ await this.persist(transaction, { ...request, success: true });
27
+ this.config.logger?.debug('Transaction completed:', transaction);
28
+ }
29
+
30
+ async fail(transaction: PersonaTransaction, request: FinishTransactionRequest): Promise<void> {
31
+ await this.persist(transaction, { ...request, success: false });
32
+ this.config.logger?.debug('Transaction failed:', { ...transaction, ...request });
33
+ }
34
+
35
+ async persist(transaction: PersonaTransaction, request: FinishTransactionRequest): Promise<void> {
36
+ await fetch(`${this.config.apiUrl}/transactions/${transaction.id}`, {
37
+ body: JSON.stringify(request),
38
+ method: 'POST',
39
+ headers: {
40
+ 'Content-Type': 'application/json',
41
+ Accept: 'application/json',
42
+ 'x-persona-apikey': this.config.apiKey,
43
+ },
44
+ });
45
+ }
46
+ }
47
+
48
+ export type PersonaToolCallback = (args: ReadonlyJSONObject | undefined) => void;
49
+ export type PersonaTools = {
50
+ [key: string]: PersonaToolCallback;
51
+ };
52
+
53
+ class PersonaPersistableTransaction {
54
+ private transaction: PersonaTransaction;
55
+ private manager: PersonaTransactionsManager;
56
+
57
+ constructor(transaction: PersonaTransaction, manager: PersonaTransactionsManager) {
58
+ this.transaction = transaction;
59
+ this.manager = manager;
60
+ }
61
+
62
+ public getFunctionCall(): FunctionCall | null {
63
+ return this.transaction.functionCall;
64
+ }
65
+
66
+ async invoke(tools: PersonaTools): Promise<void> {
67
+ const functionCall = this.transaction.functionCall;
68
+ if (!functionCall) {
69
+ await this.fail('No function call found');
70
+ return;
71
+ }
72
+ const functionName = functionCall.name;
73
+ const functionArgs = functionCall.args;
74
+ const tool = tools[functionName];
75
+ if (!tool) {
76
+ await this.fail(`Tool ${functionName} not found`);
77
+ return;
78
+ }
79
+ try {
80
+ const result = await tool(functionArgs);
81
+ await this.complete({ date: new Date().toISOString(), result });
82
+ } catch (error) {
83
+ await this.fail(`Error executing tool ${functionName}: ${error}`);
84
+ }
85
+ }
86
+ async complete(output: any): Promise<void> {
87
+ await this.manager.complete(this.transaction, { success: true, output, error: null });
88
+ }
89
+ async fail(error: string): Promise<void> {
90
+ await this.manager.fail(this.transaction, { success: false, output: null, error });
91
+ }
92
+ }
93
+
94
+ type PersonaTransactionCallback = (transaction: PersonaPersistableTransaction) => void;
95
+
96
+ type PersonaTransactionProtocolConfig = PersonaProtocolBaseConfig & {
97
+ apiUrl: string;
98
+ onTransaction: PersonaTransactionCallback;
99
+ };
100
+
101
+ class PersonaTransactionProtocol extends PersonaProtocolBase {
102
+ status: ProtocolStatus;
103
+ autostart: boolean;
104
+ session: Session;
105
+ config: PersonaTransactionProtocolConfig;
106
+ notify: boolean = true;
107
+
108
+ constructor(config: PersonaTransactionProtocolConfig) {
109
+ super();
110
+ this.config = config;
111
+ this.status = 'disconnected';
112
+ this.autostart = true;
113
+ }
114
+
115
+ public getName(): string {
116
+ return 'transaction';
117
+ }
118
+
119
+ public getPriority(): number {
120
+ return 0;
121
+ }
122
+
123
+ public async connect(session: Session): Promise<Session> {
124
+ this.setStatus('connected');
125
+ return session;
126
+ }
127
+
128
+ public async disconnect(): Promise<void> {
129
+ this.setStatus('disconnected');
130
+ this.session = null;
131
+ }
132
+
133
+ public async syncSession(session: Session): Promise<void> {
134
+ this.session = session;
135
+ }
136
+
137
+ public async send(message: Message): Promise<void> {
138
+ this.config.logger?.debug('Sending message:', message);
139
+ throw new Error('Not implemented');
140
+ }
141
+
142
+ public onTransaction(transaction: PersonaTransaction): void {
143
+ if (!this.config.onTransaction) {
144
+ this.config.logger?.error('Transaction protocol config is not set');
145
+ return;
146
+ }
147
+ const manager = new PersonaTransactionsManager(this.config);
148
+ const persistable = new PersonaPersistableTransaction(transaction, manager);
149
+ this.config.onTransaction(persistable);
150
+ }
151
+ }
152
+
153
+ export { PersonaTransactionProtocol };
154
+ export type { PersonaTransactionProtocolConfig, FinishTransactionRequest, PersonaPersistableTransaction, PersonaTransactionCallback };
@@ -1,5 +1,5 @@
1
1
  import { PersonaProtocolBase } from './base';
2
- import { Message, PersonaMessage, PersonaProtocolBaseConfig, ProtocolStatus, Session } from '../types';
2
+ import { Message, PersonaPayload, PersonaProtocolBaseConfig, ProtocolStatus, Session } from '../types';
3
3
 
4
4
  type AudioAnalysisData = {
5
5
  localAmplitude: number;
@@ -274,11 +274,8 @@ class PersonaWebRTCProtocol extends PersonaProtocolBase {
274
274
  this.autostart = config?.autostart ?? false;
275
275
  this.webRTCClient = new PersonaWebRTCClient(config);
276
276
  this.webRTCClient.addMessageCallback((msg: MessageEvent) => {
277
- config.logger?.debug('Received data message:', msg.data);
278
- const data = JSON.parse(msg.data) as { type: 'message' | unknown; payload: PersonaMessage | unknown };
279
- if (data.type === 'message') {
280
- this.notifyMessage(data.payload as PersonaMessage);
281
- }
277
+ const data = JSON.parse(msg.data) as PersonaPayload;
278
+ this.notifyMessage(data);
282
279
  });
283
280
  }
284
281
 
@@ -1,4 +1,4 @@
1
- import { Message, PersonaMessage, PersonaProtocolBaseConfig, ProtocolStatus, Session } from '../types';
1
+ import { Message, PersonaPayload, PersonaProtocolBaseConfig, ProtocolStatus, Session } from '../types';
2
2
  import { PersonaProtocolBase } from './base';
3
3
 
4
4
  type PersonaWebSocketProtocolConfig = PersonaProtocolBaseConfig & {
@@ -56,14 +56,8 @@ class PersonaWebSocketProtocol extends PersonaProtocolBase {
56
56
  this.setStatus('connected');
57
57
  });
58
58
  this.webSocket.addEventListener('message', (event) => {
59
- const data = JSON.parse(event.data) as { type: 'message' | unknown; payload: PersonaMessage | unknown };
60
-
61
- if (data.type !== 'message') {
62
- return;
63
- }
64
- const message = data.payload as PersonaMessage & { thought?: string };
65
-
66
- this.notifyMessage(message?.thought ? { role: 'assistant', type: 'reasoning', text: message.thought } : message);
59
+ const data = JSON.parse(event.data) as PersonaPayload;
60
+ this.notifyMessage(data);
67
61
  });
68
62
  this.webSocket.addEventListener('close', () => {
69
63
  this.setStatus('disconnected');
package/src/runtime.tsx CHANGED
@@ -3,16 +3,20 @@ import { useExternalStoreRuntime, AppendMessage, AssistantRuntimeProvider } from
3
3
  import {
4
4
  PersonaConfig,
5
5
  PersonaMessage,
6
+ PersonaPayload,
6
7
  PersonaProtocol,
7
8
  PersonaProtocolBaseConfig,
8
9
  PersonaResponse,
10
+ PersonaTransaction,
9
11
  ProtocolStatus,
10
12
  Session,
11
13
  } from './types';
12
14
  import { parseMessages, convertMessage } from './messages';
13
15
  import {
16
+ PersonaPersistableTransaction,
14
17
  PersonaRESTProtocol,
15
18
  PersonaRESTProtocolConfig,
19
+ PersonaTransactionProtocol,
16
20
  PersonaWebRTCProtocol,
17
21
  PersonaWebRTCProtocolConfig,
18
22
  PersonaWebSocketProtocol,
@@ -49,7 +53,7 @@ function PersonaRuntimeProviderInner({
49
53
  const baseEndpoint = dev ? 'localhost:8000' : 'persona.applica.guru/api';
50
54
  const baseEndpointProtocol = dev ? 'http' : 'https';
51
55
  const baseWebSocketProtocol = dev ? 'ws' : 'wss';
52
- const availableProtocols = Object.keys(_protocols).map((key) => {
56
+ let availableProtocols = Object.keys(_protocols).map((key) => {
53
57
  switch (key) {
54
58
  case 'rest':
55
59
  const restConfig: PersonaProtocolBaseConfig | true | undefined = _protocols[key];
@@ -88,6 +92,20 @@ function PersonaRuntimeProviderInner({
88
92
  throw new Error(`Unknown protocol: ${key}`);
89
93
  }
90
94
  });
95
+
96
+ if (config.tools) {
97
+ availableProtocols.push(
98
+ new PersonaTransactionProtocol({
99
+ apiUrl: `${baseEndpointProtocol}://${baseEndpoint}`,
100
+ apiKey: config.apiKey,
101
+ agentId: config.agentId,
102
+ onTransaction: async (transaction: PersonaPersistableTransaction) => {
103
+ await transaction.invoke(config.tools!);
104
+ },
105
+ logger,
106
+ }),
107
+ );
108
+ }
91
109
  return availableProtocols;
92
110
  }
93
111
  throw new Error('Invalid protocols configuration');
@@ -109,8 +127,15 @@ function PersonaRuntimeProviderInner({
109
127
  protocolsStatus.set(protocol.getName(), status);
110
128
  setProtocolsStatus(new Map(protocolsStatus));
111
129
  });
112
- protocol.addMessageListener((message: PersonaMessage) => {
113
- setMessages((currentConversation) => parseMessages([...currentConversation, ...[{ ...message, protocol: protocol.getName() }]]));
130
+ protocol.addMessageListener((message: PersonaPayload) => {
131
+ if (message.type === 'message') {
132
+ const personaMessage = message.payload as PersonaMessage;
133
+ setMessages((currentConversation) =>
134
+ parseMessages([...currentConversation, ...[{ ...personaMessage, protocol: protocol.getName() }]]),
135
+ );
136
+ } else if (message.type === 'transaction') {
137
+ protocols.filter((p) => p !== protocol).forEach((p) => p.onTransaction(message.payload as PersonaTransaction));
138
+ }
114
139
  });
115
140
  if (protocol.autostart && protocol.status === 'disconnected') {
116
141
  logger?.debug(`Connecting to protocol: ${protocol.getName()}`);
package/src/types.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import { PersonaTools } from 'src/protocol';
1
2
  import { PersonaLogger } from './logging';
2
3
  import { ReactNode } from 'react';
3
4
 
@@ -23,11 +24,41 @@ export type PersonaFile = {
23
24
  contentType: string;
24
25
  };
25
26
 
27
+ export type PersonaSession = {
28
+ id: string;
29
+ code: string;
30
+ projectId: string;
31
+ agentId: string;
32
+ currentAgentId: string;
33
+ userId: string;
34
+ status: 'active' | 'finished';
35
+ type: 'realtime' | 'async';
36
+ createdAt: string;
37
+ finishedAt: string | null;
38
+ };
39
+
40
+ export type PersonaAgentContext = {
41
+ data: unknown;
42
+ files: PersonaFile[];
43
+ session: PersonaSession;
44
+ };
45
+
46
+ export type PersonaTransaction = {
47
+ id: string;
48
+ projectId: string;
49
+ sessionId: string;
50
+ status: 'pending' | 'completed' | 'failed';
51
+ error: string | null;
52
+ functionCall: FunctionCall | null;
53
+ context: PersonaAgentContext;
54
+ };
55
+
26
56
  export type PersonaMessage = {
27
57
  id?: string | null;
28
58
  protocol?: string;
59
+ thought?: string;
29
60
  text: string;
30
- type: 'reasoning' | 'text';
61
+ type: 'reasoning' | 'text' | 'transaction';
31
62
  role: 'user' | 'assistant' | 'function';
32
63
  files?: PersonaFile[];
33
64
  sessionId?: string;
@@ -36,6 +67,11 @@ export type PersonaMessage = {
36
67
  functionResponse?: FunctionResponse;
37
68
  };
38
69
 
70
+ export type PersonaPayload = {
71
+ type: 'message' | 'transaction';
72
+ payload: PersonaMessage | PersonaTransaction;
73
+ };
74
+
39
75
  export type ModelResponse = {
40
76
  messages: PersonaMessage[];
41
77
  };
@@ -58,7 +94,7 @@ export type PersonaWebRTCConfig = PersonaBaseConfig & {
58
94
  export type Session = string | null | undefined;
59
95
  export type Message = string;
60
96
 
61
- export type MessageListenerCallback = (message: PersonaMessage) => void;
97
+ export type MessageListenerCallback = (message: PersonaPayload) => void;
62
98
  export type StatusChangeCallback = (status: ProtocolStatus) => void;
63
99
 
64
100
  export type ProtocolStatus = 'disconnected' | 'connecting' | 'connected';
@@ -78,6 +114,8 @@ export interface PersonaProtocol {
78
114
  connect: (session?: Session) => Promise<Session>;
79
115
  disconnect: () => Promise<void>;
80
116
 
117
+ onTransaction: (transaction: PersonaTransaction) => void;
118
+
81
119
  setSession: (session: Session) => Promise<void>;
82
120
 
83
121
  send: (message: Message) => Promise<void>;
@@ -102,4 +140,6 @@ export type PersonaConfig = PersonaBaseConfig &
102
140
  webrtc?: PersonaProtocolBaseConfig | true;
103
141
  websocket?: PersonaProtocolBaseConfig | true;
104
142
  };
143
+
144
+ tools?: PersonaTools;
105
145
  };