@eka-care/medassist-core 1.0.69 → 1.0.71
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/Synapse.d.ts +0 -1
- package/dist/connection/ConnectionFactory.d.ts +0 -1
- package/dist/connection/SSE.d.ts +0 -1
- package/dist/connection/Websocket.d.ts +0 -1
- package/dist/constants/index.d.ts +0 -1
- package/dist/constants/types.d.ts +0 -1
- package/dist/conversation.d.ts +0 -1
- package/dist/events/Events.d.ts +0 -1
- package/dist/events/Incoming.d.ts +0 -1
- package/dist/events/Outgoing.d.ts +0 -1
- package/dist/events/index.d.ts +0 -1
- package/dist/events/types.d.ts +0 -1
- package/dist/index.d.mts +1442 -0
- package/dist/index.d.ts +0 -1
- package/dist/index.mjs +2 -0
- package/dist/internal/Api/BaseResource.d.ts +0 -1
- package/dist/internal/Api/HttpClient.d.ts +0 -1
- package/dist/internal/Api/types.d.ts +0 -1
- package/dist/internal/Error/Error.d.ts +0 -1
- package/dist/internal/Error/types.d.ts +0 -1
- package/dist/internal/connection/BaseConnection.d.ts +0 -1
- package/dist/internal/connection/types.d.ts +0 -1
- package/dist/internal/events/EventEmitter.d.ts +0 -1
- package/dist/internal/store/index.d.ts +0 -1
- package/dist/media/audio/Audio.copy.d.ts +0 -1
- package/dist/media/audio/Audio.d.ts +0 -1
- package/dist/media/audio/types.d.ts +0 -1
- package/dist/media/file/File.d.ts +0 -1
- package/dist/messages/MessageManager.d.ts +0 -1
- package/dist/messages/types.d.ts +1 -1
- package/dist/resources/config/Config.d.ts +0 -1
- package/dist/resources/feedback/Feedback.d.ts +0 -1
- package/dist/resources/feedback/types.d.ts +0 -1
- package/dist/resources/index.d.ts +0 -1
- package/dist/resources/session/Session.d.ts +0 -1
- package/dist/resources/session/types.d.ts +0 -1
- package/dist/resources/toolCall/ToolCall.d.ts +0 -1
- package/dist/resources/toolCall/types.d.ts +0 -1
- package/dist/resources/types.d.ts +0 -1
- package/dist/resources/voice/VoiceResource.d.ts +0 -1
- package/dist/resources/voice/types.d.ts +0 -1
- package/dist/types/index.d.ts +0 -1
- package/dist/utils/Error.d.ts +0 -1
- package/dist/voice/VoiceAgent.d.ts +0 -1
- package/dist/voice/VoiceAudioAnalyser.d.ts +0 -1
- package/dist/voice/index.d.ts +0 -1
- package/dist/voice/types.d.ts +0 -1
- package/package.json +1 -1
- package/dist/Synapse.d.ts.map +0 -1
- package/dist/connection/ConnectionFactory.d.ts.map +0 -1
- package/dist/connection/SSE.d.ts.map +0 -1
- package/dist/connection/Websocket.d.ts.map +0 -1
- package/dist/constants/index.d.ts.map +0 -1
- package/dist/constants/types.d.ts.map +0 -1
- package/dist/conversation.d.ts.map +0 -1
- package/dist/esm/Synapse.js +0 -612
- package/dist/esm/connection/ConnectionFactory.js +0 -27
- package/dist/esm/connection/SSE.js +0 -212
- package/dist/esm/connection/Websocket.js +0 -178
- package/dist/esm/constants/index.js +0 -25
- package/dist/esm/constants/types.js +0 -1
- package/dist/esm/conversation.js +0 -7
- package/dist/esm/events/Events.js +0 -41
- package/dist/esm/events/Incoming.js +0 -1
- package/dist/esm/events/Outgoing.js +0 -1
- package/dist/esm/events/index.js +0 -2
- package/dist/esm/events/types.js +0 -5
- package/dist/esm/index.js +0 -34
- package/dist/esm/internal/Api/BaseResource.js +0 -50
- package/dist/esm/internal/Api/HttpClient.js +0 -131
- package/dist/esm/internal/Api/types.js +0 -1
- package/dist/esm/internal/Error/Error.js +0 -229
- package/dist/esm/internal/Error/types.js +0 -9
- package/dist/esm/internal/connection/BaseConnection.js +0 -134
- package/dist/esm/internal/connection/types.js +0 -17
- package/dist/esm/internal/events/EventEmitter.js +0 -26
- package/dist/esm/internal/store/index.js +0 -5
- package/dist/esm/media/audio/Audio.copy.js +0 -363
- package/dist/esm/media/audio/Audio.js +0 -310
- package/dist/esm/media/audio/types.js +0 -13
- package/dist/esm/media/file/File.js +0 -159
- package/dist/esm/messages/MessageManager.js +0 -476
- package/dist/esm/messages/types.js +0 -35
- package/dist/esm/resources/config/Config.js +0 -11
- package/dist/esm/resources/feedback/Feedback.js +0 -9
- package/dist/esm/resources/feedback/types.js +0 -7
- package/dist/esm/resources/index.js +0 -152
- package/dist/esm/resources/session/Session.js +0 -44
- package/dist/esm/resources/session/types.js +0 -5
- package/dist/esm/resources/toolCall/ToolCall.js +0 -12
- package/dist/esm/resources/toolCall/types.js +0 -34
- package/dist/esm/resources/types.js +0 -4
- package/dist/esm/resources/voice/VoiceResource.js +0 -14
- package/dist/esm/resources/voice/types.js +0 -1
- package/dist/esm/types/index.js +0 -8
- package/dist/esm/utils/Error.js +0 -110
- package/dist/esm/voice/VoiceAgent.js +0 -305
- package/dist/esm/voice/VoiceAudioAnalyser.js +0 -32
- package/dist/esm/voice/index.js +0 -1
- package/dist/esm/voice/types.js +0 -15
- package/dist/events/Events.d.ts.map +0 -1
- package/dist/events/Incoming.d.ts.map +0 -1
- package/dist/events/Outgoing.d.ts.map +0 -1
- package/dist/events/index.d.ts.map +0 -1
- package/dist/events/types.d.ts.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/internal/Api/BaseResource.d.ts.map +0 -1
- package/dist/internal/Api/HttpClient.d.ts.map +0 -1
- package/dist/internal/Api/types.d.ts.map +0 -1
- package/dist/internal/Error/Error.d.ts.map +0 -1
- package/dist/internal/Error/types.d.ts.map +0 -1
- package/dist/internal/connection/BaseConnection.d.ts.map +0 -1
- package/dist/internal/connection/types.d.ts.map +0 -1
- package/dist/internal/events/EventEmitter.d.ts.map +0 -1
- package/dist/internal/store/index.d.ts.map +0 -1
- package/dist/media/audio/Audio.copy.d.ts.map +0 -1
- package/dist/media/audio/Audio.d.ts.map +0 -1
- package/dist/media/audio/types.d.ts.map +0 -1
- package/dist/media/file/File.d.ts.map +0 -1
- package/dist/messages/MessageManager.d.ts.map +0 -1
- package/dist/messages/types.d.ts.map +0 -1
- package/dist/resources/config/Config.d.ts.map +0 -1
- package/dist/resources/feedback/Feedback.d.ts.map +0 -1
- package/dist/resources/feedback/types.d.ts.map +0 -1
- package/dist/resources/index.d.ts.map +0 -1
- package/dist/resources/session/Session.d.ts.map +0 -1
- package/dist/resources/session/types.d.ts.map +0 -1
- package/dist/resources/toolCall/ToolCall.d.ts.map +0 -1
- package/dist/resources/toolCall/types.d.ts.map +0 -1
- package/dist/resources/types.d.ts.map +0 -1
- package/dist/resources/voice/VoiceResource.d.ts.map +0 -1
- package/dist/resources/voice/types.d.ts.map +0 -1
- package/dist/types/index.d.ts.map +0 -1
- package/dist/utils/Error.d.ts.map +0 -1
- package/dist/voice/VoiceAgent.d.ts.map +0 -1
- package/dist/voice/VoiceAudioAnalyser.d.ts.map +0 -1
- package/dist/voice/index.d.ts.map +0 -1
- package/dist/voice/types.d.ts.map +0 -1
|
@@ -1,159 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Class to store file states
|
|
3
|
-
* Helpers: Zipping, uploading to presigned url, etc.
|
|
4
|
-
*/
|
|
5
|
-
import { FileError, normalizeError } from "../../internal/Error/Error";
|
|
6
|
-
export const MAX_FILE_SIZE = 3 * 1024 * 1024; // 3MB
|
|
7
|
-
export class Filemanager {
|
|
8
|
-
pendingFiles = [];
|
|
9
|
-
pendingMessage = "";
|
|
10
|
-
pendingFormats = [];
|
|
11
|
-
/**
|
|
12
|
-
* Set the files for upload
|
|
13
|
-
*/
|
|
14
|
-
setFilesForUpload(files, message) {
|
|
15
|
-
if (this.pendingFiles.length > 0) {
|
|
16
|
-
this.clearPendingFilesState();
|
|
17
|
-
}
|
|
18
|
-
const validFiles = files.filter((file) => this.validateFile(file));
|
|
19
|
-
if (validFiles.length === 0) {
|
|
20
|
-
throw new FileError("File not supported", {
|
|
21
|
-
context: { stage: "setFilesForUpload" },
|
|
22
|
-
});
|
|
23
|
-
}
|
|
24
|
-
this.pendingFiles = validFiles;
|
|
25
|
-
if (message && message.trim()) {
|
|
26
|
-
this.pendingMessage = message;
|
|
27
|
-
}
|
|
28
|
-
this.pendingFormats = validFiles.map(file => file.type);
|
|
29
|
-
}
|
|
30
|
-
/**
|
|
31
|
-
* Get the pending file state
|
|
32
|
-
*/
|
|
33
|
-
getPendingFileState() {
|
|
34
|
-
return {
|
|
35
|
-
files: this.pendingFiles,
|
|
36
|
-
message: this.pendingMessage || "",
|
|
37
|
-
formats: this.pendingFormats || [],
|
|
38
|
-
};
|
|
39
|
-
}
|
|
40
|
-
/**
|
|
41
|
-
* Upload files to presigned URLs
|
|
42
|
-
*/
|
|
43
|
-
async uploadFilesToPresignedUrl(presignedUrls) {
|
|
44
|
-
let successIds = [];
|
|
45
|
-
// Filter out invalid URLs
|
|
46
|
-
const validUrls = presignedUrls.filter((url) => url.url && url.url.trim());
|
|
47
|
-
try {
|
|
48
|
-
if (validUrls.length === 0) {
|
|
49
|
-
throw new FileError("No valid presigned URLs provided", {
|
|
50
|
-
context: { stage: "uploadFilesToPresignedUrl" },
|
|
51
|
-
});
|
|
52
|
-
}
|
|
53
|
-
if (!this.pendingFiles.length) {
|
|
54
|
-
throw new FileError("No files to upload", {
|
|
55
|
-
context: { stage: "uploadFilesToPresignedUrl" },
|
|
56
|
-
});
|
|
57
|
-
}
|
|
58
|
-
for (let i = 0; i < validUrls.length; i++) {
|
|
59
|
-
const url = validUrls[i].url;
|
|
60
|
-
const response = await fetch(url, {
|
|
61
|
-
method: "PUT",
|
|
62
|
-
body: this.pendingFiles[i],
|
|
63
|
-
headers: {
|
|
64
|
-
"Content-Type": this.pendingFiles[i].type,
|
|
65
|
-
"x-ms-blob-type": "BlockBlob",
|
|
66
|
-
},
|
|
67
|
-
});
|
|
68
|
-
if (!response.ok) {
|
|
69
|
-
throw new FileError(`Failed to upload ${this.pendingFiles[i].name} to URL ${i + 1}: ${response.status} ${response.statusText}`, {
|
|
70
|
-
context: { stage: "uploadFilesToPresignedUrl" },
|
|
71
|
-
});
|
|
72
|
-
}
|
|
73
|
-
successIds.push(validUrls[i].id);
|
|
74
|
-
}
|
|
75
|
-
// Call sendFileUploadComplete only once with the first presigned URL
|
|
76
|
-
// this.sendFileUploadComplete(validUrls[0]);
|
|
77
|
-
return successIds;
|
|
78
|
-
}
|
|
79
|
-
catch (error) {
|
|
80
|
-
if (successIds.length > 0) {
|
|
81
|
-
// this.sendFileUploadComplete(validUrls[0]);
|
|
82
|
-
return successIds;
|
|
83
|
-
}
|
|
84
|
-
throw normalizeError(error, FileError, "Failed to upload files to presigned URL", { context: { stage: "uploadFilesToPresignedUrl" } });
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
// /**
|
|
88
|
-
// * Zips multiple files into a single zip file
|
|
89
|
-
// * @param files Array of files to zip
|
|
90
|
-
// * @param zipFileName Name for the zip file (without extension)
|
|
91
|
-
// * @returns Promise<Blob> - The zipped file as a blob
|
|
92
|
-
// */
|
|
93
|
-
// public async zipFiles(): Promise<Blob> {
|
|
94
|
-
// const zip = new JSZip();
|
|
95
|
-
// // Add each file to the zip
|
|
96
|
-
// this.pendingFiles.forEach((file) => {
|
|
97
|
-
// zip.file(file.name, file);
|
|
98
|
-
// });
|
|
99
|
-
// // Generate the zip file as a blob
|
|
100
|
-
// const zipBlob = await zip.generateAsync({ type: "blob" });
|
|
101
|
-
// return zipBlob;
|
|
102
|
-
// }
|
|
103
|
-
/**
|
|
104
|
-
* Creates a File object from a blob with a specific name
|
|
105
|
-
* @param blob The blob to convert
|
|
106
|
-
* @param fileName The name for the file
|
|
107
|
-
* @returns File object
|
|
108
|
-
*/
|
|
109
|
-
blobToFile(blob, fileName) {
|
|
110
|
-
return new File([blob], fileName, { type: blob.type });
|
|
111
|
-
}
|
|
112
|
-
// /**
|
|
113
|
-
// * Checks if multiple files should be zipped
|
|
114
|
-
// * @param files Array of files
|
|
115
|
-
// * @returns boolean - true if files should be zipped
|
|
116
|
-
// */
|
|
117
|
-
// public shouldZipFiles(): boolean {
|
|
118
|
-
// return this.pendingFiles.length > 1;
|
|
119
|
-
// }
|
|
120
|
-
// /**
|
|
121
|
-
// * Gets the appropriate file name for upload (either zip or single file)
|
|
122
|
-
// * @param files Array of files
|
|
123
|
-
// * @returns string - the file name to use for upload
|
|
124
|
-
// */
|
|
125
|
-
// public getUploadFileName(): string {
|
|
126
|
-
// if (this.shouldZipFiles()) {
|
|
127
|
-
// return `uploaded_files_${Date.now()}.zip`;
|
|
128
|
-
// }
|
|
129
|
-
// return this.pendingFiles[0]?.name || "file";
|
|
130
|
-
// }
|
|
131
|
-
/**
|
|
132
|
-
* Validate file types
|
|
133
|
-
* @param file The file to validate
|
|
134
|
-
* @returns boolean - true if file type is supported
|
|
135
|
-
*/
|
|
136
|
-
validateFile(file) {
|
|
137
|
-
const validFormats = [
|
|
138
|
-
"application/pdf",
|
|
139
|
-
"image/jpeg",
|
|
140
|
-
"image/png",
|
|
141
|
-
"image/jpg",
|
|
142
|
-
// "image/tiff",
|
|
143
|
-
// "text/plain",
|
|
144
|
-
// "text/markdown",
|
|
145
|
-
// "image/heif",
|
|
146
|
-
// "image/heic",
|
|
147
|
-
// "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
|
148
|
-
];
|
|
149
|
-
return validFormats.includes(file.type) && file.size < MAX_FILE_SIZE;
|
|
150
|
-
}
|
|
151
|
-
/**
|
|
152
|
-
* Clears the pending files
|
|
153
|
-
*/
|
|
154
|
-
clearPendingFilesState() {
|
|
155
|
-
this.pendingFiles = [];
|
|
156
|
-
this.pendingMessage = "";
|
|
157
|
-
this.pendingFormats = [];
|
|
158
|
-
}
|
|
159
|
-
}
|
|
@@ -1,476 +0,0 @@
|
|
|
1
|
-
import { SOCKET_CONTENT_TYPES, SOCKET_EVENTS, } from "../events/Events";
|
|
2
|
-
import { Filemanager } from "../media/file/File";
|
|
3
|
-
import { SYNAPSE_REALTIME_ERROR_CODES, SYNAPSE_REALTIME_EVENTS, SYNAPSE_REALTIME_RESERVED_EVENTS, } from "./types";
|
|
4
|
-
import { AudioManager } from "../media/audio/Audio";
|
|
5
|
-
import { ConnectionError, FileError, MessageError, RecordingError, normalizeError, } from "../internal/Error/Error";
|
|
6
|
-
export class MessageManager {
|
|
7
|
-
connection = null;
|
|
8
|
-
callbacks = null;
|
|
9
|
-
fileManager = null;
|
|
10
|
-
audioManager = null;
|
|
11
|
-
outgoingBuffer = null;
|
|
12
|
-
constructor(callbacks) {
|
|
13
|
-
this.callbacks = callbacks || null;
|
|
14
|
-
}
|
|
15
|
-
setConnection(connection) {
|
|
16
|
-
this.connection = connection;
|
|
17
|
-
}
|
|
18
|
-
/**
|
|
19
|
-
* Handle file upload process
|
|
20
|
-
*/
|
|
21
|
-
handleFileUploadProcess({ files, message, urls, tool_declined, tool_result }) {
|
|
22
|
-
if (!this.fileManager) {
|
|
23
|
-
this.fileManager = new Filemanager();
|
|
24
|
-
}
|
|
25
|
-
let fileUploadMessage;
|
|
26
|
-
if (files && files.length > 0) {
|
|
27
|
-
//stage 1. of file upload process
|
|
28
|
-
//--store files temproary in memory
|
|
29
|
-
this.fileManager.setFilesForUpload(files, message);
|
|
30
|
-
fileUploadMessage = {
|
|
31
|
-
ev: SOCKET_EVENTS.CHAT,
|
|
32
|
-
ct: SOCKET_CONTENT_TYPES.FILE,
|
|
33
|
-
_id: Date.now().toString(),
|
|
34
|
-
ts: Date.now(),
|
|
35
|
-
data: {
|
|
36
|
-
extensions: this.fileManager.getPendingFileState().formats,
|
|
37
|
-
...(tool_declined && { tool_declined }),
|
|
38
|
-
...(tool_result && { tool_result })
|
|
39
|
-
},
|
|
40
|
-
};
|
|
41
|
-
}
|
|
42
|
-
else if (urls && urls.length > 0) {
|
|
43
|
-
//--stage 3. of file upload process
|
|
44
|
-
//--only requirement is url
|
|
45
|
-
//--send file upload acknowledgement to client
|
|
46
|
-
const text = this.fileManager.getPendingFileState().message;
|
|
47
|
-
fileUploadMessage = {
|
|
48
|
-
ev: SOCKET_EVENTS.CHAT,
|
|
49
|
-
ct: SOCKET_CONTENT_TYPES.FILE,
|
|
50
|
-
_id: Date.now().toString(),
|
|
51
|
-
ts: Date.now(),
|
|
52
|
-
data: {
|
|
53
|
-
urls: urls,
|
|
54
|
-
...(text && { text }),
|
|
55
|
-
...(tool_declined && { tool_declined }),
|
|
56
|
-
...(tool_result && { tool_result })
|
|
57
|
-
},
|
|
58
|
-
};
|
|
59
|
-
this.fileManager?.clearPendingFilesState();
|
|
60
|
-
}
|
|
61
|
-
return fileUploadMessage;
|
|
62
|
-
}
|
|
63
|
-
/**
|
|
64
|
-
* send chat message through socket
|
|
65
|
-
*/
|
|
66
|
-
sendSocketMessage({ message, files, audio, urls, tool_declined, tool_id, tool_result, initial_prompts }) {
|
|
67
|
-
if (!this.connection?.isConnected()) {
|
|
68
|
-
this.outgoingBuffer = {
|
|
69
|
-
...(message !== undefined && { message }),
|
|
70
|
-
...(files && { files }),
|
|
71
|
-
...(audio && { audio }),
|
|
72
|
-
...(urls && { urls }),
|
|
73
|
-
...(tool_declined && { tool_declined }),
|
|
74
|
-
...(tool_id && { tool_id }),
|
|
75
|
-
...(tool_result && { tool_result }),
|
|
76
|
-
...(initial_prompts && { initial_prompts }),
|
|
77
|
-
};
|
|
78
|
-
return;
|
|
79
|
-
}
|
|
80
|
-
const connection = this.connection;
|
|
81
|
-
let outMessage;
|
|
82
|
-
if ((files && files.length > 0) || (urls && urls.length > 0)) {
|
|
83
|
-
if (files && files.length > 3) {
|
|
84
|
-
const error = new MessageError("Maximum 3 files are allowed to be sent at a time", {
|
|
85
|
-
context: { stage: "sendSocketChatMessage" },
|
|
86
|
-
});
|
|
87
|
-
this.emitError(error);
|
|
88
|
-
throw error;
|
|
89
|
-
}
|
|
90
|
-
outMessage = this.handleFileUploadProcess({
|
|
91
|
-
files,
|
|
92
|
-
message,
|
|
93
|
-
urls,
|
|
94
|
-
tool_declined,
|
|
95
|
-
tool_result
|
|
96
|
-
});
|
|
97
|
-
}
|
|
98
|
-
else if (message) {
|
|
99
|
-
outMessage = {
|
|
100
|
-
ev: SOCKET_EVENTS.CHAT,
|
|
101
|
-
ct: SOCKET_CONTENT_TYPES.TEXT,
|
|
102
|
-
_id: Date.now().toString(),
|
|
103
|
-
ts: Date.now(),
|
|
104
|
-
data: {
|
|
105
|
-
text: message,
|
|
106
|
-
...(tool_declined && { tool_declined }),
|
|
107
|
-
...(tool_id && { tool_id }),
|
|
108
|
-
...(initial_prompts && { initial_prompts }),
|
|
109
|
-
...(tool_result && { tool_result })
|
|
110
|
-
},
|
|
111
|
-
};
|
|
112
|
-
}
|
|
113
|
-
else if (audio && audio?.audio && audio?.format) {
|
|
114
|
-
outMessage = {
|
|
115
|
-
ev: SOCKET_EVENTS.CHAT,
|
|
116
|
-
ct: SOCKET_CONTENT_TYPES.AUDIO,
|
|
117
|
-
_id: Date.now().toString(),
|
|
118
|
-
ts: Date.now(),
|
|
119
|
-
data: {
|
|
120
|
-
audio: audio?.audio,
|
|
121
|
-
format: audio?.format,
|
|
122
|
-
...(tool_declined && { tool_declined }),
|
|
123
|
-
...(tool_result && { tool_result })
|
|
124
|
-
},
|
|
125
|
-
};
|
|
126
|
-
}
|
|
127
|
-
else if (tool_result) {
|
|
128
|
-
outMessage = {
|
|
129
|
-
ev: SOCKET_EVENTS.CHAT,
|
|
130
|
-
ct: SOCKET_CONTENT_TYPES.TEXT,
|
|
131
|
-
_id: Date.now().toString(),
|
|
132
|
-
ts: Date.now(),
|
|
133
|
-
data: {
|
|
134
|
-
text: "",
|
|
135
|
-
tool_result,
|
|
136
|
-
}
|
|
137
|
-
};
|
|
138
|
-
}
|
|
139
|
-
if (!outMessage) {
|
|
140
|
-
const error = new MessageError("No message to send", {
|
|
141
|
-
context: { stage: "sendSocketChatMessage" },
|
|
142
|
-
});
|
|
143
|
-
this.emitError(error);
|
|
144
|
-
throw error;
|
|
145
|
-
}
|
|
146
|
-
connection.sendMessage(outMessage);
|
|
147
|
-
}
|
|
148
|
-
/**
|
|
149
|
-
* Handle incoming chat message
|
|
150
|
-
*/
|
|
151
|
-
handleIncomingSocketChatMessage(message) {
|
|
152
|
-
const connection = this.assertConnection("handleIncomingSocketChatMessage");
|
|
153
|
-
switch (message.ct) {
|
|
154
|
-
case SOCKET_CONTENT_TYPES.FILE: {
|
|
155
|
-
if (message?.data?.urls && message.data.urls?.length > 0) {
|
|
156
|
-
//stage 2. of file upload process
|
|
157
|
-
this.fileManager
|
|
158
|
-
?.uploadFilesToPresignedUrl(message.data.urls)
|
|
159
|
-
.then((validUrls) => {
|
|
160
|
-
this.sendSocketMessage({
|
|
161
|
-
urls: validUrls,
|
|
162
|
-
});
|
|
163
|
-
})
|
|
164
|
-
.catch((error) => {
|
|
165
|
-
const fileError = this.toFileError(error, "Failed to upload files to presigned URL", {
|
|
166
|
-
stage: "handleIncomingSocketChatMessage",
|
|
167
|
-
urls: message.data?.urls?.length,
|
|
168
|
-
});
|
|
169
|
-
this.emitError(fileError);
|
|
170
|
-
});
|
|
171
|
-
}
|
|
172
|
-
break;
|
|
173
|
-
}
|
|
174
|
-
case SOCKET_CONTENT_TYPES.TEXT:
|
|
175
|
-
if (message.data.text &&
|
|
176
|
-
message.data.text.trim() === "" &&
|
|
177
|
-
message._id) {
|
|
178
|
-
const messageData = {
|
|
179
|
-
data: { text: message.data.text },
|
|
180
|
-
// type: message.ct,
|
|
181
|
-
messageId: message._id,
|
|
182
|
-
timestamp: message.ts,
|
|
183
|
-
};
|
|
184
|
-
connection.emit(SYNAPSE_REALTIME_EVENTS.MESSAGE_CHUNK, messageData);
|
|
185
|
-
}
|
|
186
|
-
break;
|
|
187
|
-
case SOCKET_CONTENT_TYPES.TOOL_CALL:
|
|
188
|
-
if (message?.data?.tool_id && message._id) {
|
|
189
|
-
const chatMessageData = {
|
|
190
|
-
data: { ...message.data },
|
|
191
|
-
// type: message.ct,
|
|
192
|
-
messageId: message._id,
|
|
193
|
-
timestamp: message.ts,
|
|
194
|
-
};
|
|
195
|
-
connection.emit(SYNAPSE_REALTIME_EVENTS.TOOL_CALL, chatMessageData);
|
|
196
|
-
// this.callbacks?.onElicitationTool?.(chatMessageData, message._id);
|
|
197
|
-
}
|
|
198
|
-
break;
|
|
199
|
-
case SOCKET_CONTENT_TYPES.AUDIO_TRANSCRIPT:
|
|
200
|
-
if (message?.data?.text) {
|
|
201
|
-
const messageData = {
|
|
202
|
-
data: { text: message.data.text },
|
|
203
|
-
// type: message.ct,
|
|
204
|
-
messageId: message._id,
|
|
205
|
-
timestamp: message.ts,
|
|
206
|
-
};
|
|
207
|
-
connection.emit(SYNAPSE_REALTIME_EVENTS.AUDIO_TRANSCRIPT, messageData);
|
|
208
|
-
// this.callbacks?.onChatmessage?.(message.data.text, message.ct);
|
|
209
|
-
}
|
|
210
|
-
break;
|
|
211
|
-
default:
|
|
212
|
-
// const error = new MessageError("Unsupported content type", {
|
|
213
|
-
// context: {
|
|
214
|
-
// stage: "handleIncomingSocketChatMessage",
|
|
215
|
-
// contentType: message.ct,
|
|
216
|
-
// },
|
|
217
|
-
// });
|
|
218
|
-
// this.emitError(error);
|
|
219
|
-
// throw error;
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
/**
|
|
223
|
-
* Handle incoming stream message
|
|
224
|
-
*/
|
|
225
|
-
handleIncomingSocketStreamMessage(message) {
|
|
226
|
-
const connection = this.assertConnection("handleIncomingSocketStreamMessage");
|
|
227
|
-
switch (message.ct) {
|
|
228
|
-
case SOCKET_CONTENT_TYPES.TEXT:
|
|
229
|
-
if (message?.data?.progress_msg) {
|
|
230
|
-
const messageData = {
|
|
231
|
-
data: { text: message.data.progress_msg },
|
|
232
|
-
// type: message.ct,
|
|
233
|
-
messageId: message._id,
|
|
234
|
-
timestamp: message.ts,
|
|
235
|
-
};
|
|
236
|
-
connection.emit(SYNAPSE_REALTIME_EVENTS.PROGRESS_MESSAGE, messageData);
|
|
237
|
-
return;
|
|
238
|
-
}
|
|
239
|
-
if (message?.data?.text) {
|
|
240
|
-
const messageData = {
|
|
241
|
-
data: { text: message.data.text },
|
|
242
|
-
// type: message.ct,
|
|
243
|
-
messageId: message._id,
|
|
244
|
-
timestamp: message.ts,
|
|
245
|
-
};
|
|
246
|
-
//the ui layer will handle the aggregation logic for stream messages
|
|
247
|
-
connection.emit(SYNAPSE_REALTIME_EVENTS.MESSAGE_CHUNK, messageData);
|
|
248
|
-
}
|
|
249
|
-
break;
|
|
250
|
-
case SOCKET_CONTENT_TYPES.TIPS:
|
|
251
|
-
if (message?.data?.tips) {
|
|
252
|
-
const messageData = {
|
|
253
|
-
data: { tips: message.data.tips },
|
|
254
|
-
// type: message.ct,
|
|
255
|
-
messageId: message._id,
|
|
256
|
-
timestamp: message.ts,
|
|
257
|
-
};
|
|
258
|
-
connection.emit(SYNAPSE_REALTIME_EVENTS.TIPS_MESSAGE, messageData);
|
|
259
|
-
return;
|
|
260
|
-
}
|
|
261
|
-
break;
|
|
262
|
-
case SOCKET_CONTENT_TYPES.TOOL_CALL:
|
|
263
|
-
if (message?.data?.tool_id && message._id) {
|
|
264
|
-
const streamMessageData = {
|
|
265
|
-
data: { ...message.data },
|
|
266
|
-
// type: message.ct,
|
|
267
|
-
messageId: message._id,
|
|
268
|
-
timestamp: message.ts,
|
|
269
|
-
};
|
|
270
|
-
connection.emit(SYNAPSE_REALTIME_EVENTS.TOOL_CALL, streamMessageData);
|
|
271
|
-
// this.callbacks?.onElicitationTool?.(chatMessageData, message._id);
|
|
272
|
-
return;
|
|
273
|
-
}
|
|
274
|
-
break;
|
|
275
|
-
case SOCKET_CONTENT_TYPES.TOOL_START:
|
|
276
|
-
const toolStartMessage = {
|
|
277
|
-
data: message?.data,
|
|
278
|
-
messageId: message._id || Date.now().toString(),
|
|
279
|
-
};
|
|
280
|
-
connection.emit(SYNAPSE_REALTIME_EVENTS.TOOL_START, toolStartMessage);
|
|
281
|
-
break;
|
|
282
|
-
case SOCKET_CONTENT_TYPES.TOOL_END:
|
|
283
|
-
const toolEndMessage = {
|
|
284
|
-
data: message?.data,
|
|
285
|
-
messageId: message._id || Date.now().toString(),
|
|
286
|
-
};
|
|
287
|
-
connection.emit(SYNAPSE_REALTIME_EVENTS.TOOL_END, toolEndMessage);
|
|
288
|
-
break;
|
|
289
|
-
default:
|
|
290
|
-
const error = new MessageError(`Unsupported content type ${message?.ct}`, {
|
|
291
|
-
context: {
|
|
292
|
-
stage: "handleIncomingSocketStreamMessage",
|
|
293
|
-
contentType: message.ct,
|
|
294
|
-
},
|
|
295
|
-
});
|
|
296
|
-
this.emitError(error);
|
|
297
|
-
throw error;
|
|
298
|
-
}
|
|
299
|
-
}
|
|
300
|
-
handleDisconnect(details) {
|
|
301
|
-
this.connection?.emit?.(SYNAPSE_REALTIME_EVENTS.DISCONNECTED, details);
|
|
302
|
-
}
|
|
303
|
-
/**
|
|
304
|
-
* Handle incoming end of stream message
|
|
305
|
-
*/
|
|
306
|
-
handleIncomingSocketEndOfStreamMessage(_message) {
|
|
307
|
-
const connection = this.assertConnection("handleIncomingSocketEndOfStreamMessage");
|
|
308
|
-
connection.emit(SYNAPSE_REALTIME_EVENTS.END_OF_STREAM);
|
|
309
|
-
}
|
|
310
|
-
/**
|
|
311
|
-
* Handle incoming error message
|
|
312
|
-
*/
|
|
313
|
-
handleIncomingSocketErrorMessage(message) {
|
|
314
|
-
const connection = this.assertConnection("handleIncomingSocketErrorMessage");
|
|
315
|
-
switch (message?.data?.code) {
|
|
316
|
-
case SYNAPSE_REALTIME_ERROR_CODES.SESSION_EXPIRED:
|
|
317
|
-
connection.emit(SYNAPSE_REALTIME_RESERVED_EVENTS.SESSION_EXPIRED);
|
|
318
|
-
break;
|
|
319
|
-
default:
|
|
320
|
-
const error = new MessageError(message?.data?.msg || "Socket error received", {
|
|
321
|
-
context: {
|
|
322
|
-
stage: "handleIncomingSocketErrorMessage",
|
|
323
|
-
errorCode: message?.data?.code,
|
|
324
|
-
},
|
|
325
|
-
hint: message?.data?.msg,
|
|
326
|
-
cause: message,
|
|
327
|
-
displayMessage: message?.data?.msg,
|
|
328
|
-
});
|
|
329
|
-
console.log("error from socket", error);
|
|
330
|
-
connection.emit(SYNAPSE_REALTIME_EVENTS.ERROR, message);
|
|
331
|
-
// this.emitError(error);
|
|
332
|
-
}
|
|
333
|
-
}
|
|
334
|
-
/**
|
|
335
|
-
* send authentication message
|
|
336
|
-
*/
|
|
337
|
-
sendSocketAuthMessage(sessionToken) {
|
|
338
|
-
const connection = this.assertConnection("sendSocketAuthMessage");
|
|
339
|
-
const authMessage = {
|
|
340
|
-
ev: SOCKET_EVENTS.AUTH,
|
|
341
|
-
_id: Date.now().toString(),
|
|
342
|
-
ts: Date.now(),
|
|
343
|
-
data: { token: sessionToken },
|
|
344
|
-
};
|
|
345
|
-
connection.sendMessage(authMessage);
|
|
346
|
-
}
|
|
347
|
-
/**
|
|
348
|
-
* send ping message
|
|
349
|
-
*/
|
|
350
|
-
sendSocketPingMessage() {
|
|
351
|
-
const connection = this.assertConnection("sendSocketPingMessage");
|
|
352
|
-
const pingMessage = {
|
|
353
|
-
ev: SOCKET_EVENTS.PING,
|
|
354
|
-
_id: Date.now().toString(),
|
|
355
|
-
ts: Date.now(),
|
|
356
|
-
};
|
|
357
|
-
connection.sendMessage(pingMessage);
|
|
358
|
-
}
|
|
359
|
-
/**
|
|
360
|
-
* send audio message
|
|
361
|
-
*/
|
|
362
|
-
async startRecording({ onChunks, onError, }) {
|
|
363
|
-
if (!onChunks) {
|
|
364
|
-
const error = new RecordingError("onChunks is required", {
|
|
365
|
-
context: { stage: "startRecording" },
|
|
366
|
-
hint: "onChunks is required",
|
|
367
|
-
});
|
|
368
|
-
this.emitError(error);
|
|
369
|
-
throw error;
|
|
370
|
-
}
|
|
371
|
-
if (!this.audioManager) {
|
|
372
|
-
this.audioManager = new AudioManager();
|
|
373
|
-
}
|
|
374
|
-
try {
|
|
375
|
-
await this.audioManager.start(onChunks, (error) => {
|
|
376
|
-
const recordingError = this.toRecordingError(error, "Failed to start audio recording", { stage: "startRecording" });
|
|
377
|
-
onError?.(recordingError);
|
|
378
|
-
this.emitError(recordingError);
|
|
379
|
-
});
|
|
380
|
-
}
|
|
381
|
-
catch (error) {
|
|
382
|
-
const recordingError = this.toRecordingError(error, "Failed to start audio recording", { stage: "startRecording" });
|
|
383
|
-
onError?.(recordingError);
|
|
384
|
-
this.emitError(recordingError);
|
|
385
|
-
throw recordingError;
|
|
386
|
-
}
|
|
387
|
-
}
|
|
388
|
-
/**
|
|
389
|
-
* stop recording audio
|
|
390
|
-
*/
|
|
391
|
-
endRecordingWithSocket() {
|
|
392
|
-
if (!this.audioManager) {
|
|
393
|
-
const error = new RecordingError("Audio manager not set. Call startRecording() first.", { context: { stage: "stopRecording" } });
|
|
394
|
-
this.emitError(error);
|
|
395
|
-
throw error;
|
|
396
|
-
}
|
|
397
|
-
try {
|
|
398
|
-
this.audioManager.stop();
|
|
399
|
-
}
|
|
400
|
-
catch (error) {
|
|
401
|
-
const recordingError = this.toRecordingError(error, "Failed to stop audio recording", { stage: "stopRecording" });
|
|
402
|
-
this.emitError(recordingError);
|
|
403
|
-
throw recordingError;
|
|
404
|
-
}
|
|
405
|
-
}
|
|
406
|
-
/**
|
|
407
|
-
* send pong message
|
|
408
|
-
*/
|
|
409
|
-
sendSocketPongMessage() {
|
|
410
|
-
const connection = this.assertConnection("sendSocketPongMessage");
|
|
411
|
-
const pongMessage = {
|
|
412
|
-
ev: SOCKET_EVENTS.PONG,
|
|
413
|
-
_id: Date.now().toString(),
|
|
414
|
-
ts: Date.now(),
|
|
415
|
-
};
|
|
416
|
-
connection.sendMessage(pongMessage);
|
|
417
|
-
}
|
|
418
|
-
handleConnectionEstablished() {
|
|
419
|
-
this.connection?.handleConnected(); //this will call the onConnectionStatusChange callback with connected
|
|
420
|
-
this.connection?.emit(SYNAPSE_REALTIME_EVENTS.CONNECTED);
|
|
421
|
-
this.flushOutgoingBuffer();
|
|
422
|
-
}
|
|
423
|
-
flushOutgoingBuffer() {
|
|
424
|
-
if (!this.connection?.isConnected() || !this.outgoingBuffer)
|
|
425
|
-
return;
|
|
426
|
-
const buf = this.outgoingBuffer;
|
|
427
|
-
this.outgoingBuffer = null;
|
|
428
|
-
this.sendSocketMessage(buf);
|
|
429
|
-
}
|
|
430
|
-
/**
|
|
431
|
-
* Cleanup message service
|
|
432
|
-
*/
|
|
433
|
-
cleanupMessageServerState() {
|
|
434
|
-
this.outgoingBuffer = null;
|
|
435
|
-
this.connection = null;
|
|
436
|
-
if (this.fileManager) {
|
|
437
|
-
this.fileManager.clearPendingFilesState();
|
|
438
|
-
this.fileManager = null;
|
|
439
|
-
}
|
|
440
|
-
if (this.audioManager) {
|
|
441
|
-
this.audioManager.destroy();
|
|
442
|
-
this.audioManager = null;
|
|
443
|
-
}
|
|
444
|
-
}
|
|
445
|
-
// /**
|
|
446
|
-
// * Generate a unique message ID
|
|
447
|
-
// */
|
|
448
|
-
// private generateId(): string {
|
|
449
|
-
// return `msg_${Date.now()}_${Math.random().toString(36).substring(2, 15)}`;
|
|
450
|
-
// }
|
|
451
|
-
emitError(error) {
|
|
452
|
-
this.callbacks?.onError?.(error);
|
|
453
|
-
}
|
|
454
|
-
toFileError(error, fallbackMessage, context, hint) {
|
|
455
|
-
return normalizeError(error, FileError, fallbackMessage, {
|
|
456
|
-
context,
|
|
457
|
-
hint,
|
|
458
|
-
});
|
|
459
|
-
}
|
|
460
|
-
toRecordingError(error, fallbackMessage, context, hint) {
|
|
461
|
-
return normalizeError(error, RecordingError, fallbackMessage, {
|
|
462
|
-
context,
|
|
463
|
-
hint,
|
|
464
|
-
});
|
|
465
|
-
}
|
|
466
|
-
assertConnection(stage) {
|
|
467
|
-
if (!this.connection) {
|
|
468
|
-
const error = new ConnectionError("Connection not set. Please ensure the connection is established before calling this method.", {
|
|
469
|
-
context: { stage },
|
|
470
|
-
});
|
|
471
|
-
this.emitError(error);
|
|
472
|
-
throw error;
|
|
473
|
-
}
|
|
474
|
-
return this.connection;
|
|
475
|
-
}
|
|
476
|
-
}
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Types for message management
|
|
3
|
-
*/
|
|
4
|
-
import { SOCKET_CONTENT_TYPES, } from "../events/Events";
|
|
5
|
-
export const SYNAPSE_MESSAGE_TYPES = SOCKET_CONTENT_TYPES;
|
|
6
|
-
//TOD0: reframe event names
|
|
7
|
-
export const SYNAPSE_REALTIME_EVENTS = {
|
|
8
|
-
CONNECTED: "connected",
|
|
9
|
-
DISCONNECTED: "disconnected",
|
|
10
|
-
PROGRESS_MESSAGE: "progress_message",
|
|
11
|
-
MESSAGE_CHUNK: "message_chunk",
|
|
12
|
-
TIPS_MESSAGE: "tips_message",
|
|
13
|
-
END_OF_STREAM: "end_of_stream",
|
|
14
|
-
ERROR: "error",
|
|
15
|
-
TOOL_CALL: "tool_call",
|
|
16
|
-
AUDIO_TRANSCRIPT: "audio_transcript",
|
|
17
|
-
TOOL_START: "tool_start",
|
|
18
|
-
TOOL_END: "tool_end"
|
|
19
|
-
};
|
|
20
|
-
export const SYNAPSE_REALTIME_ERROR_CODES = {
|
|
21
|
-
SESSION_INACTIVE: "session_not_found",
|
|
22
|
-
SESSION_EXPIRED: "session_expired",
|
|
23
|
-
INVALID_EVENT: "invalid_event",
|
|
24
|
-
INVALID_CONTENT_TYPE: "invalid_content",
|
|
25
|
-
PARSING_ERROR: "parsing", // for all LLM related error
|
|
26
|
-
FILE_UPLOAD_INPROGRESS: "file_upload_inprogress",
|
|
27
|
-
TIMEOUT: "timeout",
|
|
28
|
-
SERVER_ERROR: "server_error",
|
|
29
|
-
SESSION_TOKEN_MISMATCH: "session_token_mismatch",
|
|
30
|
-
PROMPT_FETCH_ERROR: "prompt_fetch_error",
|
|
31
|
-
INVALID_FILE_REQUEST: "invalid_file_request",
|
|
32
|
-
};
|
|
33
|
-
export const SYNAPSE_REALTIME_RESERVED_EVENTS = {
|
|
34
|
-
SESSION_EXPIRED: "session_expired", //to be used for session expiry
|
|
35
|
-
};
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* resource for initial setup of the agent
|
|
3
|
-
* will update soon
|
|
4
|
-
*/
|
|
5
|
-
import { BaseResource } from "../../internal/Api/BaseResource";
|
|
6
|
-
export class Config extends BaseResource {
|
|
7
|
-
basePath = "/med-assist/agent-config";
|
|
8
|
-
async retrieve(agentId) {
|
|
9
|
-
return this.get(`${this.basePath}/${agentId}`);
|
|
10
|
-
}
|
|
11
|
-
}
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
// import { BaseResource } from "../../internal/Api/BaseResource";
|
|
3
|
-
// import { FeedbackRequest } from "./types";
|
|
4
|
-
// export class Feedback extends BaseResource {
|
|
5
|
-
// private basePath = "/med-assist/session";
|
|
6
|
-
// public async update(feedback: FeedbackRequest): Promise<{success: boolean, m}> {
|
|
7
|
-
// return this.patch<Feedback>(`${this.basePath}/${feedback.sessionId}/message/${feedback.messageId}/feedback`, feedback);
|
|
8
|
-
// }
|
|
9
|
-
// }
|