@reverbia/sdk 1.0.0-next.20251208112742 → 1.0.0-next.20251208162906

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.
@@ -30,7 +30,136 @@ var import_react = require("react");
30
30
  // src/clientConfig.ts
31
31
  var BASE_URL = "https://ai-portal-dev.zetachain.com";
32
32
 
33
+ // src/lib/chat/useChat/utils.ts
34
+ var VALIDATION_ERROR_MESSAGES = {
35
+ messages_required: "messages are required to call sendMessage.",
36
+ model_required: "model is required to call sendMessage.",
37
+ token_getter_required: "Token getter function is required.",
38
+ token_unavailable: "No access token available."
39
+ };
40
+ function validateMessages(messages) {
41
+ if (!messages?.length) {
42
+ return {
43
+ valid: false,
44
+ error: "messages_required",
45
+ message: VALIDATION_ERROR_MESSAGES.messages_required
46
+ };
47
+ }
48
+ return { valid: true };
49
+ }
50
+ function validateModel(model) {
51
+ if (!model) {
52
+ return {
53
+ valid: false,
54
+ error: "model_required",
55
+ message: VALIDATION_ERROR_MESSAGES.model_required
56
+ };
57
+ }
58
+ return { valid: true };
59
+ }
60
+ function validateTokenGetter(getToken) {
61
+ if (!getToken) {
62
+ return {
63
+ valid: false,
64
+ error: "token_getter_required",
65
+ message: VALIDATION_ERROR_MESSAGES.token_getter_required
66
+ };
67
+ }
68
+ return { valid: true };
69
+ }
70
+ function validateToken(token) {
71
+ if (!token) {
72
+ return {
73
+ valid: false,
74
+ error: "token_unavailable",
75
+ message: VALIDATION_ERROR_MESSAGES.token_unavailable
76
+ };
77
+ }
78
+ return { valid: true };
79
+ }
80
+ function createStreamAccumulator() {
81
+ return {
82
+ content: "",
83
+ completionId: "",
84
+ completionModel: "",
85
+ usage: {},
86
+ finishReason: void 0
87
+ };
88
+ }
89
+ function buildCompletionResponse(accumulator) {
90
+ return {
91
+ id: accumulator.completionId,
92
+ model: accumulator.completionModel,
93
+ choices: [
94
+ {
95
+ index: 0,
96
+ message: {
97
+ role: "assistant",
98
+ content: [{ type: "text", text: accumulator.content }]
99
+ },
100
+ finish_reason: accumulator.finishReason
101
+ }
102
+ ],
103
+ usage: Object.keys(accumulator.usage).length > 0 ? accumulator.usage : void 0
104
+ };
105
+ }
106
+ function createErrorResult(message, onError) {
107
+ if (onError) {
108
+ onError(new Error(message));
109
+ }
110
+ return { data: null, error: message };
111
+ }
112
+ function handleError(err, onError) {
113
+ const errorMsg = err instanceof Error ? err.message : "Failed to send message.";
114
+ const errorObj = err instanceof Error ? err : new Error(errorMsg);
115
+ if (onError) {
116
+ onError(errorObj);
117
+ }
118
+ return { data: null, error: errorMsg };
119
+ }
120
+ function parseSSEDataLine(line) {
121
+ if (!line.startsWith("data: ")) {
122
+ return null;
123
+ }
124
+ const data = line.substring(6).trim();
125
+ if (data === "[DONE]") {
126
+ return null;
127
+ }
128
+ try {
129
+ return JSON.parse(data);
130
+ } catch {
131
+ return null;
132
+ }
133
+ }
134
+
33
135
  // src/expo/useChat.ts
