@reverbia/sdk 1.0.0-next.20251217123222 → 1.0.0-next.20251217134403

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.
@@ -1440,20 +1440,42 @@ Please inform the user about this issue and try to help them alternatively.`
1440
1440
  }
1441
1441
  });
1442
1442
  const accumulator = createStreamAccumulator();
1443
- for await (const chunk of sseResult.stream) {
1444
- if (isDoneMarker(chunk)) {
1445
- continue;
1446
- }
1447
- if (chunk && typeof chunk === "object") {
1448
- const contentDelta = processStreamingChunk(
1449
- chunk,
1450
- accumulator
1451
- );
1452
- if (contentDelta) {
1453
- if (onData) onData(contentDelta);
1454
- if (globalOnData) globalOnData(contentDelta);
1443
+ try {
1444
+ for await (const chunk of sseResult.stream) {
1445
+ if (isDoneMarker(chunk)) {
1446
+ continue;
1455
1447
  }
1448
+ if (chunk && typeof chunk === "object") {
1449
+ const contentDelta = processStreamingChunk(
1450
+ chunk,
1451
+ accumulator
1452
+ );
1453
+ if (contentDelta) {
1454
+ if (onData) onData(contentDelta);
1455
+ if (globalOnData) globalOnData(contentDelta);
1456
+ }
1457
+ }
1458
+ }
1459
+ } catch (streamErr) {
1460
+ if (isAbortError(streamErr) || abortController.signal.aborted) {
1461
+ setIsLoading(false);
1462
+ const partialCompletion = buildCompletionResponse(accumulator);
1463
+ return {
1464
+ data: partialCompletion,
1465
+ error: "Request aborted",
1466
+ toolExecution: toolExecutionResult
1467
+ };
1456
1468
  }
1469
+ throw streamErr;
1470
+ }
1471
+ if (abortController.signal.aborted) {
1472
+ setIsLoading(false);
1473
+ const partialCompletion = buildCompletionResponse(accumulator);
1474
+ return {
1475
+ data: partialCompletion,
1476
+ error: "Request aborted",
1477
+ toolExecution: toolExecutionResult
1478
+ };
1457
1479
  }
1458
1480
  if (sseError) {
1459
1481
  throw sseError;
@@ -1678,7 +1700,8 @@ function messageToStored(message) {
1678
1700
  embeddingModel: message.embeddingModel,
1679
1701
  usage: message.usage,
1680
1702
  sources: message.sources,
1681
- responseDuration: message.responseDuration
1703
+ responseDuration: message.responseDuration,
1704
+ wasStopped: message.wasStopped
1682
1705
  };
1683
1706
  }
1684
1707
  function conversationToStored(conversation) {
@@ -1767,6 +1790,7 @@ async function createMessageOp(ctx, opts) {
1767
1790
  msg._setRaw("response_duration", opts.responseDuration);
1768
1791
  if (opts.vector) msg._setRaw("vector", JSON.stringify(opts.vector));
1769
1792
  if (opts.embeddingModel) msg._setRaw("embedding_model", opts.embeddingModel);
1793
+ if (opts.wasStopped) msg._setRaw("was_stopped", opts.wasStopped);
1770
1794
  });
1771
1795
  });
1772
1796
  return messageToStored(created);
@@ -2057,6 +2081,45 @@ function useChatStorage(options) {
2057
2081
  });
2058
2082
  const responseDuration = (Date.now() - startTime) / 1e3;
2059
2083
  if (result.error || !result.data) {
2084
+ const abortedResult = result;
2085
+ if (abortedResult.error === "Request aborted") {
2086
+ const assistantContent2 = abortedResult.data?.choices?.[0]?.message?.content?.map((part) => part.text || "").join("") || "";
2087
+ const responseModel = abortedResult.data?.model || model || "";
2088
+ let storedAssistantMessage2;
2089
+ try {
2090
+ storedAssistantMessage2 = await createMessageOp(storageCtx, {
2091
+ conversationId: convId,
2092
+ role: "assistant",
2093
+ content: assistantContent2,
2094
+ model: responseModel,
2095
+ usage: convertUsageToStored(abortedResult.data?.usage),
2096
+ responseDuration,
2097
+ wasStopped: true
2098
+ });
2099
+ const completionData = abortedResult.data || {
2100
+ id: `aborted-${Date.now()}`,
2101
+ model: responseModel,
2102
+ choices: [{
2103
+ index: 0,
2104
+ message: {
2105
+ role: "assistant",
2106
+ content: [{ type: "text", text: assistantContent2 }]
2107
+ },
2108
+ finish_reason: "stop"
2109
+ }],
2110
+ usage: void 0
2111
+ };
2112
+ return {
2113
+ data: completionData,
2114
+ error: null,
2115
+ // Treat as success to the caller
2116
+ toolExecution: abortedResult.toolExecution,
2117
+ userMessage: storedUserMessage,
2118
+ assistantMessage: storedAssistantMessage2
2119
+ };
2120
+ } catch (err) {
2121
+ }
2122
+ }
2060
2123
  return {
2061
2124
  data: null,
2062
2125
  error: result.error || "No response data received",
@@ -2128,8 +2191,9 @@ function useChatStorage(options) {
2128
2191
 
2129
2192
  // src/lib/chatStorage/schema.ts
2130
2193
  import { appSchema, tableSchema } from "@nozbe/watermelondb";
2194
+ import { schemaMigrations, addColumns } from "@nozbe/watermelondb/Schema/migrations";
2131
2195
  var chatStorageSchema = appSchema({
2132
- version: 1,
2196
+ version: 2,
2133
2197
  tables: [
2134
2198
  tableSchema({
2135
2199
  name: "history",
@@ -2152,7 +2216,8 @@ var chatStorageSchema = appSchema({
2152
2216
  // JSON stringified ChatCompletionUsage
2153
2217
  { name: "sources", type: "string", isOptional: true },
2154
2218
  // JSON stringified SearchSource[]
2155
- { name: "response_duration", type: "number", isOptional: true }
2219
+ { name: "response_duration", type: "number", isOptional: true },
2220
+ { name: "was_stopped", type: "boolean", isOptional: true }
2156
2221
  ]
2157
2222
  }),
2158
2223
  tableSchema({
@@ -2167,6 +2232,21 @@ var chatStorageSchema = appSchema({
2167
2232
  })
2168
2233
  ]
2169
2234
  });
2235
+ var chatStorageMigrations = schemaMigrations({
2236
+ migrations: [
2237
+ {
2238
+ toVersion: 2,
2239
+ steps: [
2240
+ addColumns({
2241
+ table: "history",
2242
+ columns: [
2243
+ { name: "was_stopped", type: "boolean", isOptional: true }
2244
+ ]
2245
+ })
2246
+ ]
2247
+ }
2248
+ ]
2249
+ });
2170
2250
 
2171
2251
  // src/lib/chatStorage/models.ts
2172
2252
  import { Model } from "@nozbe/watermelondb";
@@ -2250,6 +2330,10 @@ var Message = class extends Model {
2250
2330
  const value = this._getRaw("response_duration");
2251
2331
  return value !== null && value !== void 0 ? value : void 0;
2252
2332
  }
2333
+ /** Whether the message generation was stopped by the user */
2334
+ get wasStopped() {
2335
+ return this._getRaw("was_stopped");
2336
+ }
2253
2337
  };
2254
2338
  Message.table = "history";
2255
2339
  Message.associations = {
@@ -3452,8 +3536,180 @@ var Memory = class extends Model2 {
3452
3536
  };
3453
3537
  Memory.table = "memories";
3454
3538
 
3539
+ // src/react/useSettings.ts
3540
+ import { useCallback as useCallback4, useState as useState4, useMemo as useMemo3, useEffect as useEffect2 } from "react";
3541
+
3542
+ // src/lib/settingsStorage/operations.ts
3543
+ import { Q as Q3 } from "@nozbe/watermelondb";
3544
+ function modelPreferenceToStored(preference) {
3545
+ return {
3546
+ uniqueId: preference.id,
3547
+ walletAddress: preference.walletAddress,
3548
+ models: preference.models
3549
+ };
3550
+ }
3551
+ async function getModelPreferenceOp(ctx, walletAddress) {
3552
+ const results = await ctx.modelPreferencesCollection.query(Q3.where("wallet_address", walletAddress)).fetch();
3553
+ return results.length > 0 ? modelPreferenceToStored(results[0]) : null;
3554
+ }
3555
+ async function setModelPreferenceOp(ctx, walletAddress, models) {
3556
+ const result = await ctx.database.write(async () => {
3557
+ const results = await ctx.modelPreferencesCollection.query(Q3.where("wallet_address", walletAddress)).fetch();
3558
+ if (results.length > 0) {
3559
+ const preference = results[0];
3560
+ await preference.update((pref) => {
3561
+ if (models !== void 0) {
3562
+ pref._setRaw("models", models || null);
3563
+ }
3564
+ });
3565
+ return preference;
3566
+ }
3567
+ return await ctx.modelPreferencesCollection.create((pref) => {
3568
+ pref._setRaw("wallet_address", walletAddress);
3569
+ if (models) pref._setRaw("models", models);
3570
+ });
3571
+ });
3572
+ return modelPreferenceToStored(result);
3573
+ }
3574
+ async function deleteModelPreferenceOp(ctx, walletAddress) {
3575
+ const results = await ctx.modelPreferencesCollection.query(Q3.where("wallet_address", walletAddress)).fetch();
3576
+ if (results.length === 0) return false;
3577
+ await ctx.database.write(async () => {
3578
+ await results[0].destroyPermanently();
3579
+ });
3580
+ return true;
3581
+ }
3582
+
3583
+ // src/react/useSettings.ts
3584
+ function useSettings(options) {
3585
+ const { database, walletAddress } = options;
3586
+ const [modelPreference, setModelPreferenceState] = useState4(null);
3587
+ const [isLoading, setIsLoading] = useState4(false);
3588
+ const modelPreferencesCollection = useMemo3(
3589
+ () => database.get("modelPreferences"),
3590
+ [database]
3591
+ );
3592
+ const storageCtx = useMemo3(
3593
+ () => ({
3594
+ database,
3595
+ modelPreferencesCollection
3596
+ }),
3597
+ [database, modelPreferencesCollection]
3598
+ );
3599
+ const getModelPreference = useCallback4(
3600
+ async (address) => {
3601
+ try {
3602
+ if (!address) throw new Error("Wallet address is required");
3603
+ const result = await getModelPreferenceOp(storageCtx, address);
3604
+ return result;
3605
+ } catch (error) {
3606
+ throw new Error(
3607
+ error instanceof Error ? error.message : "An unknown error occurred"
3608
+ );
3609
+ }
3610
+ },
3611
+ [storageCtx]
3612
+ );
3613
+ const setModelPreference = useCallback4(
3614
+ async (address, models) => {
3615
+ try {
3616
+ if (!address) throw new Error("Wallet address is required");
3617
+ const result = await setModelPreferenceOp(storageCtx, address, models);
3618
+ if (walletAddress && address === walletAddress) {
3619
+ setModelPreferenceState(result);
3620
+ }
3621
+ return result;
3622
+ } catch (error) {
3623
+ throw new Error(
3624
+ error instanceof Error ? error.message : "An unknown error occurred"
3625
+ );
3626
+ }
3627
+ },
3628
+ [storageCtx, walletAddress]
3629
+ );
3630
+ const deleteModelPreference = useCallback4(
3631
+ async (address) => {
3632
+ try {
3633
+ if (!address) throw new Error("Wallet address is required");
3634
+ const deleted = await deleteModelPreferenceOp(storageCtx, address);
3635
+ if (deleted && walletAddress && address === walletAddress) {
3636
+ setModelPreferenceState(null);
3637
+ }
3638
+ return deleted;
3639
+ } catch (error) {
3640
+ throw new Error(
3641
+ error instanceof Error ? error.message : "An unknown error occurred"
3642
+ );
3643
+ }
3644
+ },
3645
+ [storageCtx, walletAddress]
3646
+ );
3647
+ useEffect2(() => {
3648
+ if (!walletAddress) {
3649
+ setModelPreferenceState(null);
3650
+ return;
3651
+ }
3652
+ let cancelled = false;
3653
+ const loadPreference = async () => {
3654
+ setIsLoading(true);
3655
+ try {
3656
+ const preference = await getModelPreference(walletAddress);
3657
+ if (!cancelled) {
3658
+ setModelPreferenceState(preference);
3659
+ }
3660
+ } finally {
3661
+ if (!cancelled) {
3662
+ setIsLoading(false);
3663
+ }
3664
+ }
3665
+ };
3666
+ loadPreference();
3667
+ return () => {
3668
+ cancelled = true;
3669
+ };
3670
+ }, [walletAddress, getModelPreference]);
3671
+ return {
3672
+ modelPreference,
3673
+ isLoading,
3674
+ getModelPreference,
3675
+ setModelPreference,
3676
+ deleteModelPreference
3677
+ };
3678
+ }
3679
+
3680
+ // src/lib/settingsStorage/schema.ts
3681
+ import { appSchema as appSchema3, tableSchema as tableSchema3 } from "@nozbe/watermelondb";
3682
+ var settingsStorageSchema = appSchema3({
3683
+ version: 1,
3684
+ tables: [
3685
+ tableSchema3({
3686
+ name: "modelPreferences",
3687
+ columns: [
3688
+ { name: "wallet_address", type: "string", isIndexed: true },
3689
+ { name: "models", type: "string", isOptional: true }
3690
+ // stored as JSON stringified ModelPreference[]
3691
+ ]
3692
+ })
3693
+ ]
3694
+ });
3695
+
3696
+ // src/lib/settingsStorage/models.ts
3697
+ import { Model as Model3 } from "@nozbe/watermelondb";
3698
+ var ModelPreference = class extends Model3 {
3699
+ /** User's wallet address */
3700
+ get walletAddress() {
3701
+ return this._getRaw("wallet_address");
3702
+ }
3703
+ /** Preferred model identifier */
3704
+ get models() {
3705
+ const value = this._getRaw("models");
3706
+ return value ? value : void 0;
3707
+ }
3708
+ };
3709
+ ModelPreference.table = "modelPreferences";
3710
+
3455
3711
  // src/react/usePdf.ts
3456
- import { useCallback as useCallback4, useState as useState4 } from "react";
3712
+ import { useCallback as useCallback5, useState as useState5 } from "react";
3457
3713
 
3458
3714
  // src/lib/pdf.ts
3459
3715
  import * as pdfjs from "pdfjs-dist";
@@ -3506,9 +3762,9 @@ async function convertPdfToImages(pdfDataUrl) {
3506
3762
  // src/react/usePdf.ts
3507
3763
  var PDF_MIME_TYPE = "application/pdf";
3508
3764
  function usePdf() {
3509
- const [isProcessing, setIsProcessing] = useState4(false);
3510
- const [error, setError] = useState4(null);
3511
- const extractPdfContext = useCallback4(
3765
+ const [isProcessing, setIsProcessing] = useState5(false);
3766
+ const [error, setError] = useState5(null);
3767
+ const extractPdfContext = useCallback5(
3512
3768
  async (files) => {
3513
3769
  setIsProcessing(true);
3514
3770
  setError(null);
@@ -3555,12 +3811,12 @@ ${text}`;
3555
3811
  }
