@rimori/client 1.3.1 → 1.4.0

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 (35) hide show
  1. package/.prettierignore +35 -0
  2. package/dist/cli/scripts/release/release-file-upload.js +1 -1
  3. package/dist/cli/types/DatabaseTypes.d.ts +2 -2
  4. package/dist/components/ai/Avatar.js +4 -2
  5. package/dist/components/ai/EmbeddedAssistent/TTS/Player.js +1 -1
  6. package/dist/core/controller/AIController.js +9 -7
  7. package/dist/core/controller/ExerciseController.d.ts +52 -0
  8. package/dist/core/controller/ExerciseController.js +73 -0
  9. package/dist/core/core.d.ts +1 -0
  10. package/dist/plugin/Logger.d.ts +5 -0
  11. package/dist/plugin/Logger.js +56 -6
  12. package/dist/plugin/RimoriClient.d.ts +28 -2
  13. package/dist/plugin/RimoriClient.js +30 -1
  14. package/eslint.config.js +53 -0
  15. package/package.json +15 -8
  16. package/prettier.config.js +8 -0
  17. package/src/cli/scripts/release/release-file-upload.ts +1 -1
  18. package/src/cli/types/DatabaseTypes.ts +17 -10
  19. package/src/components/ai/Avatar.tsx +3 -2
  20. package/src/components/ai/EmbeddedAssistent/TTS/Player.ts +176 -176
  21. package/src/core/controller/AIController.ts +36 -34
  22. package/src/core/controller/ExerciseController.ts +105 -0
  23. package/src/core/core.ts +1 -0
  24. package/src/plugin/Logger.ts +59 -8
  25. package/src/plugin/RimoriClient.ts +40 -6
  26. package/dist/components/LoggerExample.d.ts +0 -6
  27. package/dist/components/LoggerExample.js +0 -79
  28. package/dist/core/controller/AudioController.d.ts +0 -0
  29. package/dist/core/controller/AudioController.js +0 -1
  30. package/dist/hooks/UseLogger.d.ts +0 -30
  31. package/dist/hooks/UseLogger.js +0 -122
  32. package/dist/plugin/LoggerExample.d.ts +0 -16
  33. package/dist/plugin/LoggerExample.js +0 -140
  34. package/dist/utils/audioFormats.d.ts +0 -26
  35. package/dist/utils/audioFormats.js +0 -67
@@ -1,10 +1,16 @@
1
-
2
1
  // Database table structure definitions
3
2
 
4
3
  /**
5
4
  * Supported database column data types for table schema definitions.
6
5
  */
7
- type DbColumnType = 'decimal' | 'integer' | 'text' | 'boolean' | 'json' | 'timestamp' | 'uuid';
6
+ type DbColumnType =
7
+ | 'decimal'
8
+ | 'integer'
9
+ | 'text'
10
+ | 'boolean'
11
+ | 'json'
12
+ | 'timestamp'
13
+ | 'uuid';
8
14
 
9
15
  /**
10
16
  * Foreign key relationship configuration with cascade delete support.
@@ -45,15 +51,15 @@ export interface DbColumnDefinition {
45
51
  // primary_key?: boolean;
46
52
  /** Restrictions for the column. If the column is restricted, the permission is further restricted. E.g. if the column is restricted to user, then the user can only read the column if they have the right permission.
47
53
  * Example: Denying users to update the column, but allowing the moderator to update the column.
48
- */
54
+ */
49
55
  restrict?: {
50
56
  /** Restrictions for the user */
51
- user: Partial<Omit<DbPermissionDefinition, 'delete'>>,
57
+ user: Partial<Omit<DbPermissionDefinition, 'delete'>>;
52
58
  /** Restrictions for the moderator */
53
- moderator?: Partial<Omit<DbPermissionDefinition, 'delete'>>,
59
+ moderator?: Partial<Omit<DbPermissionDefinition, 'delete'>>;
54
60
  /** Restrictions for the maintainer */
55
61
  // maintainer?: Partial<DbPermissionDefinition>,
56
- }
62
+ };
57
63
  }
58
64
 
