@aomi-labs/react 0.3.2 → 0.3.4

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/README.md CHANGED
@@ -10,12 +10,16 @@ npm install @aomi-labs/react @assistant-ui/react react react-dom
10
10
  pnpm add @aomi-labs/react @assistant-ui/react react react-dom
11
11
  ```
12
12
 
13
- Optional peer dependencies for wallet features:
13
+ Optional dependencies for advanced custom wallet adapters:
14
14
 
15
15
  ```bash
16
16
  pnpm add wagmi viem
17
17
  ```
18
18
 
19
+ If you use the registry-installed `AomiFrame`, the default Para-backed
20
+ `AomiAdapterProvider` is already wired for you. Add `wagmi` only when you want
21
+ to bring your own adapter implementation.
22
+
19
23
  ## Quick Start
20
24
 
21
25
  Wrap your app with `AomiRuntimeProvider`, then use `useAomiRuntime()` anywhere inside:
@@ -117,7 +121,7 @@ Returns an `AomiRuntimeApi` object with:
117
121
  | `useControl()` | Model/namespace/API key state |
118
122
  | `useNotification()` | Toast notification context |
119
123
  | `useEventContext()` | Raw event system access |
120
- | `useWalletHandler()` | Wallet request handler (auto-sign with wagmi) |
124
+ | `useWalletHandler()` | Wallet request handler for custom adapter implementations |
121
125
  | `useNotificationHandler()` | Notification event handler |
122
126
 
123
127
  ## Utilities
package/dist/index.cjs CHANGED
@@ -276,6 +276,7 @@ function ControlContextProvider({
276
276
  var _a, _b;
277
277
  const [state, setStateInternal] = (0, import_react.useState)(() => ({
278
278
  apiKey: null,
279
+ clientId: null,
279
280
  availableModels: [],
280
281
  authorizedApps: [],
281
282
  defaultModel: null,
@@ -296,6 +297,11 @@ function ControlContextProvider({
296
297
  const callbacks = (0, import_react.useRef)(/* @__PURE__ */ new Set());
297
298
  const currentThreadMetadata = getThreadMetadata(sessionId);
298
299
  const isProcessing = (_b = (_a = currentThreadMetadata == null ? void 0 : currentThreadMetadata.control) == null ? void 0 : _a.isProcessing) != null ? _b : false;
300
+ (0, import_react.useEffect)(() => {
301
+ var _a2, _b2, _c;
302
+ const clientId = (_c = (_b2 = (_a2 = globalThis.crypto) == null ? void 0 : _a2.randomUUID) == null ? void 0 : _b2.call(_a2)) != null ? _c : `client-${Date.now()}`;
303
+ setStateInternal((prev) => __spreadProps(__spreadValues({}, prev), { clientId }));
304
+ }, []);
299
305
  (0, import_react.useEffect)(() => {
300
306
  var _a2, _b2;
301
307
  try {
@@ -369,6 +375,24 @@ function ControlContextProvider({
369
375
  return next;
370
376
  });
371
377
  }, []);
378
+ const ingestSecrets = (0, import_react.useCallback)(
379
+ async (secrets) => {
380
+ const clientId = stateRef.current.clientId;
381
+ if (!clientId) throw new Error("clientId not initialized");
382
+ const { handles } = await aomiClientRef.current.ingestSecrets(
383
+ clientId,
384
+ secrets
385
+ );
386
+ return handles;
387
+ },
388
+ []
389
+ );
390
+ const clearSecrets = (0, import_react.useCallback)(async () => {
391
+ var _a2, _b2;
392
+ const clientId = stateRef.current.clientId;
393
+ if (!clientId) return;
394
+ await ((_b2 = (_a2 = aomiClientRef.current).clearSecrets) == null ? void 0 : _b2.call(_a2, clientId));
395
+ }, []);
372
396
  const getAvailableModels = (0, import_react.useCallback)(async () => {
373
397
  try {
374
398
  const models = await aomiClientRef.current.getModels(
@@ -549,6 +573,8 @@ function ControlContextProvider({
549
573
  value: {
550
574
  state,
551
575
  setApiKey,
576
+ ingestSecrets,
577
+ clearSecrets,
552
578
  getAvailableModels,
553
579
  getAuthorizedApps,
554
580
  getCurrentThreadControl,
@@ -840,6 +866,8 @@ function useUser() {
840
866
  return {
841
867
  user: context.user,
842
868
  setUser: context.setUser,
869
+ addExtValue: context.addExtValue,
870
+ removeExtValue: context.removeExtValue,
843
871
  getUserState: context.getUserState,
844
872
  onUserStateChange: context.onUserStateChange
845
873
  };
@@ -849,7 +877,8 @@ function UserContextProvider({ children }) {
849
877
  isConnected: false,
850
878
  address: void 0,
851
879
  chainId: void 0,
852
- ensName: void 0
880
+ ensName: void 0,
881
+ ext: void 0
853
882
  });
854
883
  const userRef = (0, import_react5.useRef)(user);
855
884
  userRef.current = user;
@@ -865,6 +894,36 @@ function UserContextProvider({ children }) {
865
894
  return next;
866
895
  });
867
896
  }, []);
897
+ const addExtValue = (0, import_react5.useCallback)((key, value) => {
898
+ setUserState((prev) => {
899
+ var _a;
900
+ const next = __spreadProps(__spreadValues({}, prev), {
901
+ ext: __spreadProps(__spreadValues({}, (_a = prev.ext) != null ? _a : {}), {
902
+ [key]: value
903
+ })
904
+ });
905
+ StateChangeCallbacks.current.forEach((callback) => {
906
+ callback(next);
907
+ });
908
+ return next;
909
+ });
910
+ }, []);
911
+ const removeExtValue = (0, import_react5.useCallback)((key) => {
912
+ setUserState((prev) => {
913
+ if (!prev.ext || !(key in prev.ext)) {
914
+ return prev;
915
+ }
916
+ const nextExt = __spreadValues({}, prev.ext);
917
+ delete nextExt[key];
918
+ const next = __spreadProps(__spreadValues({}, prev), {
919
+ ext: Object.keys(nextExt).length > 0 ? nextExt : void 0
920
+ });
921
+ StateChangeCallbacks.current.forEach((callback) => {
922
+ callback(next);
923
+ });
924
+ return next;
925
+ });
926
+ }, []);
868
927
  const getUserState = (0, import_react5.useCallback)(() => userRef.current, []);
869
928
  const onUserStateChange = (0, import_react5.useCallback)(
870
929
  (callback) => {
@@ -881,6 +940,8 @@ function UserContextProvider({ children }) {
881
940
  value: {
882
941
  user,
883
942
  setUser,
943
+ addExtValue,
944
+ removeExtValue,
884
945
  getUserState,
885
946
  onUserStateChange
886
947
  },
@@ -1035,7 +1096,7 @@ var MessageController = class {
1035
1096
  this.getThreadContextApi().setThreadMessages(threadId, threadMessages);
1036
1097
  }
1037
1098
  async outbound(message, threadId) {
1038
- var _a, _b, _c, _d, _e, _f, _g, _h;
1099
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
1039
1100
  const backendState = this.config.backendStateRef.current;
1040
1101
  const text = message.content.filter(
1041
1102
  (part) => part.type === "text"
@@ -1058,18 +1119,19 @@ var MessageController = class {
1058
1119
  const app = this.config.getApp();
1059
1120
  const publicKey = (_b = (_a = this.config).getPublicKey) == null ? void 0 : _b.call(_a);
1060
1121
  const apiKey = (_e = (_d = (_c = this.config).getApiKey) == null ? void 0 : _d.call(_c)) != null ? _e : void 0;
1061
- const userState = (_g = (_f = this.config).getUserState) == null ? void 0 : _g.call(_f);
1122
+ const clientId = (_g = (_f = this.config).getClientId) == null ? void 0 : _g.call(_f);
1123
+ const userState = (_i = (_h = this.config).getUserState) == null ? void 0 : _i.call(_h);
1062
1124
  try {
1063
1125
  this.markRunning(threadId, true);
1064
1126
  const response = await this.config.aomiClientRef.current.sendMessage(
1065
1127
  backendThreadId,
1066
1128
  text,
1067
- { app, publicKey, apiKey, userState }
1129
+ { app, publicKey, apiKey, userState, clientId }
1068
1130
  );
1069
1131
  if (response == null ? void 0 : response.messages) {
1070
1132
  this.inbound(threadId, response.messages);
1071
1133
  }
1072
- if (((_h = response == null ? void 0 : response.system_events) == null ? void 0 : _h.length) && this.config.onSyncEvents) {
1134
+ if (((_j = response == null ? void 0 : response.system_events) == null ? void 0 : _j.length) && this.config.onSyncEvents) {
1073
1135
  this.config.onSyncEvents(backendThreadId, response.system_events);
1074
1136
  }
1075
1137
  if (response == null ? void 0 : response.is_processing) {
@@ -1128,7 +1190,7 @@ var PollingController = class {
1128
1190
  const backendThreadId = resolveThreadId(backendState, threadId);
1129
1191
  setThreadRunning(backendState, threadId, true);
1130
1192
  const tick = async () => {
1131
- var _a2, _b2;
1193
+ var _a2, _b2, _c, _d;
1132
1194
  if (!this.intervals.has(threadId)) return;
1133
1195
  try {
1134
1196
  console.log(
@@ -1136,9 +1198,11 @@ var PollingController = class {
1136
1198
  threadId
1137
1199
  );
1138
1200
  const userState = (_b2 = (_a2 = this.config).getUserState) == null ? void 0 : _b2.call(_a2);
1201
+ const clientId = (_d = (_c = this.config).getClientId) == null ? void 0 : _d.call(_c);
1139
1202
  const state = await this.config.aomiClientRef.current.fetchState(
1140
1203
  backendThreadId,
1141
- userState
1204
+ userState,
1205
+ clientId
1142
1206
  );
1143
1207
  if (!this.intervals.has(threadId)) return;
1144
1208
  this.handleState(threadId, state);
@@ -1205,6 +1269,7 @@ function useRuntimeOrchestrator(aomiClient, options) {
1205
1269
  },
1206
1270
  onSyncEvents: options.onSyncEvents,
1207
1271
  getUserState: options.getUserState,
1272
+ getClientId: options.getClientId,
1208
1273
  onStart: (threadId) => {
1209
1274
  if (threadContextRef.current.currentThreadId === threadId) {
1210
1275
  setIsRunning(true);
@@ -1227,29 +1292,32 @@ function useRuntimeOrchestrator(aomiClient, options) {
1227
1292
  getPublicKey: options.getPublicKey,
1228
1293
  getApp: options.getApp,
1229
1294
  getApiKey: options.getApiKey,
1295
+ getClientId: options.getClientId,
1230
1296
  getUserState: options.getUserState,
1231
1297
  onSyncEvents: options.onSyncEvents
1232
1298
  });
1233
1299
  }
1234
1300
  const ensureInitialState = (0, import_react6.useCallback)(async (threadId) => {
1235
- var _a, _b, _c, _d;
1301
+ var _a, _b, _c, _d, _e;
1236
1302
  if (pendingFetches.current.has(threadId)) return;
1237
1303
  const backendThreadId = resolveThreadId(backendStateRef.current, threadId);
1238
1304
  pendingFetches.current.add(threadId);
1239
1305
  try {
1240
1306
  const userState = (_a = options.getUserState) == null ? void 0 : _a.call(options);
1307
+ const clientId = (_b = options.getClientId) == null ? void 0 : _b.call(options);
1241
1308
  const state = await aomiClientRef.current.fetchState(
1242
1309
  backendThreadId,
1243
- userState
1310
+ userState,
1311
+ clientId
1244
1312
  );
1245
- (_b = messageControllerRef.current) == null ? void 0 : _b.inbound(threadId, state.messages);
1246
- if (((_c = state.system_events) == null ? void 0 : _c.length) && options.onSyncEvents) {
1313
+ (_c = messageControllerRef.current) == null ? void 0 : _c.inbound(threadId, state.messages);
1314
+ if (((_d = state.system_events) == null ? void 0 : _d.length) && options.onSyncEvents) {
1247
1315
  options.onSyncEvents(backendThreadId, state.system_events);
1248
1316
  }
1249
1317
  if (threadContextRef.current.currentThreadId === threadId) {
1250
1318
  if (state.is_processing) {
1251
1319
  setIsRunning(true);
1252
- (_d = pollingRef.current) == null ? void 0 : _d.start(threadId);
1320
+ (_e = pollingRef.current) == null ? void 0 : _e.start(threadId);
1253
1321
  } else {
1254
1322
  setIsRunning(false);
1255
1323
  }
@@ -1582,7 +1650,7 @@ function AomiRuntimeCore({
1582
1650
  const notificationContext = useNotification();
1583
1651
  const { dispatchInboundSystem: dispatchSystemEvents } = eventContext;
1584
1652
  const { user, onUserStateChange, getUserState } = useUser();
1585
- const { getControlState, getCurrentThreadApp } = useControl();
1653
+ const { getControlState, getCurrentThreadApp, clearSecrets } = useControl();
1586
1654
  const {
1587
1655
  backendStateRef,
1588
1656
  polling,
@@ -1596,24 +1664,46 @@ function AomiRuntimeCore({
1596
1664
  getPublicKey: () => getUserState().address,
1597
1665
  getUserState,
1598
1666
  getApp: getCurrentThreadApp,
1599
- getApiKey: () => getControlState().apiKey
1667
+ getApiKey: () => getControlState().apiKey,
1668
+ getClientId: () => {
1669
+ var _a;
1670
+ return (_a = getControlState().clientId) != null ? _a : void 0;
1671
+ }
1600
1672
  });
1673
+ const walletSnapshot = (0, import_react9.useCallback)(
1674
+ (nextUser) => ({
1675
+ address: nextUser.address,
1676
+ chainId: nextUser.chainId,
1677
+ isConnected: nextUser.isConnected,
1678
+ ensName: nextUser.ensName
1679
+ }),
1680
+ [getUserState]
1681
+ );
1682
+ const lastWalletStateRef = (0, import_react9.useRef)(walletSnapshot(getUserState()));
1601
1683
  (0, import_react9.useEffect)(() => {
1684
+ lastWalletStateRef.current = walletSnapshot(getUserState());
1602
1685
  const unsubscribe = onUserStateChange(async (newUser) => {
1686
+ const nextWalletState = walletSnapshot(newUser);
1687
+ const prevWalletState = lastWalletStateRef.current;
1688
+ if (prevWalletState.address === nextWalletState.address && prevWalletState.chainId === nextWalletState.chainId && prevWalletState.isConnected === nextWalletState.isConnected && prevWalletState.ensName === nextWalletState.ensName) {
1689
+ return;
1690
+ }
1691
+ lastWalletStateRef.current = nextWalletState;
1603
1692
  const sessionId = threadContext.currentThreadId;
1604
1693
  const message = JSON.stringify({
1605
1694
  type: "wallet:state_changed",
1606
- payload: {
1607
- address: newUser.address,
1608
- chainId: newUser.chainId,
1609
- isConnected: newUser.isConnected,
1610
- ensName: newUser.ensName
1611
- }
1695
+ payload: nextWalletState
1612
1696
  });
1613
1697
  await aomiClientRef.current.sendSystemMessage(sessionId, message);
1614
1698
  });
1615
1699
  return unsubscribe;
1616
- }, [onUserStateChange, aomiClientRef, threadContext.currentThreadId]);
1700
+ }, [
1701
+ onUserStateChange,
1702
+ aomiClientRef,
1703
+ threadContext.currentThreadId,
1704
+ getUserState,
1705
+ walletSnapshot
1706
+ ]);
1617
1707
  const threadContextRef = (0, import_react9.useRef)(threadContext);
1618
1708
  threadContextRef.current = threadContext;
1619
1709
  const currentThreadIdRef = (0, import_react9.useRef)(threadContext.currentThreadId);
@@ -1805,8 +1895,9 @@ function AomiRuntimeCore({
1805
1895
  (0, import_react9.useEffect)(() => {
1806
1896
  return () => {
1807
1897
  polling.stopAll();
1898
+ void clearSecrets();
1808
1899
  };
1809
- }, [polling]);
1900
+ }, [polling, clearSecrets]);
1810
1901
  const userContext = useUser();
1811
1902
  const sendMessage = (0, import_react9.useCallback)(
1812
1903
  async (text) => {
@@ -1869,6 +1960,8 @@ function AomiRuntimeCore({
1869
1960
  user: userContext.user,
1870
1961
  getUserState: userContext.getUserState,
1871
1962
  setUser: userContext.setUser,
1963
+ addExtValue: userContext.addExtValue,
1964
+ removeExtValue: userContext.removeExtValue,
1872
1965
  onUserStateChange: userContext.onUserStateChange,
1873
1966
  // Thread API
1874
1967
  currentThreadId: threadContext.currentThreadId,