@rimori/client 2.5.8-next.0 → 2.5.8-next.2

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.
@@ -37,6 +37,6 @@ export interface ObjectRequest {
37
37
  instructions: string;
38
38
  }
39
39
  export declare function generateObject<T = any>(backendUrl: string, request: ObjectRequest, token: string): Promise<T>;
40
- export type OnLLMResponse = (id: string, response: string, finished: boolean, toolInvocations?: any[]) => void;
41
- export declare function streamObject(backendUrl: string, request: ObjectRequest, onResponse: OnLLMResponse, token: string): Promise<void>;
40
+ export type OnStreamedObjectResult<T = any> = (result: T, isLoading: boolean) => void;
41
+ export declare function streamObject<T = any>(backendUrl: string, request: ObjectRequest, onResult: OnStreamedObjectResult<T>, token: string): Promise<void>;
42
42
  export {};
@@ -21,56 +21,85 @@ export function generateObject(backendUrl, request, token) {
21
21
  }).then((response) => response.json());
22
22
  });
23
23
  }
24
- export function streamObject(backendUrl, request, onResponse, token) {
24
+ const tryParseJson = (value) => {
25
+ try {
26
+ return JSON.parse(value);
27
+ }
28
+ catch (_a) {
29
+ return null;
30
+ }
31
+ };
32
+ const mergeStreamObject = (base, patch) => {
33
+ if (Array.isArray(patch)) {
34
+ return patch.map((item, index) => mergeStreamObject(base === null || base === void 0 ? void 0 : base[index], item));
35
+ }
36
+ if (patch && typeof patch === 'object') {
37
+ const result = base && typeof base === 'object' && !Array.isArray(base) ? Object.assign({}, base) : {};
38
+ for (const [key, value] of Object.entries(patch)) {
39
+ result[key] = mergeStreamObject(result[key], value);
40
+ }
41
+ return result;
42
+ }
43
+ return patch;
44
+ };
45
+ const applyStreamChunk = (current, chunk) => {
46
+ if (!chunk || typeof chunk !== 'object') {
47
+ return { next: current, updated: false };
48
+ }
49
+ if (chunk.object && typeof chunk.object === 'object') {
50
+ return { next: chunk.object, updated: true };
51
+ }
52
+ if (chunk.delta && typeof chunk.delta === 'object') {
53
+ return { next: mergeStreamObject(current, chunk.delta), updated: true };
54
+ }
55
+ if (chunk.value && typeof chunk.value === 'object') {
56
+ return { next: mergeStreamObject(current, chunk.value), updated: true };
57
+ }
58
+ return { next: current, updated: false };
59
+ };
60
+ export function streamObject(backendUrl, request, onResult, token) {
25
61
  return __awaiter(this, void 0, void 0, function* () {
26
- const messageId = Math.random().toString(36).substring(3);
27
62
  const response = yield fetch(`${backendUrl}/ai/llm-object`, {
28
63
  method: 'POST',
29
64
  body: JSON.stringify({
30
65
  stream: true,
31
- tools: request.tool,
32
- systemInstructions: request.behaviour,
33
- secondaryInstructions: request.instructions,
66
+ tool: request.tool,
67
+ behaviour: request.behaviour,
68
+ instructions: request.instructions,
34
69
  }),
35
70
  headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json' },
36
71
  });
72
+ if (!response.ok) {
73
+ console.error('Failed to stream object:', response.status, response.statusText);
74
+ return;
75
+ }
37
76
  if (!response.body) {
38
77
  console.error('No response body.');
39
78
  return;
40
79
  }
41
80
  const reader = response.body.getReader();
42
81
  const decoder = new TextDecoder('utf-8');
43
- let content = '';
44
82
  let done = false;
45
- const toolInvocations = [];
83
+ let currentObject = {};
46
84
  while (!done) {
47
- const { value } = yield reader.read();
85
+ const { value, done: readerDone } = yield reader.read();
48
86
  if (value) {
49
87
  const chunk = decoder.decode(value, { stream: true });
50
- const lines = chunk.split('\n').filter((line) => line.trim() !== '');
88
+ const lines = chunk.split('\n').filter((line) => line.trim());
51
89
  for (const line of lines) {
52
- const data = line.substring(3, line.length - 1);
53
- const command = line.substring(0, 1);
54
- // console.log("data: ", { line, data, command });
55
- if (command === '0') {
56
- content += data;
57
- // console.log("AI response:", content);
58
- //content \n\n should be real line break when message is displayed
59
- onResponse(messageId, content.replace(/\\n/g, '\n').replace(/\\+"/g, '"'), false);
60
- }
61
- else if (command === 'd') {
62
- // console.log("AI usage:", JSON.parse(line.substring(2)));
90
+ const dataStr = line.substring(5).trim();
91
+ if (dataStr === '[DONE]') {
63
92
  done = true;
64
93
  break;
65
94
  }
66
- else if (command === '9') {
67
- // console.log("tool call:", JSON.parse(line.substring(2)));
68
- // console.log("tools", tools);
69
- toolInvocations.push(JSON.parse(line.substring(2)));
70
- }
95
+ currentObject = JSON.parse(dataStr);
96
+ onResult(currentObject, true);
71
97
  }
72
98
  }
99
+ if (readerDone) {
100
+ done = true;
101
+ }
73
102
  }
74
- onResponse(messageId, content.replace(/\\n/g, '\n').replace(/\\+"/g, '"'), true, toolInvocations);
103
+ onResult(currentObject, false);
75
104
  });
76
105
  }
@@ -80,7 +80,7 @@ export class RimoriCommunicationHandler {
80
80
  // Listen for updates from rimori-main (data changes, token refresh, etc.)
81
81
  // Topic format: {pluginId}.supabase.triggerUpdate
82
82
  EventBus.on(`${this.pluginId}.supabase.triggerUpdate`, (ev) => {
83
- console.log('[RimoriCommunicationHandler] Received update from rimori-main', ev.data);
83
+ // console.log('[RimoriCommunicationHandler] Received update from rimori-main', ev.data);
84
84
  this.handleRimoriInfoUpdate(ev.data);
85
85
  });
86
86
  // Mark MessageChannel as ready and process pending requests
@@ -211,7 +211,7 @@ export class RimoriCommunicationHandler {
211
211
  */
212
212
  handleRimoriInfoUpdate(newInfo) {
213
213
  if (JSON.stringify(this.rimoriInfo) === JSON.stringify(newInfo)) {
214
- console.log('[RimoriCommunicationHandler] RimoriInfo update is the same as the cached info, skipping update');
214
+ // console.log('[RimoriCommunicationHandler] RimoriInfo update is the same as the cached info, skipping update');
215
215
  return;
216
216
  }
217
217
  // Update cached rimoriInfo
@@ -46,4 +46,10 @@ export declare class AIModule {
46
46
  * @returns The generated object.
47
47
  */
48
48
  getObject<T = any>(request: ObjectRequest): Promise<T>;
49
+ /**
50
+ * Generate a streamed structured object from a request using AI.
51
+ * @param request The object generation request.
52
+ * @param onResult Callback for each result chunk.
53
+ */
54
+ getStreamedObject<T = any>(request: ObjectRequest, onResult: (result: T, isLoading: boolean) => void): Promise<void>;
49
55
  }
@@ -8,7 +8,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
8
8
  });
9
9
  };
10
10
  import { generateText, streamChatGPT } from '../../controller/AIController';
11
- import { generateObject } from '../../controller/ObjectController';
11
+ import { generateObject, streamObject } from '../../controller/ObjectController';
12
12
  import { getSTTResponse, getTTSResponse } from '../../controller/VoiceController';
13
13
  /**
14
14
  * Controller for AI-related operations.
@@ -78,4 +78,14 @@ export class AIModule {
78
78
  return generateObject(this.backendUrl, request, this.token);
79
79
  });
80
80
  }
81
+ /**
82
+ * Generate a streamed structured object from a request using AI.
83
+ * @param request The object generation request.
84
+ * @param onResult Callback for each result chunk.
85
+ */
86
+ getStreamedObject(request, onResult) {
87
+ return __awaiter(this, void 0, void 0, function* () {
88
+ return streamObject(this.backendUrl, request, onResult, this.token);
89
+ });
90
+ }
81
91
  }
@@ -2,3 +2,11 @@ export type LanguageLevel = 'Pre-A1' | 'A1' | 'A2' | 'B1' | 'B2' | 'C1' | 'C2' |
2
2
  export declare function getDifficultyLevel(difficulty: LanguageLevel): number;
3
3
  export declare function getDifficultyLabel(difficulty: number): LanguageLevel;
4
4
  export declare function getNeighborDifficultyLevel(difficulty: LanguageLevel, difficultyAdjustment: number): LanguageLevel;
5
+ /**
6
+ * Compares two LanguageLevel values to determine their relative order.
7
+ * Returns:
8
+ * - negative number if level1 < level2
9
+ * - 0 if level1 === level2
10
+ * - positive number if level1 > level2
11
+ */
12
+ export declare function compareLanguageLevels(level1: LanguageLevel, level2: LanguageLevel): number;
@@ -8,3 +8,13 @@ export function getDifficultyLabel(difficulty) {
8
8
  export function getNeighborDifficultyLevel(difficulty, difficultyAdjustment) {
9
9
  return getDifficultyLabel(getDifficultyLevel(difficulty) + difficultyAdjustment - 1);
10
10
  }
11
+ /**
12
+ * Compares two LanguageLevel values to determine their relative order.
13
+ * Returns:
14
+ * - negative number if level1 < level2
15
+ * - 0 if level1 === level2
16
+ * - positive number if level1 > level2
17
+ */
18
+ export function compareLanguageLevels(level1, level2) {
19
+ return getDifficultyLevel(level1) - getDifficultyLevel(level2);
20
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rimori/client",
3
- "version": "2.5.8-next.0",
3
+ "version": "2.5.8-next.2",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "repository": {