59
65
  /**
@@ -80,8 +86,8 @@ export interface DbTableDefinition {
80
86
  description: string;
81
87
  /** Permissions for the table */
82
88
  permissions: {
83
- user: DbPermissionDefinition,
84
- moderator?: DbPermissionDefinition,
89
+ user: DbPermissionDefinition;
90
+ moderator?: DbPermissionDefinition;
85
91
  // maintainer?: DbPermissionDefinition,
86
92
  };
87
93
  /** Column definitions for the table */
@@ -98,7 +104,7 @@ export interface DbTableDefinition {
98
104
  *
99
105
  * Defines the permissions for a database table.
100
106
  */
101
- export type DbPermission = "NONE" | "OWN" | "ALL";
107
+ export type DbPermission = 'NONE' | 'OWN' | 'ALL';
102
108
 
103
109
  /**
104
110
  * Permission definition for a database table.
@@ -114,4 +120,5 @@ export interface DbPermissionDefinition {
114
120
  /**
115
121
  * Full table definition that includes automatically generated fields.
116
122
  */
117
- export type FullTable<T extends Record<string, DbColumnDefinition>> = T & BaseTableStructure;
123
+ export type FullTable<T extends Record<string, DbColumnDefinition>> = T &
124
+ BaseTableStructure;
@@ -44,6 +44,7 @@ export function Avatar({
44
44
  }, [isLoading]);
45
45
 
46
46
  useEffect(() => {
47
+ if (!voiceId) return; //at the beginning when being mounted the voiceId is undefined
47
48
  sender.setOnLoudnessChange((value) => event.emit('self.avatar.triggerLoudness', { loudness: value }));
48
49
  sender.setOnEndOfSpeech(() => setAgentReplying(false));
49
50
 
@@ -58,13 +59,13 @@ export function Avatar({
58
59
  } else if (autoStartConversation.userMessage) {
59
60
  append([{ role: 'user', content: autoStartConversation.userMessage, id: messages.length.toString() }]);
60
61
  }
61
- }, [autoStartConversation]);
62
+ }, [autoStartConversation, voiceId]);
62
63
 