136
+ function processSSELines(lines, accumulator, onData, globalOnData) {
137
+ for (const line of lines) {
138
+ const chunk = parseSSEDataLine(line);
139
+ if (!chunk) continue;
140
+ if (chunk.id && !accumulator.completionId) {
141
+ accumulator.completionId = chunk.id;
142
+ }
143
+ if (chunk.model && !accumulator.completionModel) {
144
+ accumulator.completionModel = chunk.model;
145
+ }
146
+ if (chunk.usage) {
147
+ accumulator.usage = { ...accumulator.usage, ...chunk.usage };
148
+ }
149
+ if (chunk.choices?.[0]) {
150
+ const choice = chunk.choices[0];
151
+ if (choice.delta?.content) {
152
+ const content = choice.delta.content;
153
+ accumulator.content += content;
154
+ if (onData) onData(content);
155
+ if (globalOnData) globalOnData(content);
156
+ }
157
+ if (choice.finish_reason) {
158
+ accumulator.finishReason = choice.finish_reason;
159
+ }
160
+ }
161
+ }
162
+ }
34
163
  function useChat(options) {
35
164
  const {
36
165
  getToken,
@@ -61,20 +190,17 @@ function useChat(options) {
61
190
  model,
62
191
  onData
63
192
  }) => {
64
- if (!messages?.length) {
65
- const errorMsg = "messages are required to call sendMessage.";
66
- if (onError) onError(new Error(errorMsg));
67
- return { data: null, error: errorMsg };
193
+ const messagesValidation = validateMessages(messages);
194
+ if (!messagesValidation.valid) {
195
+ return createErrorResult(messagesValidation.message, onError);
68
196
  }
69
- if (!model) {
70
- const errorMsg = "model is required to call sendMessage.";
71
- if (onError) onError(new Error(errorMsg));
72
- return { data: null, error: errorMsg };
197
+ const modelValidation = validateModel(model);
198
+ if (!modelValidation.valid) {
199
+ return createErrorResult(modelValidation.message, onError);
73
200
  }
74
- if (!getToken) {
75
- const errorMsg = "Token getter function is required.";
76
- if (onError) onError(new Error(errorMsg));
77
- return { data: null, error: errorMsg };
201
+ const tokenGetterValidation = validateTokenGetter(getToken);
202
+ if (!tokenGetterValidation.valid) {
203
+ return createErrorResult(tokenGetterValidation.message, onError);
78
204
  }
79
205
  if (abortControllerRef.current) {
80
206
  abortControllerRef.current.abort();
@@ -84,20 +210,15 @@ function useChat(options) {
84
210
  setIsLoading(true);
85
211
  try {
86
212
  const token = await getToken();
87
- if (!token) {
88
- const errorMsg = "No access token available.";
213
+ const tokenValidation = validateToken(token);
214
+ if (!tokenValidation.valid) {
89
215
  setIsLoading(false);
90
- if (onError) onError(new Error(errorMsg));
91
- return { data: null, error: errorMsg };
216
+ return createErrorResult(tokenValidation.message, onError);
92
217
  }
93
218
  const result = await new Promise((resolve) => {
94
219
  const xhr = new XMLHttpRequest();
95
220
  const url = `${baseUrl}/api/v1/chat/completions`;
96
- let accumulatedContent = "";
97
- let completionId = "";
98
- let completionModel = "";
99
- let accumulatedUsage = {};
100
- let finishReason;
221
+ const accumulator = createStreamAccumulator();
101
222
  let lastProcessedIndex = 0;
102
223
  let incompleteLineBuffer = "";
103
224
  const abortHandler = () => {
@@ -117,93 +238,21 @@ function useChat(options) {
117
238
  if (!newData.endsWith("\n") && lines.length > 0) {
118
239
  incompleteLineBuffer = lines.pop() || "";
119
240
  }
120
- for (const line of lines) {
121
- if (line.startsWith("data: ")) {
122
- const data = line.substring(6).trim();
123
- if (data === "[DONE]") continue;
124
- try {
125
- const chunk = JSON.parse(data);
126
- if (chunk.id && !completionId) {
127
- completionId = chunk.id;
128
- }
129
- if (chunk.model && !completionModel) {
130
- completionModel = chunk.model;
131
- }
132
- if (chunk.usage) {
133
- accumulatedUsage = { ...accumulatedUsage, ...chunk.usage };
134
- }
135
- if (chunk.choices?.[0]) {
136
- const choice = chunk.choices[0];
137
- if (choice.delta?.content) {
138
- const content = choice.delta.content;
139
- accumulatedContent += content;
140
- if (onData) onData(content);
141
- if (globalOnData) globalOnData(content);
142
- }
143
- if (choice.finish_reason) {
144
- finishReason = choice.finish_reason;
145
- }
146
- }
147
- } catch {
148
- }
149
- }
150
- }
241
+ processSSELines(lines, accumulator, onData, globalOnData);
151
242
  };
152
243
  xhr.onload = () => {
153
244
  abortController.signal.removeEventListener("abort", abortHandler);
154
245
  if (incompleteLineBuffer) {
155
- const line = incompleteLineBuffer.trim();
156
- if (line.startsWith("data: ")) {
157
- const data = line.substring(6).trim();
158
- if (data !== "[DONE]") {
159
- try {
160
- const chunk = JSON.parse(data);
161
- if (chunk.id && !completionId) {
162
- completionId = chunk.id;
163
- }
164
- if (chunk.model && !completionModel) {
165
- completionModel = chunk.model;
166
- }
167
- if (chunk.usage) {
168
- accumulatedUsage = {
169
- ...accumulatedUsage,
170
- ...chunk.usage
171
- };
172
- }
173
- if (chunk.choices?.[0]) {
174
- const choice = chunk.choices[0];
175
- if (choice.delta?.content) {
176
- const content = choice.delta.content;
177
- accumulatedContent += content;
178
- if (onData) onData(content);
179
- if (globalOnData) globalOnData(content);
180
- }
181
- if (choice.finish_reason) {
182
- finishReason = choice.finish_reason;
183
- }
184
- }
185
- } catch {
186
- }
187
- }
188
- }
246
+ processSSELines(
247
+ [incompleteLineBuffer.trim()],
248
+ accumulator,
249
+ onData,
250
+ globalOnData
251
+ );
189
252
  incompleteLineBuffer = "";
190
253
  }
191
254
  if (xhr.status >= 200 && xhr.status < 300) {
192
- const completion = {
193
- id: completionId,
194
- model: completionModel,
195
- choices: [
196
- {
197
- index: 0,
198
- message: {
199
- role: "assistant",
200
- content: [{ type: "text", text: accumulatedContent }]
201
- },
202
- finish_reason: finishReason
203
- }
204
- ],
205
- usage: Object.keys(accumulatedUsage).length > 0 ? accumulatedUsage : void 0
206
- };
255
+ const completion = buildCompletionResponse(accumulator);
207
256
  setIsLoading(false);
208
257
  if (onFinish) onFinish(completion);
209
258
  resolve({ data: completion, error: null });
@@ -236,13 +285,8 @@ function useChat(options) {
236
285
  });
237
286
  return result;
238
287
  } catch (err) {
239
- const errorMsg = err instanceof Error ? err.message : "Failed to send message.";
240
- const errorObj = err instanceof Error ? err : new Error(errorMsg);
241
288
  setIsLoading(false);
242
- if (onError) {
243
- onError(errorObj);
244
- }
245
- return { data: null, error: errorMsg };
289
+ return handleError(err, onError);
246
290
  } finally {
247
291
  if (abortControllerRef.current === abortController) {
248
292
  abortControllerRef.current = null;
@@ -106,7 +106,10 @@ type LlmapiMessageContentPart = {
106
106
  */
107
107
  type LlmapiRole = string;
108
108
 
109
- type SendMessageArgs = {
109
+ /**
110
+ * Base arguments for sending a message
111
+ */
112
+ type BaseSendMessageArgs = {
110
113
  messages: LlmapiMessage[];
111
114
  model?: string;
112
115
  /**
@@ -117,14 +120,20 @@ type SendMessageArgs = {
117
120
  */
118
121
  onData?: (chunk: string) => void;
119
122
  };
120
- type SendMessageResult = {
123
+ /**
124
+ * Base result type for sendMessage
125
+ */
126
+ type BaseSendMessageResult = {
121
127
  data: LlmapiChatCompletionResponse;
122
128
  error: null;
123
129
  } | {
124
130
  data: null;
125
131
  error: string;
126
132
  };
127
- type UseChatOptions = {
133
+ /**
134
+ * Base options for useChat hook
135
+ */
136
+ type BaseUseChatOptions = {
128
137
  getToken?: () => Promise<string | null>;
129
138
  baseUrl?: string;
130
139
  /**
@@ -147,9 +156,11 @@ type UseChatOptions = {
147
156
  */
148
157
  onError?: (error: Error) => void;
149
158
  };
150
- type UseChatResult = {
159
+ /**
160
+ * Base result type for useChat hook
161
+ */
162
+ type BaseUseChatResult = {
151
163
  isLoading: boolean;
152
- sendMessage: (args: SendMessageArgs) => Promise<SendMessageResult>;
153
164
  /**
154
165
  * Aborts the current streaming request if one is in progress.
155
166
  *
@@ -159,6 +170,13 @@ type UseChatResult = {
159
170
  */
160
171
  stop: () => void;
161
172
  };
173
+
174
+ type SendMessageArgs = BaseSendMessageArgs;
175
+ type SendMessageResult = BaseSendMessageResult;
176
+ type UseChatOptions = BaseUseChatOptions;
177
+ type UseChatResult = BaseUseChatResult & {
178
+ sendMessage: (args: SendMessageArgs) => Promise<SendMessageResult>;
179
+ };
162
180
  /**
163
181
  * A React hook for managing chat completions with authentication.
164
182
  *
@@ -106,7 +106,10 @@ type LlmapiMessageContentPart = {
106
106
  */
107
107
  type LlmapiRole = string;
108
108
 
109
- type SendMessageArgs = {
109
+ /**
110
+ * Base arguments for sending a message
111
+ */
112
+ type BaseSendMessageArgs = {
110
113
  messages: LlmapiMessage[];
111
114
  model?: string;
112
115
  /**
@@ -117,14 +120,20 @@ type SendMessageArgs = {
117
120
  */
118
121
  onData?: (chunk: string) => void;
119
122
  };
120
- type SendMessageResult = {
123
+ /**
124
+ * Base result type for sendMessage
125
+ */
126
+ type BaseSendMessageResult = {
121
127
  data: LlmapiChatCompletionResponse;
122
128
  error: null;
123
129
  } | {
124
130
  data: null;
125
131
  error: string;
126
132
  };
127
- type UseChatOptions = {
133
+ /**
134
+ * Base options for useChat hook
135
+ */
136
+ type BaseUseChatOptions = {
128
137
  getToken?: () => Promise<string | null>;
129
138
  baseUrl?: string;
130
139
  /**
@@ -147,9 +156,11 @@ type UseChatOptions = {
147
156
  */
148
157
  onError?: (error: Error) => void;
149
158
  };
150
- type UseChatResult = {
159
+ /**
160
+ * Base result type for useChat hook
161
+ */
162
+ type BaseUseChatResult = {
151
163
  isLoading: boolean;
152
- sendMessage: (args: SendMessageArgs) => Promise<SendMessageResult>;
153
164
  /**
154
165
  * Aborts the current streaming request if one is in progress.
155
166
  *
@@ -159,6 +170,13 @@ type UseChatResult = {
159
170
  */
160
171
  stop: () => void;
161
172
  };
173
+
174
+ type SendMessageArgs = BaseSendMessageArgs;
175
+ type SendMessageResult = BaseSendMessageResult;
176
+ type UseChatOptions = BaseUseChatOptions;
177
+ type UseChatResult = BaseUseChatResult & {
178
+ sendMessage: (args: SendMessageArgs) => Promise<SendMessageResult>;
179
+ };
162
180
  /**
163
181
  * A React hook for managing chat completions with authentication.
164
182
  *