3556
3812
 
3557
3813
  // src/react/useOCR.ts
3558
- import { useCallback as useCallback5, useState as useState5 } from "react";
3814
+ import { useCallback as useCallback6, useState as useState6 } from "react";
3559
3815
  import Tesseract from "tesseract.js";
3560
3816
  function useOCR() {
3561
- const [isProcessing, setIsProcessing] = useState5(false);
3562
- const [error, setError] = useState5(null);
3563
- const extractOCRContext = useCallback5(
3817
+ const [isProcessing, setIsProcessing] = useState6(false);
3818
+ const [error, setError] = useState6(null);
3819
+ const extractOCRContext = useCallback6(
3564
3820
  async (files) => {
3565
3821
  setIsProcessing(true);
3566
3822
  setError(null);
@@ -3646,22 +3902,22 @@ ${text}`;
3646
3902
  }
3647
3903
 
3648
3904
  // src/react/useModels.ts
3649
- import { useCallback as useCallback6, useEffect as useEffect2, useRef as useRef3, useState as useState6 } from "react";
3905
+ import { useCallback as useCallback7, useEffect as useEffect3, useRef as useRef3, useState as useState7 } from "react";
3650
3906
  function useModels(options = {}) {
3651
3907
  const { getToken, baseUrl = BASE_URL, provider, autoFetch = true } = options;
3652
- const [models, setModels] = useState6([]);
3653
- const [isLoading, setIsLoading] = useState6(false);
3654
- const [error, setError] = useState6(null);
3908
+ const [models, setModels] = useState7([]);
3909
+ const [isLoading, setIsLoading] = useState7(false);
3910
+ const [error, setError] = useState7(null);
3655
3911
  const getTokenRef = useRef3(getToken);
3656
3912
  const baseUrlRef = useRef3(baseUrl);
3657
3913
  const providerRef = useRef3(provider);
3658
3914
  const abortControllerRef = useRef3(null);
3659
- useEffect2(() => {
3915
+ useEffect3(() => {
3660
3916
  getTokenRef.current = getToken;
3661
3917
  baseUrlRef.current = baseUrl;
3662
3918
  providerRef.current = provider;
3663
3919
  });
3664
- useEffect2(() => {
3920
+ useEffect3(() => {
3665
3921
  return () => {
3666
3922
  if (abortControllerRef.current) {
3667
3923
  abortControllerRef.current.abort();
@@ -3669,7 +3925,7 @@ function useModels(options = {}) {
3669
3925
  }
3670
3926
  };
3671
3927
  }, []);
3672
- const fetchModels = useCallback6(async () => {
3928
+ const fetchModels = useCallback7(async () => {
3673
3929
  if (abortControllerRef.current) {
3674
3930
  abortControllerRef.current.abort();
3675
3931
  }
@@ -3727,12 +3983,12 @@ function useModels(options = {}) {
3727
3983
  }
3728
3984
  }
3729
3985
  }, []);
3730
- const refetch = useCallback6(async () => {
3986
+ const refetch = useCallback7(async () => {
3731
3987
  setModels([]);
3732
3988
  await fetchModels();
3733
3989
  }, [fetchModels]);
3734
3990
  const hasFetchedRef = useRef3(false);
3735
- useEffect2(() => {
3991
+ useEffect3(() => {
3736
3992
  if (autoFetch && !hasFetchedRef.current) {
3737
3993
  hasFetchedRef.current = true;
3738
3994
  fetchModels();
@@ -3750,15 +4006,15 @@ function useModels(options = {}) {
3750
4006
  }
3751
4007
 
3752
4008
  // src/react/useSearch.ts
3753
- import { useCallback as useCallback7, useEffect as useEffect3, useRef as useRef4, useState as useState7 } from "react";
4009
+ import { useCallback as useCallback8, useEffect as useEffect4, useRef as useRef4, useState as useState8 } from "react";
3754
4010
  function useSearch(options = {}) {
3755
4011
  const { getToken, baseUrl = BASE_URL, onError } = options;
3756
- const [isLoading, setIsLoading] = useState7(false);
3757
- const [results, setResults] = useState7(null);
3758
- const [response, setResponse] = useState7(null);
3759
- const [error, setError] = useState7(null);
4012
+ const [isLoading, setIsLoading] = useState8(false);
4013
+ const [results, setResults] = useState8(null);
4014
+ const [response, setResponse] = useState8(null);
4015
+ const [error, setError] = useState8(null);
3760
4016
  const abortControllerRef = useRef4(null);
3761
- useEffect3(() => {
4017
+ useEffect4(() => {
3762
4018
  return () => {
3763
4019
  if (abortControllerRef.current) {
3764
4020
  abortControllerRef.current.abort();
@@ -3766,7 +4022,7 @@ function useSearch(options = {}) {
3766
4022
  }
3767
4023
  };
3768
4024
  }, []);
3769
- const search = useCallback7(
4025
+ const search = useCallback8(
3770
4026
  async (query, searchOptions = {}) => {
3771
4027
  if (abortControllerRef.current) {
3772
4028
  abortControllerRef.current.abort();
@@ -3834,12 +4090,12 @@ function useSearch(options = {}) {
3834
4090
  }
3835
4091
 
3836
4092
  // src/react/useImageGeneration.ts
3837
- import { useCallback as useCallback8, useEffect as useEffect4, useRef as useRef5, useState as useState8 } from "react";
4093
+ import { useCallback as useCallback9, useEffect as useEffect5, useRef as useRef5, useState as useState9 } from "react";
3838
4094
  function useImageGeneration(options = {}) {
3839
4095
  const { getToken, baseUrl = BASE_URL, onFinish, onError } = options;
3840
- const [isLoading, setIsLoading] = useState8(false);
4096
+ const [isLoading, setIsLoading] = useState9(false);
3841
4097
  const abortControllerRef = useRef5(null);
3842
- useEffect4(() => {
4098
+ useEffect5(() => {
3843
4099
  return () => {
3844
4100
  if (abortControllerRef.current) {
3845
4101
  abortControllerRef.current.abort();
@@ -3847,13 +4103,13 @@ function useImageGeneration(options = {}) {
3847
4103
  }
3848
4104
  };
3849
4105
  }, []);
3850
- const stop = useCallback8(() => {
4106
+ const stop = useCallback9(() => {
3851
4107
  if (abortControllerRef.current) {
3852
4108
  abortControllerRef.current.abort();
3853
4109
  abortControllerRef.current = null;
3854
4110
  }
3855
4111
  }, []);
3856
- const generateImage = useCallback8(
4112
+ const generateImage = useCallback9(
3857
4113
  async (args) => {
3858
4114
  if (abortControllerRef.current) {
3859
4115
  abortControllerRef.current.abort();
@@ -3974,6 +4230,8 @@ export {
3974
4230
  Message as ChatMessage,
3975
4231
  DEFAULT_TOOL_SELECTOR_MODEL,
3976
4232
  Memory as StoredMemoryModel,
4233
+ ModelPreference as StoredModelPreferenceModel,
4234
+ chatStorageMigrations,
3977
4235
  chatStorageSchema,
3978
4236
  createMemoryContextSystemMessage,
3979
4237
  decryptData,
@@ -3989,6 +4247,7 @@ export {
3989
4247
  memoryStorageSchema,
3990
4248
  requestEncryptionKey,
3991
4249
  selectTool,
4250
+ settingsStorageSchema,
3992
4251
  useChat,
3993
4252
  useChatStorage,
3994
4253
  useEncryption,
@@ -3997,5 +4256,6 @@ export {
3997
4256
  useModels,
3998
4257
  useOCR,
3999
4258
  usePdf,
4000
- useSearch
4259
+ useSearch,
4260
+ useSettings
4001
4261
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@reverbia/sdk",
3
- "version": "1.0.0-next.20251217123222",
3
+ "version": "1.0.0-next.20251217134403",
4
4
  "description": "",
5
5
  "main": "./dist/index.cjs",
6
6
  "module": "./dist/index.mjs",