63
64
  useEffect(() => {
64
65
  if (lastMessage?.role === 'assistant') {
65
66
  sender.handleNewText(lastMessage.content, isLoading);
66
67
  if (lastMessage.toolCalls) {
67
- console.log("unlocking mic",lastMessage)
68
+ // console.log("unlocking mic", lastMessage)
68
69
  setAgentReplying(false);
69
70
  setIsProcessingMessage(false);
70
71
  }
@@ -1,198 +1,198 @@
1
1
  export class ChunkedAudioPlayer {
2
2
 
3
- private audioContext!: AudioContext;
4
- private chunkQueue: ArrayBuffer[] = [];
5
- private isPlaying = false;
6
- private analyser!: AnalyserNode;
7
- private dataArray!: Uint8Array;
8
- private shouldMonitorLoudness = true;
9
- private isMonitoring = false;
10
- private handle = 0;
11
- private volume = 1.0;
12
- private loudnessCallback: (value: number) => void = () => { };
13
- private currentIndex = 0;
14
- private startedPlaying = false;
15
- private onEndOfSpeech: () => void = () => { };
16
-
17
- constructor() {
18
- this.init();
3
+ private audioContext!: AudioContext;
4
+ private chunkQueue: ArrayBuffer[] = [];
5
+ private isPlaying = false;
6
+ private analyser!: AnalyserNode;
7
+ private dataArray!: Uint8Array<ArrayBuffer>;
8
+ private shouldMonitorLoudness = true;
9
+ private isMonitoring = false;
10
+ private handle = 0;
11
+ private volume = 1.0;
12
+ private loudnessCallback: (value: number) => void = () => { };
13
+ private currentIndex = 0;
14
+ private startedPlaying = false;
15
+ private onEndOfSpeech: () => void = () => { };
16
+
17
+ constructor() {
18
+ this.init();
19
+ }
20
+
21
+ private init(): void {
22
+ this.audioContext = new AudioContext();
23
+ this.analyser = this.audioContext.createAnalyser();
24
+ this.analyser.fftSize = 256; // Set the FFT size (smaller values provide faster updates, larger ones give better resolution)
25
+ const bufferLength = this.analyser.frequencyBinCount;
26
+ this.dataArray = new Uint8Array(bufferLength); // Array to hold frequency data
27
+ }
28
+
29
+ public setOnLoudnessChange(callback: (value: number) => void) {
30
+ this.loudnessCallback = callback;
31
+ }
32
+
33
+ public setVolume(volume: number) {
34
+ this.volume = volume;
35
+ }
36
+
37
+ public async addChunk(chunk: ArrayBuffer, position: number): Promise<void> {
38
+ console.log('Adding chunk', position, chunk);
39
+ this.chunkQueue[position] = chunk;
40
+ // console.log("received chunk", {
41
+ // chunkQueue: this.chunkQueue.length,
42
+ // isPlaying: this.isPlaying,
43
+ // })
44
+
45
+ if (position === 0 && !this.startedPlaying) {
46
+ this.startedPlaying = true;
47
+ this.playChunks();
19
48
  }
20
-
21
- private init(): void {
22
- this.audioContext = new AudioContext();
23
- this.analyser = this.audioContext.createAnalyser();
24
- this.analyser.fftSize = 256; // Set the FFT size (smaller values provide faster updates, larger ones give better resolution)
25
- const bufferLength = this.analyser.frequencyBinCount;
26
- this.dataArray = new Uint8Array(bufferLength); // Array to hold frequency data
27
- }
28
-
29
- public setOnLoudnessChange(callback: (value: number) => void) {
30
- this.loudnessCallback = callback;
49
+ }
50
+
51
+ private playChunks(): void {
52
+ // console.log({ isPlaying: this.isPlaying });
53
+ if (this.isPlaying) return;
54
+ if (!this.chunkQueue[this.currentIndex]) {
55
+ // wait until the correct chunk arrives
56
+ setTimeout(() => this.playChunks(), 10);
31
57
  }
58
+ this.isPlaying = true;
32
59
 
33
- public setVolume(volume: number) {
34
- this.volume = volume;
35
- }
36
-
37
- public async addChunk(chunk: ArrayBuffer, position: number): Promise<void> {
38
- console.log('Adding chunk', position, chunk);
39
- this.chunkQueue[position] = chunk;
40
- // console.log("received chunk", {
41
- // chunkQueue: this.chunkQueue.length,
42
- // isPlaying: this.isPlaying,
43
- // })
44
-
45
- if (position === 0 && !this.startedPlaying) {
46
- this.startedPlaying = true;
60
+ this.playChunk(this.chunkQueue[this.currentIndex]).then(() => {
61
+ this.isPlaying = false;
62
+ this.currentIndex++;
63
+ if (this.chunkQueue[this.currentIndex]) {
64
+ this.shouldMonitorLoudness = true;
65
+ this.playChunks();
66
+ } else {
67
+ // console.log('Playback finished', { currentIndex: this.currentIndex, chunkQueue: this.chunkQueue });
68
+ setTimeout(() => {
69
+ // console.log('Check again if really playback finished', { currentIndex: this.currentIndex, chunkQueue: this.chunkQueue });
70
+ if (this.chunkQueue.length > this.currentIndex) {
47
71
  this.playChunks();
48
- }
72
+ } else {
73
+ this.startedPlaying = false;
74
+ this.shouldMonitorLoudness = false;
75
+ }
76
+ }, 1000);
77
+ }
78
+ });
79
+ }
80
+
81
+ public stopPlayback(): void {
82
+ // console.log('Stopping playback');
83
+ // Implement logic to stop the current playback
84
+ this.isPlaying = false;
85
+ this.chunkQueue = [];
86
+ this.startedPlaying = false;
87
+ this.shouldMonitorLoudness = false;
88
+ cancelAnimationFrame(this.handle);
89
+ }
90
+
91
+ private playChunk(chunk: ArrayBuffer): Promise<void> {
92
+ // console.log({queue: this.chunkQueue})
93
+ if (!chunk) {
94
+ return Promise.resolve();
49
95
  }
50
96
 
51
- private playChunks(): void {
52
- // console.log({ isPlaying: this.isPlaying });
53
- if (this.isPlaying) return;
54
- if (!this.chunkQueue[this.currentIndex]) {
55
- // wait until the correct chunk arrives
56
- setTimeout(() => this.playChunks(), 10);
97
+ // console.log('Playing chunk', chunk);
98
+ return new Promise((resolve) => {
99
+ const source = this.audioContext.createBufferSource();
100
+ this.audioContext.decodeAudioData(chunk.slice(0)).then((audioBuffer) => {
101
+ source.buffer = audioBuffer;
102
+
103
+ // Create a GainNode for volume control
104
+ const gainNode = this.audioContext.createGain();
105
+ gainNode.gain.value = this.volume;
106
+
107
+ // Connect the source to the GainNode, then to the analyser node, then to the destination (speakers)
108
+ source.connect(gainNode);
109
+ gainNode.connect(this.analyser);
110
+ this.analyser.connect(this.audioContext.destination);
111
+
112
+ source.start(0);
113
+ // console.log('Playing chunk', this.currentIndex);
114
+ gainNode.gain.value = this.volume;
115
+ source.onended = () => {
116
+ // console.log('Chunk ended');
117
+ resolve();
118
+ };
119
+
120
+ // Start monitoring loudness only once
121
+ if (!this.isMonitoring) {
122
+ this.isMonitoring = true;
123
+ this.shouldMonitorLoudness = true;
124
+ this.monitorLoudness();
57
125
  }
58
- this.isPlaying = true;
59
-
60
- this.playChunk(this.chunkQueue[this.currentIndex]).then(() => {
61
- this.isPlaying = false;
62
- this.currentIndex++;
63
- if (this.chunkQueue[this.currentIndex]) {
64
- this.shouldMonitorLoudness = true;
65
- this.playChunks();
66
- } else {
67
- // console.log('Playback finished', { currentIndex: this.currentIndex, chunkQueue: this.chunkQueue });
68
- setTimeout(() => {
69
- // console.log('Check again if really playback finished', { currentIndex: this.currentIndex, chunkQueue: this.chunkQueue });
70
- if (this.chunkQueue.length > this.currentIndex) {
71
- this.playChunks();
72
- } else {
73
- this.startedPlaying = false;
74
- this.shouldMonitorLoudness = false;
75
- }
76
- }, 1000);
77
- }
78
- });
126
+ });
127
+ });
128
+ }
129
+
130
+ async playAgain(): Promise<void> {
131
+ console.log('Playing again');
132
+ if (this.chunkQueue.length > 0 && !this.isPlaying) {
133
+ this.playChunks();
79
134
  }
80
-
81
- public stopPlayback(): void {
82
- // console.log('Stopping playback');
83
- // Implement logic to stop the current playback
84
- this.isPlaying = false;
85
- this.chunkQueue = [];
86
- this.startedPlaying = false;
87
- this.shouldMonitorLoudness = false;
88
- cancelAnimationFrame(this.handle);
135
+ }
136
+
137
+ private monitorLoudness(): void {
138
+ // Stop monitoring when the flag is false
139
+ if (!this.shouldMonitorLoudness) {
140
+ // console.log('Loudness monitoring stopped.');
141
+ cancelAnimationFrame(this.handle);
142
+ this.loudnessCallback(0);
143
+ this.onEndOfSpeech();
144
+ return;
89
145
  }
90
146
 
91
- private playChunk(chunk: ArrayBuffer): Promise<void> {
92
- console.log({queue: this.chunkQueue})
93
- if (!chunk) {
94
- return Promise.resolve();
95
- }
96
-
97
- // console.log('Playing chunk', chunk);
98
- return new Promise((resolve) => {
99
- const source = this.audioContext.createBufferSource();
100
- this.audioContext.decodeAudioData(chunk.slice(0)).then((audioBuffer) => {
101
- source.buffer = audioBuffer;
102
-
103
- // Create a GainNode for volume control
104
- const gainNode = this.audioContext.createGain();
105
- gainNode.gain.value = this.volume;
106
-
107
- // Connect the source to the GainNode, then to the analyser node, then to the destination (speakers)
108
- source.connect(gainNode);
109
- gainNode.connect(this.analyser);
110
- this.analyser.connect(this.audioContext.destination);
111
-
112
- source.start(0);
113
- // console.log('Playing chunk', this.currentIndex);
114
- gainNode.gain.value = this.volume;
115
- source.onended = () => {
116
- // console.log('Chunk ended');
117
- resolve();
118
- };
119
-
120
- // Start monitoring loudness only once
121
- if (!this.isMonitoring) {
122
- this.isMonitoring = true;
123
- this.shouldMonitorLoudness = true;
124
- this.monitorLoudness();
125
- }
126
- });
127
- });
128
- }
147
+ // Get the time domain data from the analyser (this is a snapshot of the waveform)
148
+ this.analyser.getByteTimeDomainData(this.dataArray);
129
149
 
130
- async playAgain(): Promise<void> {
131
- console.log('Playing again');
132
- if (this.chunkQueue.length > 0 && !this.isPlaying) {
133
- this.playChunks();
134
- }
150
+ // Calculate the RMS (root mean square) of the waveform values to get the perceived loudness
151
+ let sum = 0;
152
+ for (let i = 0; i < this.dataArray.length; i++) {
153
+ const value = this.dataArray[i] / 128.0 - 1.0; // Normalize between -1 and 1
154
+ sum += value * value;
135
155
  }
136
156
 
137
- private monitorLoudness(): void {
138
- // Stop monitoring when the flag is false
139
- if (!this.shouldMonitorLoudness) {
140
- // console.log('Loudness monitoring stopped.');
141
- cancelAnimationFrame(this.handle);
142
- this.loudnessCallback(0);
143
- this.onEndOfSpeech();
144
- return;
145
- }
146
-
147
- // Get the time domain data from the analyser (this is a snapshot of the waveform)
148
- this.analyser.getByteTimeDomainData(this.dataArray);
149
-
150
- // Calculate the RMS (root mean square) of the waveform values to get the perceived loudness
151
- let sum = 0;
152
- for (let i = 0; i < this.dataArray.length; i++) {
153
- const value = this.dataArray[i] / 128.0 - 1.0; // Normalize between -1 and 1
154
- sum += value * value;
155
- }
156
-
157
- const rms = Math.sqrt(sum / this.dataArray.length);
158
-
159
- // Handle the case where RMS is 0 to avoid log10(0)
160
- if (rms === 0) {
161
- // console.log('Current loudness: Silent');
162
- } else {
163
- let loudnessInDb = 20 * Math.log10(rms); // Convert to dB
164
- // console.log('Current loudness:' + loudnessInDb);
165
- const minDb = -57;
166
- const maxDb = -15;
157
+ const rms = Math.sqrt(sum / this.dataArray.length);
167
158
 
168
- if (loudnessInDb < minDb) {
169
- loudnessInDb = minDb;
170
- }
171
- if (loudnessInDb > maxDb) {
172
- loudnessInDb = maxDb;
173
- }
159
+ // Handle the case where RMS is 0 to avoid log10(0)
160
+ if (rms === 0) {
161
+ // console.log('Current loudness: Silent');
162
+ } else {
163
+ let loudnessInDb = 20 * Math.log10(rms); // Convert to dB
164
+ // console.log('Current loudness:' + loudnessInDb);
165
+ const minDb = -57;
166
+ const maxDb = -15;
174
167
 
175
- const loudnessScale = ((loudnessInDb - minDb) / (maxDb - minDb)) * 100;
176
- // console.log("root:corrent loudness", loudnessScale);
168
+ if (loudnessInDb < minDb) {
169
+ loudnessInDb = minDb;
170
+ }
171
+ if (loudnessInDb > maxDb) {
172
+ loudnessInDb = maxDb;
173
+ }
177
174
 
178
- this.loudnessCallback(loudnessScale);
179
- }
175
+ const loudnessScale = ((loudnessInDb - minDb) / (maxDb - minDb)) * 100;
176
+ // console.log("root:corrent loudness", loudnessScale);
180
177
 
181
- // Call this method again at regular intervals if you want continuous loudness monitoring
182
- this.handle = requestAnimationFrame(() => this.monitorLoudness());
183
- }
184
- public reset() {
185
- // console.log('Resetting player');
186
- this.stopPlayback();
187
- this.currentIndex = 0;
188
- this.shouldMonitorLoudness = true;
189
- //reset to the beginning when the class gets initialized
190
- this.isMonitoring = false;
191
- this.isPlaying = false;
192
- this.init();
178
+ this.loudnessCallback(loudnessScale);
193
179
  }
194
180
 
195
- public setOnEndOfSpeech(callback: () => void) {
196
- this.onEndOfSpeech = callback;
197
- }
181
+ // Call this method again at regular intervals if you want continuous loudness monitoring
182
+ this.handle = requestAnimationFrame(() => this.monitorLoudness());
183
+ }
184
+ public reset() {
185
+ // console.log('Resetting player');
186
+ this.stopPlayback();
187
+ this.currentIndex = 0;
188
+ this.shouldMonitorLoudness = true;
189
+ //reset to the beginning when the class gets initialized
190
+ this.isMonitoring = false;
191
+ this.isPlaying = false;
192
+ this.init();
193
+ }
194
+
195
+ public setOnEndOfSpeech(callback: () => void) {
196
+ this.onEndOfSpeech = callback;
197
+ }
198
198
  }
@@ -71,10 +71,10 @@ export async function streamChatGPT(backendUrl: string, messages: Message[], too
71
71
  if (value) {
72
72
  const chunk = decoder.decode(value, { stream: true });
73
73
  buffer += chunk;
74
-
74
+
75
75
  // Split by lines, but handle incomplete lines
76
76
  const lines = buffer.split('\n');
77
-
77
+
78
78
  // Keep the last line in buffer if it's incomplete
79
79
  if (lines.length > 1) {
80
80
  buffer = lines.pop() || "";
@@ -82,11 +82,11 @@ export async function streamChatGPT(backendUrl: string, messages: Message[], too
82
82
 
83
83
  for (const line of lines) {
84
84
  if (line.trim() === '') continue;
85
-
85
+
86
86
  // Handle the new streaming format
87
87
  if (line.startsWith('data: ')) {
88
88
  const dataStr = line.substring(6); // Remove 'data: ' prefix
89
-
89
+
90
90
  // Handle [DONE] marker
91
91
  if (dataStr === '[DONE]') {
92
92
  done = true;
@@ -95,39 +95,39 @@ export async function streamChatGPT(backendUrl: string, messages: Message[], too
95
95
 
96
96
  try {
97
97
  const data = JSON.parse(dataStr);
98
-
98
+
99
99
  // Log the first message to understand the format
100
100
  if (!content && !isToolCallMode) {
101
- console.log('First stream message received:', data);
101
+ // console.log('First stream message received:', data);
102
102
  }
103
-
103
+
104
104
  switch (data.type) {
105
105
  case 'start':
106
106
  // Stream started, no action needed
107
- console.log('Stream started');
107
+ // console.log('Stream started');
108
108
  break;
109
-
109
+
110
110
  case 'start-step':
111
111
  // Step started, no action needed
112
- console.log('Step started');
112
+ // console.log('Step started');
113
113
  break;
114
-
114
+
115
115
  case 'reasoning-start':
116
116
  // Reasoning started, no action needed
117
117
  console.log('Reasoning started:', data.id);
118
118
  break;
119
-
119
+
120
120
  case 'reasoning-end':
121
121
  // Reasoning ended, no action needed
122
122
  console.log('Reasoning ended:', data.id);
123
123
  break;
124
-
124
+
125
125
  case 'text-start':
126
126
  // Text generation started, store the ID
127
127
  currentTextId = data.id;
128
128
  console.log('Text generation started:', data.id);
129
129
  break;
130
-
130
+
131
131
  case 'text-delta':
132
132
  // Text delta received, append to content
133
133
  if (data.delta) {
@@ -135,73 +135,75 @@ export async function streamChatGPT(backendUrl: string, messages: Message[], too
135
135
  onResponse(messageId, content, false);
136
136
  }
137
137
  break;
138
-
138
+
139
139
  case 'text-end':
140
140
  // Text generation ended
141
141
  console.log('Text generation ended:', data.id);
142
142
  break;
143
-
143
+
144
144
  case 'finish-step':
145
145
  // Step finished, no action needed
146
- console.log('Step finished');
146
+ // console.log('Step finished');
147
147
  break;
148
-
148
+
149
149
  case 'finish':
150
150
  // Stream finished
151
- console.log('Stream finished');
151
+ // console.log('Stream finished');
152
152
  done = true;
153
153
  break;
154
-
154
+
155
155
  // Additional message types that might be present in the AI library
156
156
  case 'tool-call':
157
+ case 'tool-input-available': //for now input calls should be handled the same way as tool calls
157
158
  // Tool call initiated
158
159
  console.log('Tool call initiated:', data);
159
160
  isToolCallMode = true;
160
- if (data.toolCallId && data.toolName && data.args) {
161
+ if (data.toolCallId && data.toolName && (data.args || data.input)) {
161
162
  toolInvocations.push({
162
163
  toolCallId: data.toolCallId,
163
164
  toolName: data.toolName,
164
- args: data.args
165
+ args: data.args || data.input
165
166
  });
166
167
  }
167
168
  break;
168
-
169
+
170
+ case 'tool-input-delta': //for now input calls should be handled the same way as tool calls
169
171
  case 'tool-call-delta':
170
172
  // Tool call delta (for streaming tool calls)
171
173
  console.log('Tool call delta:', data);
172
174
  break;
173
-
175
+
174
176
  case 'tool-call-end':
175
177
  // Tool call completed
176
178
  console.log('Tool call completed:', data);
177
179
  break;
178
-
180
+
179
181
  case 'tool-result':
180
182
  // Tool execution result
181
183
  console.log('Tool result:', data);
182
184
  break;
183
-
185
+
184
186
  case 'error':
185
187
  // Error occurred
186
188
  console.error('Stream error:', data);
187
189
  break;
188
-
190
+
189
191
  case 'usage':
190
192
  // Usage information
191
193
  console.log('Usage info:', data);
192
194
  break;
193
-
195
+
194
196
  case 'model':
195
197
  // Model information
196
198
  console.log('Model info:', data);
197
199
  break;
198
-
200
+
199
201
  case 'stop':
200
202
  // Stop signal
201
203
  console.log('Stop signal received');
202
204
  done = true;
203
205
  break;
204
-
206
+
205
207
  default:
206
208
  // Unknown type, log for debugging
207
209
  console.log('Unknown stream type:', data.type, data);
@@ -225,14 +227,14 @@ export async function streamChatGPT(backendUrl: string, messages: Message[], too
225
227
  id: messageId,
226
228
  role: "assistant",
227
229
  content: content,
228
- toolCalls: toolInvocations.length > 0 ? toolInvocations: undefined,
230
+ toolCalls: toolInvocations.length > 0 ? toolInvocations : undefined,
229
231
  });
230
232
  }
231
233
 
232
234
  // Handle tool call scenario if tools were provided
233
235
  if (tools.length > 0 && toolInvocations.length > 0) {
234
236
  console.log('Tool calls detected, executing tools...');
235
-
237
+
236
238
  const toolResults: Message[] = [];
237
239
  for (const toolInvocation of toolInvocations) {
238
240
  const tool = tools.find(t => t.name === toolInvocation.toolName);
@@ -254,7 +256,7 @@ export async function streamChatGPT(backendUrl: string, messages: Message[], too
254
256
  }
255
257
  }
256
258
  }
257
-
259
+
258
260
  if (toolResults.length > 0) {
259
261
  currentMessages.push(...toolResults);
260
262
  // Continue the loop to handle the next response
@@ -273,7 +275,7 @@ export async function streamChatGPT(backendUrl: string, messages: Message[], too
273
275
 
274
276
  onResponse(messageId, content, true, toolInvocations);
275
277
  return;
276
-
278
+
277
279
  } catch (error) {
278
280
  console.error('Error in streamChatGPT:', error);
279
281
  onResponse(messageId, `Error: ${error instanceof Error ? error.message : String(error)}`, true, []);