@aomi-labs/react 0.2.4 → 0.3.1

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/dist/index.cjs CHANGED
@@ -37,8 +37,8 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
37
37
  // packages/react/src/index.ts
38
38
  var index_exports = {};
39
39
  __export(index_exports, {
40
+ AomiClient: () => import_client3.AomiClient,
40
41
  AomiRuntimeProvider: () => AomiRuntimeProvider,
41
- BackendApi: () => BackendApi,
42
42
  ControlContextProvider: () => ControlContextProvider,
43
43
  EventContextProvider: () => EventContextProvider,
44
44
  NotificationContextProvider: () => NotificationContextProvider,
@@ -62,439 +62,11 @@ __export(index_exports, {
62
62
  useWalletHandler: () => useWalletHandler
63
63
  });
64
64
  module.exports = __toCommonJS(index_exports);
65
-
66
- // packages/react/src/backend/sse.ts
67
- function extractSseData(rawEvent) {
68
- const dataLines = rawEvent.split("\n").filter((line) => line.startsWith("data:")).map((line) => line.slice(5).trimStart());
69
- if (!dataLines.length) return null;
70
- return dataLines.join("\n");
71
- }
72
- async function readSseStream(stream, signal, onMessage) {
73
- const reader = stream.getReader();
74
- const decoder = new TextDecoder();
75
- let buffer = "";
76
- try {
77
- while (!signal.aborted) {
78
- const { value, done } = await reader.read();
79
- if (done) break;
80
- buffer += decoder.decode(value, { stream: true });
81
- buffer = buffer.replace(/\r/g, "");
82
- let separatorIndex = buffer.indexOf("\n\n");
83
- while (separatorIndex >= 0) {
84
- const rawEvent = buffer.slice(0, separatorIndex);
85
- buffer = buffer.slice(separatorIndex + 2);
86
- const data = extractSseData(rawEvent);
87
- if (data) {
88
- onMessage(data);
89
- }
90
- separatorIndex = buffer.indexOf("\n\n");
91
- }
92
- }
93
- } finally {
94
- reader.releaseLock();
95
- }
96
- }
97
- function createSseSubscriber({
98
- backendUrl,
99
- getHeaders,
100
- shouldLog = process.env.NODE_ENV !== "production"
101
- }) {
102
- const subscriptions = /* @__PURE__ */ new Map();
103
- const subscribe2 = (sessionId, onUpdate, onError) => {
104
- const existing = subscriptions.get(sessionId);
105
- const listener = { onUpdate, onError };
106
- if (existing) {
107
- existing.listeners.add(listener);
108
- if (shouldLog) {
109
- console.debug("[aomi][sse] listener added", {
110
- sessionId,
111
- listeners: existing.listeners.size
112
- });
113
- }
114
- return () => {
115
- existing.listeners.delete(listener);
116
- if (shouldLog) {
117
- console.debug("[aomi][sse] listener removed", {
118
- sessionId,
119
- listeners: existing.listeners.size
120
- });
121
- }
122
- if (existing.listeners.size === 0) {
123
- existing.stop("unsubscribe");
124
- if (subscriptions.get(sessionId) === existing) {
125
- subscriptions.delete(sessionId);
126
- }
127
- }
128
- };
129
- }
130
- const subscription = {
131
- abortController: null,
132
- retries: 0,
133
- retryTimer: null,
134
- stopped: false,
135
- listeners: /* @__PURE__ */ new Set([listener]),
136
- stop: (reason) => {
137
- var _a;
138
- subscription.stopped = true;
139
- if (subscription.retryTimer) {
140
- clearTimeout(subscription.retryTimer);
141
- subscription.retryTimer = null;
142
- }
143
- (_a = subscription.abortController) == null ? void 0 : _a.abort();
144
- subscription.abortController = null;
145
- if (shouldLog) {
146
- console.debug("[aomi][sse] stop", {
147
- sessionId,
148
- reason,
149
- retries: subscription.retries
150
- });
151
- }
152
- }
153
- };
154
- const scheduleRetry = () => {
155
- if (subscription.stopped) return;
156
- subscription.retries += 1;
157
- const delayMs = Math.min(500 * 2 ** (subscription.retries - 1), 1e4);
158
- if (shouldLog) {
159
- console.debug("[aomi][sse] retry scheduled", {
160
- sessionId,
161
- delayMs,
162
- retries: subscription.retries
163
- });
164
- }
165
- subscription.retryTimer = setTimeout(() => {
166
- void open();
167
- }, delayMs);
168
- };
169
- const open = async () => {
170
- var _a;
171
- if (subscription.stopped) return;
172
- if (subscription.retryTimer) {
173
- clearTimeout(subscription.retryTimer);
174
- subscription.retryTimer = null;
175
- }
176
- const controller = new AbortController();
177
- subscription.abortController = controller;
178
- const openedAt = Date.now();
179
- try {
180
- const response = await fetch(`${backendUrl}/api/updates`, {
181
- headers: getHeaders(sessionId),
182
- signal: controller.signal
183
- });
184
- if (!response.ok) {
185
- throw new Error(
186
- `SSE HTTP ${response.status}: ${response.statusText}`
187
- );
188
- }
189
- if (!response.body) {
190
- throw new Error("SSE response missing body");
191
- }
192
- subscription.retries = 0;
193
- await readSseStream(response.body, controller.signal, (data) => {
194
- var _a2, _b;
195
- let parsed;
196
- try {
197
- parsed = JSON.parse(data);
198
- } catch (error) {
199
- for (const item of subscription.listeners) {
200
- (_a2 = item.onError) == null ? void 0 : _a2.call(item, error);
201
- }
202
- return;
203
- }
204
- for (const item of subscription.listeners) {
205
- try {
206
- item.onUpdate(parsed);
207
- } catch (error) {
208
- (_b = item.onError) == null ? void 0 : _b.call(item, error);
209
- }
210
- }
211
- });
212
- if (shouldLog) {
213
- console.debug("[aomi][sse] stream ended", {
214
- sessionId,
215
- aborted: controller.signal.aborted,
216
- stopped: subscription.stopped,
217
- durationMs: Date.now() - openedAt
218
- });
219
- }
220
- } catch (error) {
221
- if (!controller.signal.aborted && !subscription.stopped) {
222
- for (const item of subscription.listeners) {
223
- (_a = item.onError) == null ? void 0 : _a.call(item, error);
224
- }
225
- }
226
- }
227
- if (!subscription.stopped) {
228
- scheduleRetry();
229
- }
230
- };
231
- subscriptions.set(sessionId, subscription);
232
- void open();
233
- return () => {
234
- subscription.listeners.delete(listener);
235
- if (shouldLog) {
236
- console.debug("[aomi][sse] listener removed", {
237
- sessionId,
238
- listeners: subscription.listeners.size
239
- });
240
- }
241
- if (subscription.listeners.size === 0) {
242
- subscription.stop("unsubscribe");
243
- if (subscriptions.get(sessionId) === subscription) {
244
- subscriptions.delete(sessionId);
245
- }
246
- }
247
- };
248
- };
249
- return { subscribe: subscribe2 };
250
- }
251
-
252
- // packages/react/src/backend/client.ts
253
- var SESSION_ID_HEADER = "X-Session-Id";
254
- var API_KEY_HEADER = "X-API-Key";
255
- function toQueryString(payload) {
256
- const params = new URLSearchParams();
257
- for (const [key, value] of Object.entries(payload)) {
258
- if (value === void 0 || value === null) continue;
259
- params.set(key, String(value));
260
- }
261
- const qs = params.toString();
262
- return qs ? `?${qs}` : "";
263
- }
264
- function withSessionHeader(sessionId, init) {
265
- const headers = new Headers(init);
266
- headers.set(SESSION_ID_HEADER, sessionId);
267
- return headers;
268
- }
269
- async function postState(backendUrl, path, payload, sessionId, apiKey) {
270
- const query = toQueryString(payload);
271
- const url = `${backendUrl}${path}${query}`;
272
- const headers = new Headers(withSessionHeader(sessionId));
273
- if (apiKey) {
274
- headers.set(API_KEY_HEADER, apiKey);
275
- }
276
- const response = await fetch(url, {
277
- method: "POST",
278
- headers
279
- });
280
- if (!response.ok) {
281
- throw new Error(`HTTP ${response.status}: ${response.statusText}`);
282
- }
283
- return await response.json();
284
- }
285
- var BackendApi = class {
286
- constructor(backendUrl) {
287
- this.backendUrl = backendUrl;
288
- this.sseSubscriber = createSseSubscriber({
289
- backendUrl,
290
- getHeaders: (sessionId) => withSessionHeader(sessionId, { Accept: "text/event-stream" })
291
- });
292
- }
293
- async fetchState(sessionId, userState) {
294
- const url = new URL("/api/state", this.backendUrl);
295
- if (userState) {
296
- url.searchParams.set("user_state", JSON.stringify(userState));
297
- }
298
- const response = await fetch(url.toString(), {
299
- headers: withSessionHeader(sessionId)
300
- });
301
- if (!response.ok) {
302
- throw new Error(`HTTP ${response.status}: ${response.statusText}`);
303
- }
304
- return await response.json();
305
- }
306
- async postChatMessage(sessionId, message, namespace, publicKey, apiKey, userState) {
307
- const payload = { message, namespace };
308
- if (publicKey) {
309
- payload.public_key = publicKey;
310
- }
311
- if (userState) {
312
- payload.user_state = JSON.stringify(userState);
313
- }
314
- return postState(
315
- this.backendUrl,
316
- "/api/chat",
317
- payload,
318
- sessionId,
319
- apiKey
320
- );
321
- }
322
- async postSystemMessage(sessionId, message) {
323
- return postState(
324
- this.backendUrl,
325
- "/api/system",
326
- {
327
- message
328
- },
329
- sessionId
330
- );
331
- }
332
- async postInterrupt(sessionId) {
333
- return postState(
334
- this.backendUrl,
335
- "/api/interrupt",
336
- {},
337
- sessionId
338
- );
339
- }
340
- /**
341
- * Subscribe to SSE updates for a session.
342
- * Uses fetch streaming and reconnects on disconnects.
343
- * Returns an unsubscribe function.
344
- */
345
- subscribeSSE(sessionId, onUpdate, onError) {
346
- return this.sseSubscriber.subscribe(sessionId, onUpdate, onError);
347
- }
348
- async fetchThreads(publicKey) {
349
- const url = `${this.backendUrl}/api/sessions?public_key=${encodeURIComponent(publicKey)}`;
350
- const response = await fetch(url);
351
- if (!response.ok) {
352
- throw new Error(`Failed to fetch threads: HTTP ${response.status}`);
353
- }
354
- return await response.json();
355
- }
356
- async fetchThread(sessionId) {
357
- const url = `${this.backendUrl}/api/sessions/${encodeURIComponent(sessionId)}`;
358
- const response = await fetch(url, {
359
- headers: withSessionHeader(sessionId)
360
- });
361
- if (!response.ok) {
362
- throw new Error(`HTTP ${response.status}: ${response.statusText}`);
363
- }
364
- return await response.json();
365
- }
366
- async createThread(threadId, publicKey) {
367
- const body = {};
368
- if (publicKey) body.public_key = publicKey;
369
- const url = `${this.backendUrl}/api/sessions`;
370
- const response = await fetch(url, {
371
- method: "POST",
372
- headers: withSessionHeader(threadId, {
373
- "Content-Type": "application/json"
374
- }),
375
- body: JSON.stringify(body)
376
- });
377
- if (!response.ok) {
378
- throw new Error(`Failed to create thread: HTTP ${response.status}`);
379
- }
380
- return await response.json();
381
- }
382
- async archiveThread(sessionId) {
383
- const url = `${this.backendUrl}/api/sessions/${encodeURIComponent(sessionId)}/archive`;
384
- const response = await fetch(url, {
385
- method: "POST",
386
- headers: withSessionHeader(sessionId)
387
- });
388
- if (!response.ok) {
389
- throw new Error(`Failed to archive thread: HTTP ${response.status}`);
390
- }
391
- }
392
- async unarchiveThread(sessionId) {
393
- const url = `${this.backendUrl}/api/sessions/${encodeURIComponent(sessionId)}/unarchive`;
394
- const response = await fetch(url, {
395
- method: "POST",
396
- headers: withSessionHeader(sessionId)
397
- });
398
- if (!response.ok) {
399
- throw new Error(`Failed to unarchive thread: HTTP ${response.status}`);
400
- }
401
- }
402
- async deleteThread(sessionId) {
403
- const url = `${this.backendUrl}/api/sessions/${encodeURIComponent(sessionId)}`;
404
- const response = await fetch(url, {
405
- method: "DELETE",
406
- headers: withSessionHeader(sessionId)
407
- });
408
- if (!response.ok) {
409
- throw new Error(`Failed to delete thread: HTTP ${response.status}`);
410
- }
411
- }
412
- async renameThread(sessionId, newTitle) {
413
- const url = `${this.backendUrl}/api/sessions/${encodeURIComponent(sessionId)}`;
414
- const response = await fetch(url, {
415
- method: "PATCH",
416
- headers: withSessionHeader(sessionId, {
417
- "Content-Type": "application/json"
418
- }),
419
- body: JSON.stringify({ title: newTitle })
420
- });
421
- if (!response.ok) {
422
- throw new Error(`Failed to rename thread: HTTP ${response.status}`);
423
- }
424
- }
425
- async getSystemEvents(sessionId, count) {
426
- const url = new URL("/api/events", this.backendUrl);
427
- if (count !== void 0) {
428
- url.searchParams.set("count", String(count));
429
- }
430
- const response = await fetch(url.toString(), {
431
- headers: withSessionHeader(sessionId)
432
- });
433
- if (!response.ok) {
434
- if (response.status === 404) return [];
435
- throw new Error(`Failed to get system events: HTTP ${response.status}`);
436
- }
437
- return await response.json();
438
- }
439
- // ===========================================================================
440
- // Control API
441
- // ===========================================================================
442
- /**
443
- * Get allowed namespaces for the current request context.
444
- */
445
- async getNamespaces(sessionId, publicKey, apiKey) {
446
- const url = new URL("/api/control/namespaces", this.backendUrl);
447
- if (publicKey) {
448
- url.searchParams.set("public_key", publicKey);
449
- }
450
- console.log("[BackendApi.getNamespaces]", {
451
- backendUrl: this.backendUrl,
452
- fullUrl: url.toString(),
453
- sessionId,
454
- publicKey
455
- });
456
- const headers = new Headers(withSessionHeader(sessionId));
457
- if (apiKey) {
458
- headers.set(API_KEY_HEADER, apiKey);
459
- }
460
- const response = await fetch(url.toString(), { headers });
461
- if (!response.ok) {
462
- throw new Error(`Failed to get namespaces: HTTP ${response.status}`);
463
- }
464
- return await response.json();
465
- }
466
- /**
467
- * Get available models.
468
- */
469
- async getModels(sessionId) {
470
- const url = new URL("/api/control/models", this.backendUrl);
471
- console.log("[BackendApi.getModels]", {
472
- backendUrl: this.backendUrl,
473
- fullUrl: url.toString(),
474
- sessionId
475
- });
476
- const response = await fetch(url.toString(), {
477
- headers: withSessionHeader(sessionId)
478
- });
479
- if (!response.ok) {
480
- throw new Error(`Failed to get models: HTTP ${response.status}`);
481
- }
482
- return await response.json();
483
- }
484
- /**
485
- * Set the model selection for a session.
486
- */
487
- async setModel(sessionId, rig, namespace, apiKey) {
488
- const payload = { rig };
489
- if (namespace) {
490
- payload.namespace = namespace;
491
- }
492
- return postState(this.backendUrl, "/api/control/model", payload, sessionId, apiKey);
493
- }
494
- };
65
+ var import_client3 = require("@aomi-labs/client");
495
66
 
496
67
  // packages/react/src/runtime/aomi-runtime.tsx
497
- var import_react10 = require("react");
68
+ var import_react11 = require("react");
69
+ var import_client2 = require("@aomi-labs/client");
498
70
 
499
71
  // packages/react/src/contexts/control-context.tsx
500
72
  var import_react = require("react");
@@ -527,7 +99,7 @@ var logThreadMetadataChange = (source, threadId, prev, next) => {
527
99
  function initThreadControl() {
528
100
  return {
529
101
  model: null,
530
- namespace: null,
102
+ app: null,
531
103
  controlDirty: false,
532
104
  isProcessing: false
533
105
  };
@@ -611,7 +183,7 @@ var ThreadStore = class {
611
183
  initialThreadId,
612
184
  {
613
185
  title: "New Chat",
614
- status: "pending",
186
+ status: "regular",
615
187
  lastActiveAt: (/* @__PURE__ */ new Date()).toISOString(),
616
188
  control: initThreadControl()
617
189
  }
@@ -683,7 +255,7 @@ function useControl() {
683
255
  }
684
256
  function ControlContextProvider({
685
257
  children,
686
- backendApi,
258
+ aomiClient,
687
259
  sessionId,
688
260
  publicKey,
689
261
  getThreadMetadata,
@@ -693,14 +265,14 @@ function ControlContextProvider({
693
265
  const [state, setStateInternal] = (0, import_react.useState)(() => ({
694
266
  apiKey: null,
695
267
  availableModels: [],
696
- authorizedNamespaces: [],
268
+ authorizedApps: [],
697
269
  defaultModel: null,
698
- defaultNamespace: null
270
+ defaultApp: null
699
271
  }));
700
272
  const stateRef = (0, import_react.useRef)(state);
701
273
  stateRef.current = state;
702
- const backendApiRef = (0, import_react.useRef)(backendApi);
703
- backendApiRef.current = backendApi;
274
+ const aomiClientRef = (0, import_react.useRef)(aomiClient);
275
+ aomiClientRef.current = aomiClient;
704
276
  const sessionIdRef = (0, import_react.useRef)(sessionId);
705
277
  sessionIdRef.current = sessionId;
706
278
  const publicKeyRef = (0, import_react.useRef)(publicKey);
@@ -734,33 +306,32 @@ function ControlContextProvider({
734
306
  }
735
307
  }, [state.apiKey]);
736
308
  (0, import_react.useEffect)(() => {
737
- const fetchNamespaces = async () => {
309
+ const fetchApps = async () => {
738
310
  var _a2, _b2;
739
311
  try {
740
- const namespaces = await backendApiRef.current.getNamespaces(
312
+ const apps = await aomiClientRef.current.getApps(
741
313
  sessionIdRef.current,
742
- publicKeyRef.current,
743
- (_a2 = stateRef.current.apiKey) != null ? _a2 : void 0
314
+ { publicKey: publicKeyRef.current, apiKey: (_a2 = stateRef.current.apiKey) != null ? _a2 : void 0 }
744
315
  );
745
- const defaultNs = namespaces.includes("default") ? "default" : (_b2 = namespaces[0]) != null ? _b2 : null;
316
+ const defaultApp = apps.includes("default") ? "default" : (_b2 = apps[0]) != null ? _b2 : null;
746
317
  setStateInternal((prev) => __spreadProps(__spreadValues({}, prev), {
747
- authorizedNamespaces: namespaces,
748
- defaultNamespace: defaultNs
318
+ authorizedApps: apps,
319
+ defaultApp
749
320
  }));
750
321
  } catch (error) {
751
- console.error("Failed to fetch namespaces:", error);
322
+ console.error("Failed to fetch apps:", error);
752
323
  setStateInternal((prev) => __spreadProps(__spreadValues({}, prev), {
753
- authorizedNamespaces: ["default"],
754
- defaultNamespace: "default"
324
+ authorizedApps: ["default"],
325
+ defaultApp: "default"
755
326
  }));
756
327
  }
757
328
  };
758
- void fetchNamespaces();
329
+ void fetchApps();
759
330
  }, [state.apiKey]);
760
331
  (0, import_react.useEffect)(() => {
761
332
  const fetchModels = async () => {
762
333
  try {
763
- const models = await backendApiRef.current.getModels(
334
+ const models = await aomiClientRef.current.getModels(
764
335
  sessionIdRef.current
765
336
  );
766
337
  setStateInternal((prev) => {
@@ -785,7 +356,7 @@ function ControlContextProvider({
785
356
  }, []);
786
357
  const getAvailableModels = (0, import_react.useCallback)(async () => {
787
358
  try {
788
- const models = await backendApiRef.current.getModels(
359
+ const models = await aomiClientRef.current.getModels(
789
360
  sessionIdRef.current
790
361
  );
791
362
  setStateInternal((prev) => {
@@ -801,25 +372,24 @@ function ControlContextProvider({
801
372
  return [];
802
373
  }
803
374
  }, []);
804
- const getAuthorizedNamespaces = (0, import_react.useCallback)(async () => {
375
+ const getAuthorizedApps = (0, import_react.useCallback)(async () => {
805
376
  var _a2, _b2;
806
377
  try {
807
- const namespaces = await backendApiRef.current.getNamespaces(
378
+ const apps = await aomiClientRef.current.getApps(
808
379
  sessionIdRef.current,
809
- publicKeyRef.current,
810
- (_a2 = stateRef.current.apiKey) != null ? _a2 : void 0
380
+ { publicKey: publicKeyRef.current, apiKey: (_a2 = stateRef.current.apiKey) != null ? _a2 : void 0 }
811
381
  );
812
- const defaultNs = namespaces.includes("default") ? "default" : (_b2 = namespaces[0]) != null ? _b2 : null;
382
+ const defaultApp = apps.includes("default") ? "default" : (_b2 = apps[0]) != null ? _b2 : null;
813
383
  setStateInternal((prev) => __spreadProps(__spreadValues({}, prev), {
814
- authorizedNamespaces: namespaces,
815
- defaultNamespace: defaultNs
384
+ authorizedApps: apps,
385
+ defaultApp
816
386
  }));
817
- return namespaces;
387
+ return apps;
818
388
  } catch (error) {
819
- console.error("Failed to fetch namespaces:", error);
389
+ console.error("Failed to fetch apps:", error);
820
390
  setStateInternal((prev) => __spreadProps(__spreadValues({}, prev), {
821
- authorizedNamespaces: ["default"],
822
- defaultNamespace: "default"
391
+ authorizedApps: ["default"],
392
+ defaultApp: "default"
823
393
  }));
824
394
  return ["default"];
825
395
  }
@@ -843,32 +413,31 @@ function ControlContextProvider({
843
413
  console.warn("[control-context] Cannot switch model while processing");
844
414
  return;
845
415
  }
846
- const namespace = (_d = (_c = currentControl.namespace) != null ? _c : stateRef.current.defaultNamespace) != null ? _d : "default";
416
+ const app = (_d = (_c = currentControl.app) != null ? _c : stateRef.current.defaultApp) != null ? _d : "default";
847
417
  console.log("[control-context] onModelSelect updating metadata", {
848
418
  threadId,
849
419
  model,
850
- namespace,
420
+ app,
851
421
  currentControl
852
422
  });
853
423
  updateThreadMetadataRef.current(threadId, {
854
424
  control: __spreadProps(__spreadValues({}, currentControl), {
855
425
  model,
856
- namespace,
426
+ app,
857
427
  controlDirty: true
858
428
  })
859
429
  });
860
430
  console.log("[control-context] onModelSelect calling backend setModel", {
861
431
  threadId,
862
432
  model,
863
- namespace,
864
- backendUrl: backendApiRef.current
433
+ app,
434
+ backendUrl: aomiClientRef.current
865
435
  });
866
436
  try {
867
- const result = await backendApiRef.current.setModel(
437
+ const result = await aomiClientRef.current.setModel(
868
438
  threadId,
869
439
  model,
870
- namespace,
871
- (_e = stateRef.current.apiKey) != null ? _e : void 0
440
+ { app, apiKey: (_e = stateRef.current.apiKey) != null ? _e : void 0 }
872
441
  );
873
442
  console.log("[control-context] onModelSelect backend result", result);
874
443
  } catch (err) {
@@ -876,34 +445,34 @@ function ControlContextProvider({
876
445
  throw err;
877
446
  }
878
447
  }, []);
879
- const onNamespaceSelect = (0, import_react.useCallback)((namespace) => {
448
+ const onAppSelect = (0, import_react.useCallback)((app) => {
880
449
  var _a2, _b2;
881
450
  const threadId = sessionIdRef.current;
882
451
  const currentControl = (_b2 = (_a2 = getThreadMetadataRef.current(threadId)) == null ? void 0 : _a2.control) != null ? _b2 : initThreadControl();
883
452
  const isProcessing2 = currentControl.isProcessing;
884
- console.log("[control-context] onNamespaceSelect called", {
885
- namespace,
453
+ console.log("[control-context] onAppSelect called", {
454
+ app,
886
455
  isProcessing: isProcessing2,
887
456
  threadId
888
457
  });
889
458
  if (isProcessing2) {
890
459
  console.warn(
891
- "[control-context] Cannot switch namespace while processing"
460
+ "[control-context] Cannot switch app while processing"
892
461
  );
893
462
  return;
894
463
  }
895
- console.log("[control-context] onNamespaceSelect updating metadata", {
464
+ console.log("[control-context] onAppSelect updating metadata", {
896
465
  threadId,
897
- namespace,
466
+ app,
898
467
  currentControl
899
468
  });
900
469
  updateThreadMetadataRef.current(threadId, {
901
470
  control: __spreadProps(__spreadValues({}, currentControl), {
902
- namespace,
471
+ app,
903
472
  controlDirty: true
904
473
  })
905
474
  });
906
- console.log("[control-context] onNamespaceSelect metadata updated");
475
+ console.log("[control-context] onAppSelect metadata updated");
907
476
  }, []);
908
477
  const markControlSynced = (0, import_react.useCallback)(() => {
909
478
  var _a2, _b2;
@@ -933,11 +502,11 @@ function ControlContextProvider({
933
502
  if ("apiKey" in updates) {
934
503
  setApiKey((_a2 = updates.apiKey) != null ? _a2 : null);
935
504
  }
936
- if ("namespace" in updates && updates.namespace !== void 0 && updates.namespace !== null) {
937
- onNamespaceSelect(updates.namespace);
505
+ if ("app" in updates && updates.app !== void 0 && updates.app !== null) {
506
+ onAppSelect(updates.app);
938
507
  }
939
508
  },
940
- [setApiKey, onNamespaceSelect]
509
+ [setApiKey, onAppSelect]
941
510
  );
942
511
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
943
512
  ControlContext.Provider,
@@ -946,10 +515,10 @@ function ControlContextProvider({
946
515
  state,
947
516
  setApiKey,
948
517
  getAvailableModels,
949
- getAuthorizedNamespaces,
518
+ getAuthorizedApps,
950
519
  getCurrentThreadControl,
951
520
  onModelSelect,
952
- onNamespaceSelect,
521
+ onAppSelect,
953
522
  isProcessing,
954
523
  markControlSynced,
955
524
  getControlState,
@@ -963,20 +532,7 @@ function ControlContextProvider({
963
532
 
964
533
  // packages/react/src/contexts/event-context.tsx
965
534
  var import_react2 = require("react");
966
-
967
- // packages/react/src/backend/types.ts
968
- function isInlineCall(event) {
969
- return "InlineCall" in event;
970
- }
971
- function isSystemNotice(event) {
972
- return "SystemNotice" in event;
973
- }
974
- function isSystemError(event) {
975
- return "SystemError" in event;
976
- }
977
- function isAsyncCallback(event) {
978
- return "AsyncCallback" in event;
979
- }
535
+ var import_client = require("@aomi-labs/client");
980
536
 
981
537
  // packages/react/src/state/event-buffer.ts
982
538
  function createEventBuffer() {
@@ -1036,7 +592,7 @@ function useEventContext() {
1036
592
  }
1037
593
  function EventContextProvider({
1038
594
  children,
1039
- backendApi,
595
+ aomiClient,
1040
596
  sessionId
1041
597
  }) {
1042
598
  const bufferRef = (0, import_react2.useRef)(null);
@@ -1048,7 +604,7 @@ function EventContextProvider({
1048
604
  (0, import_react2.useEffect)(() => {
1049
605
  setSSEStatus(buffer, "connecting");
1050
606
  setSseStatus("connecting");
1051
- const unsubscribe = backendApi.subscribeSSE(
607
+ const unsubscribe = aomiClient.subscribeSSE(
1052
608
  sessionId,
1053
609
  (event) => {
1054
610
  enqueueInbound(buffer, {
@@ -1078,7 +634,7 @@ function EventContextProvider({
1078
634
  setSSEStatus(buffer, "disconnected");
1079
635
  setSseStatus("disconnected");
1080
636
  };
1081
- }, [backendApi, sessionId, buffer]);
637
+ }, [aomiClient, sessionId, buffer]);
1082
638
  const subscribeCallback = (0, import_react2.useCallback)(
1083
639
  (type, callback) => {
1084
640
  return subscribe(buffer, type, callback);
@@ -1092,12 +648,12 @@ function EventContextProvider({
1092
648
  type: event.type,
1093
649
  payload: event.payload
1094
650
  });
1095
- await backendApi.postSystemMessage(event.sessionId, message);
651
+ await aomiClient.sendSystemMessage(event.sessionId, message);
1096
652
  } catch (error) {
1097
653
  console.error("Failed to send outbound event:", error);
1098
654
  }
1099
655
  },
1100
- [backendApi]
656
+ [aomiClient]
1101
657
  );
1102
658
  const dispatchSystemEvents = (0, import_react2.useCallback)(
1103
659
  (sessionId2, events) => {
@@ -1105,16 +661,16 @@ function EventContextProvider({
1105
661
  for (const event of events) {
1106
662
  let eventType;
1107
663
  let payload;
1108
- if (isInlineCall(event)) {
664
+ if ((0, import_client.isInlineCall)(event)) {
1109
665
  eventType = event.InlineCall.type;
1110
666
  payload = (_a = event.InlineCall.payload) != null ? _a : event.InlineCall;
1111
- } else if (isSystemNotice(event)) {
667
+ } else if ((0, import_client.isSystemNotice)(event)) {
1112
668
  eventType = "system_notice";
1113
669
  payload = { message: event.SystemNotice };
1114
- } else if (isSystemError(event)) {
670
+ } else if ((0, import_client.isSystemError)(event)) {
1115
671
  eventType = "system_error";
1116
672
  payload = { message: event.SystemError };
1117
- } else if (isAsyncCallback(event)) {
673
+ } else if ((0, import_client.isAsyncCallback)(event)) {
1118
674
  eventType = "async_callback";
1119
675
  payload = event.AsyncCallback;
1120
676
  } else {
@@ -1298,8 +854,8 @@ function UserContextProvider({ children }) {
1298
854
  }
1299
855
 
1300
856
  // packages/react/src/runtime/core.tsx
1301
- var import_react8 = require("react");
1302
- var import_react9 = require("@assistant-ui/react");
857
+ var import_react9 = require("react");
858
+ var import_react10 = require("@assistant-ui/react");
1303
859
 
1304
860
  // packages/react/src/runtime/orchestrator.ts
1305
861
  var import_react6 = require("react");
@@ -1409,28 +965,12 @@ var getChainInfo = (chainId) => chainId === void 0 ? void 0 : SUPPORTED_CHAINS.f
1409
965
  // packages/react/src/state/backend-state.ts
1410
966
  function createBackendState() {
1411
967
  return {
1412
- skipInitialFetch: /* @__PURE__ */ new Set(),
1413
- pendingChat: /* @__PURE__ */ new Map(),
1414
- runningThreads: /* @__PURE__ */ new Set(),
1415
- creatingThreadId: null,
1416
- createThreadPromise: null
968
+ runningThreads: /* @__PURE__ */ new Set()
1417
969
  };
1418
970
  }
1419
- function resolveThreadId(state, threadId) {
971
+ function resolveThreadId(_state, threadId) {
1420
972
  return threadId;
1421
973
  }
1422
- function isThreadReady(state, threadId) {
1423
- return state.creatingThreadId !== threadId;
1424
- }
1425
- function markSkipInitialFetch(state, threadId) {
1426
- state.skipInitialFetch.add(threadId);
1427
- }
1428
- function shouldSkipInitialFetch(state, threadId) {
1429
- return state.skipInitialFetch.has(threadId);
1430
- }
1431
- function clearSkipInitialFetch(state, threadId) {
1432
- state.skipInitialFetch.delete(threadId);
1433
- }
1434
974
  function setThreadRunning(state, threadId, running) {
1435
975
  if (running) {
1436
976
  state.runningThreads.add(threadId);
@@ -1441,21 +981,6 @@ function setThreadRunning(state, threadId, running) {
1441
981
  function isThreadRunning(state, threadId) {
1442
982
  return state.runningThreads.has(threadId);
1443
983
  }
1444
- function enqueuePendingChat(state, threadId, text) {
1445
- var _a;
1446
- const existing = (_a = state.pendingChat.get(threadId)) != null ? _a : [];
1447
- state.pendingChat.set(threadId, [...existing, text]);
1448
- }
1449
- function dequeuePendingChat(state, threadId) {
1450
- var _a;
1451
- const pending = (_a = state.pendingChat.get(threadId)) != null ? _a : [];
1452
- state.pendingChat.delete(threadId);
1453
- return pending;
1454
- }
1455
- function hasPendingChat(state, threadId) {
1456
- var _a, _b;
1457
- return ((_b = (_a = state.pendingChat.get(threadId)) == null ? void 0 : _a.length) != null ? _b : 0) > 0;
1458
- }
1459
984
 
1460
985
  // packages/react/src/runtime/message-controller.ts
1461
986
  var MessageController = class {
@@ -1463,11 +988,7 @@ var MessageController = class {
1463
988
  this.config = config;
1464
989
  }
1465
990
  inbound(threadId, msgs) {
1466
- const backendState = this.config.backendStateRef.current;
1467
991
  if (!msgs) return;
1468
- if (hasPendingChat(backendState, threadId)) {
1469
- return;
1470
- }
1471
992
  const threadMessages = [];
1472
993
  for (const msg of msgs) {
1473
994
  const threadMessage = toInboundMessage(msg);
@@ -1497,25 +1018,17 @@ var MessageController = class {
1497
1018
  threadState.updateThreadMetadata(threadId, {
1498
1019
  lastActiveAt: (/* @__PURE__ */ new Date()).toISOString()
1499
1020
  });
1500
- if (!isThreadReady(backendState, threadId)) {
1501
- this.markRunning(threadId, true);
1502
- enqueuePendingChat(backendState, threadId, text);
1503
- return;
1504
- }
1505
1021
  const backendThreadId = resolveThreadId(backendState, threadId);
1506
- const namespace = this.config.getNamespace();
1022
+ const app = this.config.getApp();
1507
1023
  const publicKey = (_b = (_a = this.config).getPublicKey) == null ? void 0 : _b.call(_a);
1508
1024
  const apiKey = (_e = (_d = (_c = this.config).getApiKey) == null ? void 0 : _d.call(_c)) != null ? _e : void 0;
1509
1025
  const userState = (_g = (_f = this.config).getUserState) == null ? void 0 : _g.call(_f);
1510
1026
  try {
1511
1027
  this.markRunning(threadId, true);
1512
- const response = await this.config.backendApiRef.current.postChatMessage(
1028
+ const response = await this.config.aomiClientRef.current.sendMessage(
1513
1029
  backendThreadId,
1514
1030
  text,
1515
- namespace,
1516
- publicKey,
1517
- apiKey,
1518
- userState
1031
+ { app, publicKey, apiKey, userState }
1519
1032
  );
1520
1033
  if (response == null ? void 0 : response.messages) {
1521
1034
  this.inbound(threadId, response.messages);
@@ -1533,40 +1046,13 @@ var MessageController = class {
1533
1046
  this.markRunning(threadId, false);
1534
1047
  }
1535
1048
  }
1536
- async flushPendingChat(threadId) {
1537
- var _a, _b, _c, _d, _e, _f, _g;
1538
- const backendState = this.config.backendStateRef.current;
1539
- const pending = dequeuePendingChat(backendState, threadId);
1540
- if (!pending.length) return;
1541
- const backendThreadId = resolveThreadId(backendState, threadId);
1542
- const namespace = this.config.getNamespace();
1543
- const publicKey = (_b = (_a = this.config).getPublicKey) == null ? void 0 : _b.call(_a);
1544
- const apiKey = (_e = (_d = (_c = this.config).getApiKey) == null ? void 0 : _d.call(_c)) != null ? _e : void 0;
1545
- const userState = (_g = (_f = this.config).getUserState) == null ? void 0 : _g.call(_f);
1546
- for (const text of pending) {
1547
- try {
1548
- await this.config.backendApiRef.current.postChatMessage(
1549
- backendThreadId,
1550
- text,
1551
- namespace,
1552
- publicKey,
1553
- apiKey,
1554
- userState
1555
- );
1556
- } catch (error) {
1557
- console.error("Failed to send queued message:", error);
1558
- }
1559
- }
1560
- this.config.polling.start(threadId);
1561
- }
1562
1049
  async cancel(threadId) {
1563
1050
  var _a;
1564
- const backendState = this.config.backendStateRef.current;
1565
- if (!isThreadReady(backendState, threadId)) return;
1566
1051
  this.config.polling.stop(threadId);
1052
+ const backendState = this.config.backendStateRef.current;
1567
1053
  const backendThreadId = resolveThreadId(backendState, threadId);
1568
1054
  try {
1569
- const response = await this.config.backendApiRef.current.postInterrupt(backendThreadId);
1055
+ const response = await this.config.aomiClientRef.current.interrupt(backendThreadId);
1570
1056
  if (response == null ? void 0 : response.messages) {
1571
1057
  this.inbound(threadId, response.messages);
1572
1058
  }
@@ -1602,7 +1088,6 @@ var PollingController = class {
1602
1088
  start(threadId) {
1603
1089
  var _a, _b;
1604
1090
  const backendState = this.config.backendStateRef.current;
1605
- if (!isThreadReady(backendState, threadId)) return;
1606
1091
  if (this.intervals.has(threadId)) return;
1607
1092
  const backendThreadId = resolveThreadId(backendState, threadId);
1608
1093
  setThreadRunning(backendState, threadId, true);
@@ -1615,7 +1100,7 @@ var PollingController = class {
1615
1100
  threadId
1616
1101
  );
1617
1102
  const userState = (_b2 = (_a2 = this.config).getUserState) == null ? void 0 : _b2.call(_a2);
1618
- const state = await this.config.backendApiRef.current.fetchState(
1103
+ const state = await this.config.aomiClientRef.current.fetchState(
1619
1104
  backendThreadId,
1620
1105
  userState
1621
1106
  );
@@ -1663,12 +1148,12 @@ var PollingController = class {
1663
1148
  };
1664
1149
 
1665
1150
  // packages/react/src/runtime/orchestrator.ts
1666
- function useRuntimeOrchestrator(backendApi, options) {
1151
+ function useRuntimeOrchestrator(aomiClient, options) {
1667
1152
  const threadContext = useThreadContext();
1668
1153
  const threadContextRef = (0, import_react6.useRef)(threadContext);
1669
1154
  threadContextRef.current = threadContext;
1670
- const backendApiRef = (0, import_react6.useRef)(backendApi);
1671
- backendApiRef.current = backendApi;
1155
+ const aomiClientRef = (0, import_react6.useRef)(aomiClient);
1156
+ aomiClientRef.current = aomiClient;
1672
1157
  const backendStateRef = (0, import_react6.useRef)(createBackendState());
1673
1158
  const [isRunning, setIsRunning] = (0, import_react6.useState)(false);
1674
1159
  const messageControllerRef = (0, import_react6.useRef)(null);
@@ -1676,7 +1161,7 @@ function useRuntimeOrchestrator(backendApi, options) {
1676
1161
  const pendingFetches = (0, import_react6.useRef)(/* @__PURE__ */ new Set());
1677
1162
  if (!pollingRef.current) {
1678
1163
  pollingRef.current = new PollingController({
1679
- backendApiRef,
1164
+ aomiClientRef,
1680
1165
  backendStateRef,
1681
1166
  applyMessages: (threadId, msgs) => {
1682
1167
  var _a;
@@ -1698,13 +1183,13 @@ function useRuntimeOrchestrator(backendApi, options) {
1698
1183
  }
1699
1184
  if (!messageControllerRef.current) {
1700
1185
  messageControllerRef.current = new MessageController({
1701
- backendApiRef,
1186
+ aomiClientRef,
1702
1187
  backendStateRef,
1703
1188
  threadContextRef,
1704
1189
  polling: pollingRef.current,
1705
1190
  setGlobalIsRunning: setIsRunning,
1706
1191
  getPublicKey: options.getPublicKey,
1707
- getNamespace: options.getNamespace,
1192
+ getApp: options.getApp,
1708
1193
  getApiKey: options.getApiKey,
1709
1194
  getUserState: options.getUserState,
1710
1195
  onSyncEvents: options.onSyncEvents
@@ -1712,26 +1197,12 @@ function useRuntimeOrchestrator(backendApi, options) {
1712
1197
  }
1713
1198
  const ensureInitialState = (0, import_react6.useCallback)(async (threadId) => {
1714
1199
  var _a, _b, _c, _d;
1715
- const backendState = backendStateRef.current;
1716
- if (shouldSkipInitialFetch(backendState, threadId)) {
1717
- clearSkipInitialFetch(backendState, threadId);
1718
- if (threadContextRef.current.currentThreadId === threadId) {
1719
- setIsRunning(false);
1720
- }
1721
- return;
1722
- }
1723
- if (!isThreadReady(backendState, threadId)) {
1724
- if (threadContextRef.current.currentThreadId === threadId) {
1725
- setIsRunning(false);
1726
- }
1727
- return;
1728
- }
1729
1200
  if (pendingFetches.current.has(threadId)) return;
1730
- const backendThreadId = resolveThreadId(backendState, threadId);
1201
+ const backendThreadId = resolveThreadId(backendStateRef.current, threadId);
1731
1202
  pendingFetches.current.add(threadId);
1732
1203
  try {
1733
1204
  const userState = (_a = options.getUserState) == null ? void 0 : _a.call(options);
1734
- const state = await backendApiRef.current.fetchState(
1205
+ const state = await aomiClientRef.current.fetchState(
1735
1206
  backendThreadId,
1736
1207
  userState
1737
1208
  );
@@ -1763,7 +1234,7 @@ function useRuntimeOrchestrator(backendApi, options) {
1763
1234
  isRunning,
1764
1235
  setIsRunning,
1765
1236
  ensureInitialState,
1766
- backendApiRef
1237
+ aomiClientRef
1767
1238
  };
1768
1239
  }
1769
1240
 
@@ -1794,151 +1265,35 @@ function buildThreadLists(threadMetadata) {
1794
1265
  return { regularThreads, archivedThreads };
1795
1266
  }
1796
1267
  function buildThreadListAdapter({
1797
- backendStateRef,
1798
- backendApiRef,
1268
+ aomiClientRef,
1799
1269
  threadContext,
1800
- currentThreadIdRef,
1801
- polling,
1802
- userAddress,
1803
- setIsRunning,
1804
- getNamespace,
1805
- getApiKey,
1806
- getUserState
1270
+ setIsRunning
1807
1271
  }) {
1808
- const backendState = backendStateRef.current;
1809
1272
  const { regularThreads, archivedThreads } = buildThreadLists(
1810
1273
  threadContext.allThreadsMetadata
1811
1274
  );
1812
- const preparePendingThread = (threadId) => {
1813
- const previousPendingId = backendState.creatingThreadId;
1814
- if (previousPendingId && previousPendingId !== threadId) {
1815
- threadContext.setThreadMetadata((prev) => {
1816
- const next = new Map(prev);
1817
- next.delete(previousPendingId);
1818
- return next;
1819
- });
1820
- threadContext.setThreads((prev) => {
1821
- const next = new Map(prev);
1822
- next.delete(previousPendingId);
1823
- return next;
1824
- });
1825
- backendState.pendingChat.delete(previousPendingId);
1826
- backendState.skipInitialFetch.delete(previousPendingId);
1827
- }
1828
- backendState.creatingThreadId = threadId;
1829
- backendState.pendingChat.delete(threadId);
1830
- threadContext.setThreadMetadata(
1831
- (prev) => new Map(prev).set(threadId, {
1832
- title: "New Chat",
1833
- status: "pending",
1834
- lastActiveAt: (/* @__PURE__ */ new Date()).toISOString(),
1835
- control: initThreadControl()
1836
- })
1837
- );
1838
- threadContext.setThreadMessages(threadId, []);
1839
- threadContext.setCurrentThreadId(threadId);
1840
- setIsRunning(false);
1841
- threadContext.bumpThreadViewKey();
1842
- };
1843
- const findPendingThreadId = () => {
1844
- if (backendState.creatingThreadId) return backendState.creatingThreadId;
1845
- for (const [id, meta] of threadContext.allThreadsMetadata.entries()) {
1846
- if (meta.status === "pending") return id;
1847
- }
1848
- return null;
1849
- };
1850
1275
  return {
1851
1276
  threadId: threadContext.currentThreadId,
1852
1277
  threads: regularThreads,
1853
1278
  archivedThreads,
1854
- onSwitchToNewThread: async () => {
1855
- var _a;
1856
- const pendingId = findPendingThreadId();
1857
- if (pendingId) {
1858
- preparePendingThread(pendingId);
1859
- return;
1860
- }
1861
- if (backendState.createThreadPromise) {
1862
- preparePendingThread((_a = backendState.creatingThreadId) != null ? _a : generateUUID());
1863
- return;
1864
- }
1279
+ onSwitchToNewThread: () => {
1865
1280
  const threadId = generateUUID();
1866
- preparePendingThread(threadId);
1867
- const createPromise = backendApiRef.current.createThread(threadId, userAddress).then(async (newThread) => {
1868
- var _a2, _b;
1869
- const uiThreadId = (_a2 = backendState.creatingThreadId) != null ? _a2 : threadId;
1870
- const backendId = newThread.session_id;
1871
- if (uiThreadId !== backendId) {
1872
- console.warn("[aomi][thread] backend id mismatch", {
1873
- uiThreadId,
1874
- backendId
1875
- });
1876
- }
1877
- markSkipInitialFetch(backendState, uiThreadId);
1878
- threadContext.setThreadMetadata((prev) => {
1879
- var _a3, _b2, _c;
1880
- const next = new Map(prev);
1881
- const existing = next.get(uiThreadId);
1882
- const nextStatus = (existing == null ? void 0 : existing.status) === "archived" ? "archived" : "regular";
1883
- next.set(uiThreadId, {
1884
- title: (_a3 = existing == null ? void 0 : existing.title) != null ? _a3 : "New Chat",
1885
- status: nextStatus,
1886
- lastActiveAt: (_b2 = existing == null ? void 0 : existing.lastActiveAt) != null ? _b2 : (/* @__PURE__ */ new Date()).toISOString(),
1887
- control: (_c = existing == null ? void 0 : existing.control) != null ? _c : initThreadControl()
1888
- });
1889
- return next;
1890
- });
1891
- if (backendState.creatingThreadId === uiThreadId) {
1892
- backendState.creatingThreadId = null;
1893
- }
1894
- const pendingMessages = backendState.pendingChat.get(uiThreadId);
1895
- if (pendingMessages == null ? void 0 : pendingMessages.length) {
1896
- backendState.pendingChat.delete(uiThreadId);
1897
- const namespace = getNamespace();
1898
- const apiKey = (_b = getApiKey == null ? void 0 : getApiKey()) != null ? _b : void 0;
1899
- const userState = getUserState == null ? void 0 : getUserState();
1900
- for (const text of pendingMessages) {
1901
- try {
1902
- await backendApiRef.current.postChatMessage(
1903
- backendId,
1904
- text,
1905
- namespace,
1906
- userAddress,
1907
- apiKey,
1908
- userState
1909
- );
1910
- } catch (error) {
1911
- console.error("Failed to send queued message:", error);
1912
- }
1913
- }
1914
- if (currentThreadIdRef.current === uiThreadId) {
1915
- polling == null ? void 0 : polling.start(uiThreadId);
1916
- }
1917
- }
1918
- }).catch((error) => {
1919
- var _a2;
1920
- console.error("Failed to create new thread:", error);
1921
- const failedId = (_a2 = backendState.creatingThreadId) != null ? _a2 : threadId;
1922
- threadContext.setThreadMetadata((prev) => {
1923
- const next = new Map(prev);
1924
- next.delete(failedId);
1925
- return next;
1926
- });
1927
- threadContext.setThreads((prev) => {
1928
- const next = new Map(prev);
1929
- next.delete(failedId);
1930
- return next;
1931
- });
1932
- if (backendState.creatingThreadId === failedId) {
1933
- backendState.creatingThreadId = null;
1934
- }
1935
- }).finally(() => {
1936
- backendState.createThreadPromise = null;
1937
- });
1938
- backendState.createThreadPromise = createPromise;
1281
+ threadContext.setThreadMetadata(
1282
+ (prev) => new Map(prev).set(threadId, {
1283
+ title: "New Chat",
1284
+ status: "regular",
1285
+ lastActiveAt: (/* @__PURE__ */ new Date()).toISOString(),
1286
+ control: initThreadControl()
1287
+ })
1288
+ );
1289
+ threadContext.setThreadMessages(threadId, []);
1290
+ threadContext.setCurrentThreadId(threadId);
1291
+ setIsRunning(false);
1292
+ threadContext.bumpThreadViewKey();
1939
1293
  },
1940
1294
  onSwitchToThread: (threadId) => {
1941
1295
  threadContext.setCurrentThreadId(threadId);
1296
+ threadContext.bumpThreadViewKey();
1942
1297
  },
1943
1298
  onRename: async (threadId, newTitle) => {
1944
1299
  var _a, _b;
@@ -1948,7 +1303,7 @@ function buildThreadListAdapter({
1948
1303
  title: normalizedTitle
1949
1304
  });
1950
1305
  try {
1951
- await backendApiRef.current.renameThread(threadId, newTitle);
1306
+ await aomiClientRef.current.renameThread(threadId, newTitle);
1952
1307
  } catch (error) {
1953
1308
  console.error("Failed to rename thread:", error);
1954
1309
  threadContext.updateThreadMetadata(threadId, {
@@ -1959,7 +1314,7 @@ function buildThreadListAdapter({
1959
1314
  onArchive: async (threadId) => {
1960
1315
  threadContext.updateThreadMetadata(threadId, { status: "archived" });
1961
1316
  try {
1962
- await backendApiRef.current.archiveThread(threadId);
1317
+ await aomiClientRef.current.archiveThread(threadId);
1963
1318
  } catch (error) {
1964
1319
  console.error("Failed to archive thread:", error);
1965
1320
  threadContext.updateThreadMetadata(threadId, { status: "regular" });
@@ -1968,7 +1323,7 @@ function buildThreadListAdapter({
1968
1323
  onUnarchive: async (threadId) => {
1969
1324
  threadContext.updateThreadMetadata(threadId, { status: "regular" });
1970
1325
  try {
1971
- await backendApiRef.current.unarchiveThread(threadId);
1326
+ await aomiClientRef.current.unarchiveThread(threadId);
1972
1327
  } catch (error) {
1973
1328
  console.error("Failed to unarchive thread:", error);
1974
1329
  threadContext.updateThreadMetadata(threadId, { status: "archived" });
@@ -1976,7 +1331,7 @@ function buildThreadListAdapter({
1976
1331
  },
1977
1332
  onDelete: async (threadId) => {
1978
1333
  try {
1979
- await backendApiRef.current.deleteThread(threadId);
1334
+ await aomiClientRef.current.deleteThread(threadId);
1980
1335
  threadContext.setThreadMetadata((prev) => {
1981
1336
  const next = new Map(prev);
1982
1337
  next.delete(threadId);
@@ -1987,12 +1342,6 @@ function buildThreadListAdapter({
1987
1342
  next.delete(threadId);
1988
1343
  return next;
1989
1344
  });
1990
- backendState.pendingChat.delete(threadId);
1991
- backendState.skipInitialFetch.delete(threadId);
1992
- backendState.runningThreads.delete(threadId);
1993
- if (backendState.creatingThreadId === threadId) {
1994
- backendState.creatingThreadId = null;
1995
- }
1996
1345
  if (threadContext.currentThreadId === threadId) {
1997
1346
  const firstRegularThread = Array.from(
1998
1347
  threadContext.allThreadsMetadata.entries()
@@ -2035,11 +1384,223 @@ function useAomiRuntime() {
2035
1384
  return context;
2036
1385
  }
2037
1386
 
1387
+ // packages/react/src/handlers/wallet-handler.ts
1388
+ var import_react8 = require("react");
1389
+
1390
+ // packages/react/src/state/wallet-buffer.ts
1391
+ function createWalletBuffer() {
1392
+ return { queue: [], nextId: 1 };
1393
+ }
1394
+ function enqueue(buffer, kind, payload) {
1395
+ const request = {
1396
+ id: `wreq-${buffer.nextId++}`,
1397
+ kind,
1398
+ payload,
1399
+ status: "pending",
1400
+ timestamp: Date.now()
1401
+ };
1402
+ buffer.queue.push(request);
1403
+ return request;
1404
+ }
1405
+ function dequeue(buffer, id) {
1406
+ const index = buffer.queue.findIndex((r) => r.id === id);
1407
+ if (index === -1) return null;
1408
+ return buffer.queue.splice(index, 1)[0];
1409
+ }
1410
+ function markProcessing(buffer, id) {
1411
+ const request = buffer.queue.find((r) => r.id === id);
1412
+ if (!request || request.status !== "pending") return false;
1413
+ request.status = "processing";
1414
+ return true;
1415
+ }
1416
+ function getAll(buffer) {
1417
+ return [...buffer.queue];
1418
+ }
1419
+
1420
+ // packages/react/src/handlers/wallet-handler.ts
1421
+ function asRecord(value) {
1422
+ if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
1423
+ return value;
1424
+ }
1425
+ function getToolArgs(payload) {
1426
+ const root = asRecord(payload);
1427
+ const nestedArgs = asRecord(root == null ? void 0 : root.args);
1428
+ return nestedArgs != null ? nestedArgs : root != null ? root : {};
1429
+ }
1430
+ function parseChainId(value) {
1431
+ if (typeof value === "number" && Number.isFinite(value)) return value;
1432
+ if (typeof value !== "string") return void 0;
1433
+ const trimmed = value.trim();
1434
+ if (!trimmed) return void 0;
1435
+ if (trimmed.startsWith("0x")) {
1436
+ const parsedHex = Number.parseInt(trimmed.slice(2), 16);
1437
+ return Number.isFinite(parsedHex) ? parsedHex : void 0;
1438
+ }
1439
+ const parsed = Number.parseInt(trimmed, 10);
1440
+ return Number.isFinite(parsed) ? parsed : void 0;
1441
+ }
1442
+ function normalizeTxPayload(payload) {
1443
+ var _a, _b, _c;
1444
+ const root = asRecord(payload);
1445
+ const args = getToolArgs(payload);
1446
+ const ctx = asRecord(root == null ? void 0 : root.ctx);
1447
+ const to = typeof args.to === "string" ? args.to : void 0;
1448
+ if (!to) return null;
1449
+ const valueRaw = args.value;
1450
+ const value = typeof valueRaw === "string" ? valueRaw : typeof valueRaw === "number" && Number.isFinite(valueRaw) ? String(Math.trunc(valueRaw)) : void 0;
1451
+ const data = typeof args.data === "string" ? args.data : void 0;
1452
+ const chainId = (_c = (_b = (_a = parseChainId(args.chainId)) != null ? _a : parseChainId(args.chain_id)) != null ? _b : parseChainId(ctx == null ? void 0 : ctx.user_chain_id)) != null ? _c : parseChainId(ctx == null ? void 0 : ctx.userChainId);
1453
+ return {
1454
+ to,
1455
+ value,
1456
+ data,
1457
+ chainId
1458
+ };
1459
+ }
1460
+ function normalizeEip712Payload(payload) {
1461
+ var _a;
1462
+ const args = getToolArgs(payload);
1463
+ const typedDataRaw = (_a = args.typed_data) != null ? _a : args.typedData;
1464
+ let typedData;
1465
+ if (typeof typedDataRaw === "string") {
1466
+ try {
1467
+ const parsed = JSON.parse(typedDataRaw);
1468
+ if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
1469
+ typedData = parsed;
1470
+ }
1471
+ } catch (e) {
1472
+ typedData = void 0;
1473
+ }
1474
+ } else if (typedDataRaw && typeof typedDataRaw === "object" && !Array.isArray(typedDataRaw)) {
1475
+ typedData = typedDataRaw;
1476
+ }
1477
+ const description = typeof args.description === "string" ? args.description : void 0;
1478
+ return {
1479
+ typed_data: typedData,
1480
+ description
1481
+ };
1482
+ }
1483
+ function useWalletHandler({
1484
+ sessionId,
1485
+ onRequestComplete
1486
+ }) {
1487
+ const { subscribe: subscribe2, sendOutboundSystem: sendOutbound } = useEventContext();
1488
+ const bufferRef = (0, import_react8.useRef)(createWalletBuffer());
1489
+ const [pendingRequests, setPendingRequests] = (0, import_react8.useState)([]);
1490
+ const syncState = (0, import_react8.useCallback)(() => {
1491
+ setPendingRequests(getAll(bufferRef.current));
1492
+ }, []);
1493
+ (0, import_react8.useEffect)(() => {
1494
+ const unsubscribe = subscribe2(
1495
+ "wallet_tx_request",
1496
+ (event) => {
1497
+ const payload = normalizeTxPayload(event.payload);
1498
+ if (!payload) {
1499
+ console.warn("[aomi][wallet] Ignoring tx request with invalid payload", event.payload);
1500
+ return;
1501
+ }
1502
+ enqueue(bufferRef.current, "transaction", payload);
1503
+ syncState();
1504
+ }
1505
+ );
1506
+ return unsubscribe;
1507
+ }, [subscribe2, syncState]);
1508
+ (0, import_react8.useEffect)(() => {
1509
+ const unsubscribe = subscribe2(
1510
+ "wallet_eip712_request",
1511
+ (event) => {
1512
+ var _a;
1513
+ const payload = normalizeEip712Payload((_a = event.payload) != null ? _a : {});
1514
+ enqueue(bufferRef.current, "eip712_sign", payload);
1515
+ syncState();
1516
+ }
1517
+ );
1518
+ return unsubscribe;
1519
+ }, [subscribe2, syncState]);
1520
+ const startProcessingCb = (0, import_react8.useCallback)(
1521
+ (id) => {
1522
+ markProcessing(bufferRef.current, id);
1523
+ syncState();
1524
+ },
1525
+ [syncState]
1526
+ );
1527
+ const resolveRequest = (0, import_react8.useCallback)(
1528
+ (id, result) => {
1529
+ var _a;
1530
+ const removed = dequeue(bufferRef.current, id);
1531
+ if (!removed) return;
1532
+ let outbound;
1533
+ if (removed.kind === "transaction") {
1534
+ outbound = sendOutbound({
1535
+ type: "wallet:tx_complete",
1536
+ sessionId,
1537
+ payload: {
1538
+ txHash: (_a = result.txHash) != null ? _a : "",
1539
+ status: "success",
1540
+ amount: result.amount
1541
+ }
1542
+ });
1543
+ } else {
1544
+ const eip712Payload = removed.payload;
1545
+ outbound = sendOutbound({
1546
+ type: "wallet_eip712_response",
1547
+ sessionId,
1548
+ payload: {
1549
+ status: "success",
1550
+ signature: result.signature,
1551
+ description: eip712Payload.description
1552
+ }
1553
+ });
1554
+ }
1555
+ outbound.then(() => onRequestComplete == null ? void 0 : onRequestComplete());
1556
+ syncState();
1557
+ },
1558
+ [sendOutbound, sessionId, syncState, onRequestComplete]
1559
+ );
1560
+ const rejectRequest = (0, import_react8.useCallback)(
1561
+ (id, error) => {
1562
+ const removed = dequeue(bufferRef.current, id);
1563
+ if (!removed) return;
1564
+ let outbound;
1565
+ if (removed.kind === "transaction") {
1566
+ outbound = sendOutbound({
1567
+ type: "wallet:tx_complete",
1568
+ sessionId,
1569
+ payload: {
1570
+ txHash: "",
1571
+ status: "failed"
1572
+ }
1573
+ });
1574
+ } else {
1575
+ const eip712Payload = removed.payload;
1576
+ outbound = sendOutbound({
1577
+ type: "wallet_eip712_response",
1578
+ sessionId,
1579
+ payload: {
1580
+ status: "failed",
1581
+ error: error != null ? error : "EIP-712 signing failed",
1582
+ description: eip712Payload.description
1583
+ }
1584
+ });
1585
+ }
1586
+ outbound.then(() => onRequestComplete == null ? void 0 : onRequestComplete());
1587
+ syncState();
1588
+ },
1589
+ [sendOutbound, sessionId, syncState, onRequestComplete]
1590
+ );
1591
+ return {
1592
+ pendingRequests,
1593
+ startProcessing: startProcessingCb,
1594
+ resolveRequest,
1595
+ rejectRequest
1596
+ };
1597
+ }
1598
+
2038
1599
  // packages/react/src/runtime/core.tsx
2039
1600
  var import_jsx_runtime6 = require("react/jsx-runtime");
2040
1601
  function AomiRuntimeCore({
2041
1602
  children,
2042
- backendApi
1603
+ aomiClient
2043
1604
  }) {
2044
1605
  const threadContext = useThreadContext();
2045
1606
  const eventContext = useEventContext();
@@ -2054,18 +1615,18 @@ function AomiRuntimeCore({
2054
1615
  isRunning,
2055
1616
  setIsRunning,
2056
1617
  ensureInitialState,
2057
- backendApiRef
2058
- } = useRuntimeOrchestrator(backendApi, {
1618
+ aomiClientRef
1619
+ } = useRuntimeOrchestrator(aomiClient, {
2059
1620
  onSyncEvents: dispatchSystemEvents,
2060
1621
  getPublicKey: () => getUserState().address,
2061
1622
  getUserState,
2062
- getNamespace: () => {
1623
+ getApp: () => {
2063
1624
  var _a, _b;
2064
- return (_b = (_a = getCurrentThreadControl().namespace) != null ? _a : getControlState().defaultNamespace) != null ? _b : "default";
1625
+ return (_b = (_a = getCurrentThreadControl().app) != null ? _a : getControlState().defaultApp) != null ? _b : "default";
2065
1626
  },
2066
1627
  getApiKey: () => getControlState().apiKey
2067
1628
  });
2068
- (0, import_react8.useEffect)(() => {
1629
+ (0, import_react9.useEffect)(() => {
2069
1630
  const unsubscribe = onUserStateChange(async (newUser) => {
2070
1631
  const sessionId = threadContext.currentThreadId;
2071
1632
  const message = JSON.stringify({
@@ -2077,24 +1638,44 @@ function AomiRuntimeCore({
2077
1638
  ensName: newUser.ensName
2078
1639
  }
2079
1640
  });
2080
- await backendApiRef.current.postSystemMessage(sessionId, message);
1641
+ await aomiClientRef.current.sendSystemMessage(sessionId, message);
2081
1642
  });
2082
1643
  return unsubscribe;
2083
- }, [onUserStateChange, backendApiRef, threadContext.currentThreadId]);
2084
- const threadContextRef = (0, import_react8.useRef)(threadContext);
1644
+ }, [onUserStateChange, aomiClientRef, threadContext.currentThreadId]);
1645
+ const threadContextRef = (0, import_react9.useRef)(threadContext);
2085
1646
  threadContextRef.current = threadContext;
2086
- const currentThreadIdRef = (0, import_react8.useRef)(threadContext.currentThreadId);
2087
- (0, import_react8.useEffect)(() => {
1647
+ const currentThreadIdRef = (0, import_react9.useRef)(threadContext.currentThreadId);
1648
+ (0, import_react9.useEffect)(() => {
2088
1649
  currentThreadIdRef.current = threadContext.currentThreadId;
2089
1650
  }, [threadContext.currentThreadId]);
2090
- (0, import_react8.useEffect)(() => {
1651
+ const onWalletRequestComplete = (0, import_react9.useCallback)(() => {
1652
+ polling.start(currentThreadIdRef.current);
1653
+ }, [polling]);
1654
+ const walletHandler = useWalletHandler({
1655
+ sessionId: threadContext.currentThreadId,
1656
+ onRequestComplete: onWalletRequestComplete
1657
+ });
1658
+ (0, import_react9.useEffect)(() => {
1659
+ const unsubscribe = eventContext.subscribe(
1660
+ "user_state_request",
1661
+ () => {
1662
+ eventContext.sendOutboundSystem({
1663
+ type: "user_state_response",
1664
+ sessionId: threadContext.currentThreadId,
1665
+ payload: getUserState()
1666
+ });
1667
+ }
1668
+ );
1669
+ return unsubscribe;
1670
+ }, [eventContext, threadContext.currentThreadId, getUserState]);
1671
+ (0, import_react9.useEffect)(() => {
2091
1672
  void ensureInitialState(threadContext.currentThreadId);
2092
1673
  }, [ensureInitialState, threadContext.currentThreadId]);
2093
- (0, import_react8.useEffect)(() => {
1674
+ (0, import_react9.useEffect)(() => {
2094
1675
  const threadId = threadContext.currentThreadId;
2095
1676
  setIsRunning(isThreadRunning(backendStateRef.current, threadId));
2096
1677
  }, [backendStateRef, setIsRunning, threadContext.currentThreadId]);
2097
- (0, import_react8.useEffect)(() => {
1678
+ (0, import_react9.useEffect)(() => {
2098
1679
  const threadId = threadContext.currentThreadId;
2099
1680
  const currentMeta = threadContext.getThreadMetadata(threadId);
2100
1681
  if (currentMeta && currentMeta.control.isProcessing !== isRunning) {
@@ -2108,21 +1689,13 @@ function AomiRuntimeCore({
2108
1689
  const currentMessages = threadContext.getThreadMessages(
2109
1690
  threadContext.currentThreadId
2110
1691
  );
2111
- const resolvedSessionId = (0, import_react8.useMemo)(
2112
- () => resolveThreadId(backendStateRef.current, threadContext.currentThreadId),
2113
- [
2114
- backendStateRef,
2115
- threadContext.currentThreadId,
2116
- threadContext.allThreadsMetadata
2117
- ]
2118
- );
2119
- (0, import_react8.useEffect)(() => {
1692
+ (0, import_react9.useEffect)(() => {
2120
1693
  const userAddress = user.address;
2121
1694
  if (!userAddress) return;
2122
1695
  const fetchThreadList = async () => {
2123
1696
  var _a, _b, _c;
2124
1697
  try {
2125
- const threadList = await backendApiRef.current.fetchThreads(userAddress);
1698
+ const threadList = await aomiClientRef.current.listThreads(userAddress);
2126
1699
  const currentContext = threadContextRef.current;
2127
1700
  const newMetadata = new Map(currentContext.allThreadsMetadata);
2128
1701
  let maxChatNum = currentContext.threadCnt;
@@ -2154,25 +1727,25 @@ function AomiRuntimeCore({
2154
1727
  }
2155
1728
  };
2156
1729
  void fetchThreadList();
2157
- }, [user.address, backendApiRef]);
2158
- const threadListAdapter = (0, import_react8.useMemo)(
1730
+ }, [user.address, aomiClientRef]);
1731
+ const threadListAdapter = (0, import_react9.useMemo)(
2159
1732
  () => buildThreadListAdapter({
2160
1733
  backendStateRef,
2161
- backendApiRef,
1734
+ aomiClientRef,
2162
1735
  threadContext,
2163
1736
  currentThreadIdRef,
2164
1737
  polling,
2165
1738
  userAddress: user.address,
2166
1739
  setIsRunning,
2167
- getNamespace: () => {
1740
+ getApp: () => {
2168
1741
  var _a, _b;
2169
- return (_b = (_a = getCurrentThreadControl().namespace) != null ? _a : getControlState().defaultNamespace) != null ? _b : "default";
1742
+ return (_b = (_a = getCurrentThreadControl().app) != null ? _a : getControlState().defaultApp) != null ? _b : "default";
2170
1743
  },
2171
1744
  getApiKey: () => getControlState().apiKey,
2172
1745
  getUserState
2173
1746
  }),
2174
1747
  [
2175
- backendApiRef,
1748
+ aomiClientRef,
2176
1749
  polling,
2177
1750
  user.address,
2178
1751
  backendStateRef,
@@ -2184,70 +1757,41 @@ function AomiRuntimeCore({
2184
1757
  getUserState
2185
1758
  ]
2186
1759
  );
2187
- (0, import_react8.useEffect)(() => {
1760
+ (0, import_react9.useEffect)(() => {
2188
1761
  const backendState = backendStateRef.current;
2189
- const currentSessionId = threadContext.currentThreadId;
2190
- if (process.env.NODE_ENV !== "production") {
2191
- console.debug("[aomi][sse] subscribe", {
2192
- currentSessionId,
2193
- resolvedSessionId,
2194
- hasMapping: currentSessionId !== resolvedSessionId
2195
- });
2196
- }
2197
- const unsubscribe = backendApiRef.current.subscribeSSE(
2198
- resolvedSessionId,
2199
- (event) => {
2200
- const eventType = event.type;
2201
- const sessionId = event.session_id;
2202
- if (eventType === "title_changed") {
2203
- const newTitle = event.new_title;
2204
- const targetThreadId = resolveThreadId(backendState, sessionId);
2205
- const normalizedTitle = isPlaceholderTitle(newTitle) ? "" : newTitle;
2206
- if (process.env.NODE_ENV !== "production") {
2207
- console.debug("[aomi][sse] title_changed", {
2208
- sessionId,
2209
- newTitle,
2210
- normalizedTitle,
2211
- currentThreadId: threadContextRef.current.currentThreadId,
2212
- targetThreadId,
2213
- hasMapping: sessionId !== targetThreadId,
2214
- creatingThreadId: backendState.creatingThreadId
2215
- });
2216
- }
2217
- threadContextRef.current.setThreadMetadata((prev) => {
2218
- var _a, _b;
2219
- const next = new Map(prev);
2220
- const existing = next.get(targetThreadId);
2221
- const nextStatus = (existing == null ? void 0 : existing.status) === "archived" ? "archived" : "regular";
2222
- next.set(targetThreadId, {
2223
- title: normalizedTitle,
2224
- status: nextStatus,
2225
- lastActiveAt: (_a = existing == null ? void 0 : existing.lastActiveAt) != null ? _a : (/* @__PURE__ */ new Date()).toISOString(),
2226
- control: (_b = existing == null ? void 0 : existing.control) != null ? _b : initThreadControl()
2227
- });
2228
- return next;
2229
- });
2230
- if (!isPlaceholderTitle(newTitle) && backendState.creatingThreadId === targetThreadId) {
2231
- backendState.creatingThreadId = null;
2232
- }
2233
- }
1762
+ const unsubscribe = eventContext.subscribe("title_changed", (event) => {
1763
+ const sessionId = event.sessionId;
1764
+ const payload = event.payload;
1765
+ const newTitle = payload == null ? void 0 : payload.new_title;
1766
+ if (typeof newTitle !== "string") return;
1767
+ const targetThreadId = resolveThreadId(backendState, sessionId);
1768
+ const normalizedTitle = isPlaceholderTitle(newTitle) ? "" : newTitle;
1769
+ if (process.env.NODE_ENV !== "production") {
1770
+ console.debug("[aomi][sse] title_changed", {
1771
+ sessionId,
1772
+ newTitle,
1773
+ normalizedTitle,
1774
+ currentThreadId: threadContextRef.current.currentThreadId,
1775
+ targetThreadId
1776
+ });
2234
1777
  }
2235
- );
2236
- return () => {
2237
- unsubscribe == null ? void 0 : unsubscribe();
2238
- };
2239
- }, [
2240
- backendApiRef,
2241
- backendStateRef,
2242
- threadContext.currentThreadId,
2243
- resolvedSessionId
2244
- ]);
2245
- (0, import_react8.useEffect)(() => {
2246
- const threadId = threadContext.currentThreadId;
2247
- if (!isThreadReady(backendStateRef.current, threadId)) return;
2248
- void messageController.flushPendingChat(threadId);
2249
- }, [messageController, backendStateRef, threadContext.currentThreadId]);
2250
- (0, import_react8.useEffect)(() => {
1778
+ threadContextRef.current.setThreadMetadata((prev) => {
1779
+ var _a, _b;
1780
+ const next = new Map(prev);
1781
+ const existing = next.get(targetThreadId);
1782
+ const nextStatus = (existing == null ? void 0 : existing.status) === "archived" ? "archived" : "regular";
1783
+ next.set(targetThreadId, {
1784
+ title: normalizedTitle,
1785
+ status: nextStatus,
1786
+ lastActiveAt: (_a = existing == null ? void 0 : existing.lastActiveAt) != null ? _a : (/* @__PURE__ */ new Date()).toISOString(),
1787
+ control: (_b = existing == null ? void 0 : existing.control) != null ? _b : initThreadControl()
1788
+ });
1789
+ return next;
1790
+ });
1791
+ });
1792
+ return unsubscribe;
1793
+ }, [eventContext, backendStateRef]);
1794
+ (0, import_react9.useEffect)(() => {
2251
1795
  const showToolNotification = (eventType) => (event) => {
2252
1796
  const payload = event.payload;
2253
1797
  const toolName = typeof (payload == null ? void 0 : payload.tool_name) === "string" ? payload.tool_name : void 0;
@@ -2272,14 +1816,14 @@ function AomiRuntimeCore({
2272
1816
  unsubscribeComplete();
2273
1817
  };
2274
1818
  }, [eventContext, notificationContext]);
2275
- (0, import_react8.useEffect)(() => {
1819
+ (0, import_react9.useEffect)(() => {
2276
1820
  const unsubscribe = eventContext.subscribe("system_notice", (event) => {
2277
1821
  const payload = event.payload;
2278
1822
  const message = payload == null ? void 0 : payload.message;
2279
1823
  });
2280
1824
  return unsubscribe;
2281
1825
  }, [eventContext, notificationContext]);
2282
- const runtime = (0, import_react9.useExternalStoreRuntime)({
1826
+ const runtime = (0, import_react10.useExternalStoreRuntime)({
2283
1827
  messages: currentMessages,
2284
1828
  setMessages: (msgs) => threadContext.setThreadMessages(threadContext.currentThreadId, [...msgs]),
2285
1829
  isRunning,
@@ -2288,13 +1832,13 @@ function AomiRuntimeCore({
2288
1832
  convertMessage: (msg) => msg,
2289
1833
  adapters: { threadList: threadListAdapter }
2290
1834
  });
2291
- (0, import_react8.useEffect)(() => {
1835
+ (0, import_react9.useEffect)(() => {
2292
1836
  return () => {
2293
1837
  polling.stopAll();
2294
1838
  };
2295
1839
  }, [polling]);
2296
1840
  const userContext = useUser();
2297
- const sendMessage = (0, import_react8.useCallback)(
1841
+ const sendMessage = (0, import_react9.useCallback)(
2298
1842
  async (text) => {
2299
1843
  const appendMessage = {
2300
1844
  role: "user",
@@ -2307,39 +1851,39 @@ function AomiRuntimeCore({
2307
1851
  },
2308
1852
  [messageController, threadContext.currentThreadId]
2309
1853
  );
2310
- const cancelGeneration = (0, import_react8.useCallback)(() => {
1854
+ const cancelGeneration = (0, import_react9.useCallback)(() => {
2311
1855
  messageController.cancel(threadContext.currentThreadId);
2312
1856
  }, [messageController, threadContext.currentThreadId]);
2313
- const getMessages = (0, import_react8.useCallback)(
1857
+ const getMessages = (0, import_react9.useCallback)(
2314
1858
  (threadId) => {
2315
1859
  const id = threadId != null ? threadId : threadContext.currentThreadId;
2316
1860
  return threadContext.getThreadMessages(id);
2317
1861
  },
2318
1862
  [threadContext]
2319
1863
  );
2320
- const createThread = (0, import_react8.useCallback)(async () => {
1864
+ const createThread = (0, import_react9.useCallback)(async () => {
2321
1865
  await threadListAdapter.onSwitchToNewThread();
2322
1866
  return threadContextRef.current.currentThreadId;
2323
1867
  }, [threadListAdapter]);
2324
- const deleteThread = (0, import_react8.useCallback)(
1868
+ const deleteThread = (0, import_react9.useCallback)(
2325
1869
  async (threadId) => {
2326
1870
  await threadListAdapter.onDelete(threadId);
2327
1871
  },
2328
1872
  [threadListAdapter]
2329
1873
  );
2330
- const renameThread = (0, import_react8.useCallback)(
1874
+ const renameThread = (0, import_react9.useCallback)(
2331
1875
  async (threadId, title) => {
2332
1876
  await threadListAdapter.onRename(threadId, title);
2333
1877
  },
2334
1878
  [threadListAdapter]
2335
1879
  );
2336
- const archiveThread = (0, import_react8.useCallback)(
1880
+ const archiveThread = (0, import_react9.useCallback)(
2337
1881
  async (threadId) => {
2338
1882
  await threadListAdapter.onArchive(threadId);
2339
1883
  },
2340
1884
  [threadListAdapter]
2341
1885
  );
2342
- const selectThread = (0, import_react8.useCallback)(
1886
+ const selectThread = (0, import_react9.useCallback)(
2343
1887
  (threadId) => {
2344
1888
  if (threadContext.allThreadsMetadata.has(threadId)) {
2345
1889
  threadListAdapter.onSwitchToThread(threadId);
@@ -2349,7 +1893,7 @@ function AomiRuntimeCore({
2349
1893
  },
2350
1894
  [threadContext.allThreadsMetadata, threadListAdapter]
2351
1895
  );
2352
- const aomiRuntimeApi = (0, import_react8.useMemo)(
1896
+ const aomiRuntimeApi = (0, import_react9.useMemo)(
2353
1897
  () => ({
2354
1898
  // User API
2355
1899
  user: userContext.user,
@@ -2376,6 +1920,11 @@ function AomiRuntimeCore({
2376
1920
  showNotification: notificationContext.showNotification,
2377
1921
  dismissNotification: notificationContext.dismissNotification,
2378
1922
  clearAllNotifications: notificationContext.clearAll,
1923
+ // Wallet API
1924
+ pendingWalletRequests: walletHandler.pendingRequests,
1925
+ startWalletRequest: walletHandler.startProcessing,
1926
+ resolveWalletRequest: walletHandler.resolveRequest,
1927
+ rejectWalletRequest: walletHandler.rejectRequest,
2379
1928
  // Event API
2380
1929
  subscribe: eventContext.subscribe,
2381
1930
  sendSystemCommand: eventContext.sendOutboundSystem,
@@ -2397,10 +1946,11 @@ function AomiRuntimeCore({
2397
1946
  sendMessage,
2398
1947
  cancelGeneration,
2399
1948
  notificationContext,
1949
+ walletHandler,
2400
1950
  eventContext
2401
1951
  ]
2402
1952
  );
2403
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(AomiRuntimeApiProvider, { value: aomiRuntimeApi, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_react9.AssistantRuntimeProvider, { runtime, children }) });
1953
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(AomiRuntimeApiProvider, { value: aomiRuntimeApi, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_react10.AssistantRuntimeProvider, { runtime, children }) });
2404
1954
  }
2405
1955
 
2406
1956
  // packages/react/src/runtime/aomi-runtime.tsx
@@ -2409,12 +1959,12 @@ function AomiRuntimeProvider({
2409
1959
  children,
2410
1960
  backendUrl = "http://localhost:8080"
2411
1961
  }) {
2412
- const backendApi = (0, import_react10.useMemo)(() => new BackendApi(backendUrl), [backendUrl]);
2413
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ThreadContextProvider, { children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(NotificationContextProvider, { children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(UserContextProvider, { children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(AomiRuntimeInner, { backendApi, children }) }) }) });
1962
+ const aomiClient = (0, import_react11.useMemo)(() => new import_client2.AomiClient({ baseUrl: backendUrl }), [backendUrl]);
1963
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ThreadContextProvider, { children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(NotificationContextProvider, { children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(UserContextProvider, { children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(AomiRuntimeInner, { aomiClient, children }) }) }) });
2414
1964
  }
2415
1965
  function AomiRuntimeInner({
2416
1966
  children,
2417
- backendApi
1967
+ aomiClient
2418
1968
  }) {
2419
1969
  var _a;
2420
1970
  const threadContext = useThreadContext();
@@ -2422,7 +1972,7 @@ function AomiRuntimeInner({
2422
1972
  return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
2423
1973
  ControlContextProvider,
2424
1974
  {
2425
- backendApi,
1975
+ aomiClient,
2426
1976
  sessionId: threadContext.currentThreadId,
2427
1977
  publicKey: (_a = user.address) != null ? _a : void 0,
2428
1978
  getThreadMetadata: threadContext.getThreadMetadata,
@@ -2430,94 +1980,15 @@ function AomiRuntimeInner({
2430
1980
  children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
2431
1981
  EventContextProvider,
2432
1982
  {
2433
- backendApi,
1983
+ aomiClient,
2434
1984
  sessionId: threadContext.currentThreadId,
2435
- children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(AomiRuntimeCore, { backendApi, children })
1985
+ children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(AomiRuntimeCore, { aomiClient, children })
2436
1986
  }
2437
1987
  )
2438
1988
  }
2439
1989
  );
2440
1990
  }
2441
1991
 
2442
- // packages/react/src/handlers/wallet-handler.ts
2443
- var import_react11 = require("react");
2444
- function useWalletHandler({
2445
- sessionId,
2446
- onTxRequest
2447
- }) {
2448
- const { subscribe: subscribe2, sendOutboundSystem: sendOutbound } = useEventContext();
2449
- const { setUser, getUserState } = useUser();
2450
- const [pendingTxRequests, setPendingTxRequests] = (0, import_react11.useState)(
2451
- []
2452
- );
2453
- (0, import_react11.useEffect)(() => {
2454
- const unsubscribe = subscribe2(
2455
- "wallet_tx_request",
2456
- (event) => {
2457
- const request = event.payload;
2458
- setPendingTxRequests((prev) => [...prev, request]);
2459
- onTxRequest == null ? void 0 : onTxRequest(request);
2460
- }
2461
- );
2462
- return unsubscribe;
2463
- }, [subscribe2, onTxRequest]);
2464
- (0, import_react11.useEffect)(() => {
2465
- const unsubscribe = subscribe2(
2466
- "user_state_request",
2467
- (event) => {
2468
- sendOutbound({
2469
- type: "user_state_response",
2470
- sessionId,
2471
- payload: getUserState()
2472
- });
2473
- }
2474
- );
2475
- return unsubscribe;
2476
- }, [subscribe2, onTxRequest]);
2477
- const sendTxComplete = (0, import_react11.useCallback)(
2478
- (tx) => {
2479
- sendOutbound({
2480
- type: "wallet:tx_complete",
2481
- sessionId,
2482
- payload: tx
2483
- });
2484
- },
2485
- [sendOutbound, sessionId]
2486
- );
2487
- const sendConnectionChange = (0, import_react11.useCallback)(
2488
- (status, address, chainId) => {
2489
- if (status === "connected") {
2490
- setUser({
2491
- isConnected: true,
2492
- address,
2493
- chainId
2494
- });
2495
- } else {
2496
- setUser({
2497
- isConnected: false,
2498
- address: void 0,
2499
- chainId: void 0
2500
- });
2501
- }
2502
- sendOutbound({
2503
- type: status === "connected" ? "wallet:connected" : "wallet:disconnected",
2504
- sessionId,
2505
- payload: { status, address }
2506
- });
2507
- },
2508
- [setUser, sendOutbound, sessionId]
2509
- );
2510
- const clearTxRequest = (0, import_react11.useCallback)((index) => {
2511
- setPendingTxRequests((prev) => prev.filter((_, i) => i !== index));
2512
- }, []);
2513
- return {
2514
- sendTxComplete,
2515
- sendConnectionChange,
2516
- pendingTxRequests,
2517
- clearTxRequest
2518
- };
2519
- }
2520
-
2521
1992
  // packages/react/src/handlers/notification-handler.ts
2522
1993
  var import_react12 = require("react");
2523
1994
  var notificationIdCounter2 = 0;
@@ -2561,8 +2032,8 @@ function useNotificationHandler({
2561
2032
  }
2562
2033
  // Annotate the CommonJS export names for ESM import in node:
2563
2034
  0 && (module.exports = {
2035
+ AomiClient,
2564
2036
  AomiRuntimeProvider,
2565
- BackendApi,
2566
2037
  ControlContextProvider,
2567
2038
  EventContextProvider,
2568
2039
  NotificationContextProvider,