@aomi-labs/react 0.3.0 → 0.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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_client4.AomiClient,
40
41
  AomiRuntimeProvider: () => AomiRuntimeProvider,
41
- BackendApi: () => BackendApi,
42
42
  ControlContextProvider: () => ControlContextProvider,
43
43
  EventContextProvider: () => EventContextProvider,
44
44
  NotificationContextProvider: () => NotificationContextProvider,
@@ -50,6 +50,7 @@ __export(index_exports, {
50
50
  getChainInfo: () => getChainInfo,
51
51
  getNetworkName: () => getNetworkName,
52
52
  initThreadControl: () => initThreadControl,
53
+ toViemSignTypedDataArgs: () => import_client5.toViemSignTypedDataArgs,
53
54
  useAomiRuntime: () => useAomiRuntime,
54
55
  useControl: () => useControl,
55
56
  useCurrentThreadMessages: () => useCurrentThreadMessages,
@@ -62,439 +63,12 @@ __export(index_exports, {
62
63
  useWalletHandler: () => useWalletHandler
63
64
  });
64
65
  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
- };
66
+ var import_client4 = require("@aomi-labs/client");
67
+ var import_client5 = require("@aomi-labs/client");
495
68
 
496
69
  // packages/react/src/runtime/aomi-runtime.tsx
497
70
  var import_react11 = require("react");
71
+ var import_client3 = require("@aomi-labs/client");
498
72
 
499
73
  // packages/react/src/contexts/control-context.tsx
500
74
  var import_react = require("react");
@@ -527,7 +101,7 @@ var logThreadMetadataChange = (source, threadId, prev, next) => {
527
101
  function initThreadControl() {
528
102
  return {
529
103
  model: null,
530
- namespace: null,
104
+ app: null,
531
105
  controlDirty: false,
532
106
  isProcessing: false
533
107
  };
@@ -673,6 +247,16 @@ var ThreadStore = class {
673
247
  // packages/react/src/contexts/control-context.tsx
674
248
  var import_jsx_runtime = require("react/jsx-runtime");
675
249
  var API_KEY_STORAGE_KEY = "aomi_api_key";
250
+ function getDefaultApp(apps) {
251
+ var _a;
252
+ return apps.includes("default") ? "default" : (_a = apps[0]) != null ? _a : null;
253
+ }
254
+ function resolveAuthorizedApp(app, authorizedApps, defaultApp) {
255
+ if (app && authorizedApps.includes(app)) {
256
+ return app;
257
+ }
258
+ return defaultApp;
259
+ }
676
260
  var ControlContext = (0, import_react.createContext)(null);
677
261
  function useControl() {
678
262
  const ctx = (0, import_react.useContext)(ControlContext);
@@ -683,7 +267,7 @@ function useControl() {
683
267
  }
684
268
  function ControlContextProvider({
685
269
  children,
686
- backendApi,
270
+ aomiClient,
687
271
  sessionId,
688
272
  publicKey,
689
273
  getThreadMetadata,
@@ -693,14 +277,14 @@ function ControlContextProvider({
693
277
  const [state, setStateInternal] = (0, import_react.useState)(() => ({
694
278
  apiKey: null,
695
279
  availableModels: [],
696
- authorizedNamespaces: [],
280
+ authorizedApps: [],
697
281
  defaultModel: null,
698
- defaultNamespace: null
282
+ defaultApp: null
699
283
  }));
700
284
  const stateRef = (0, import_react.useRef)(state);
701
285
  stateRef.current = state;
702
- const backendApiRef = (0, import_react.useRef)(backendApi);
703
- backendApiRef.current = backendApi;
286
+ const aomiClientRef = (0, import_react.useRef)(aomiClient);
287
+ aomiClientRef.current = aomiClient;
704
288
  const sessionIdRef = (0, import_react.useRef)(sessionId);
705
289
  sessionIdRef.current = sessionId;
706
290
  const publicKeyRef = (0, import_react.useRef)(publicKey);
@@ -734,33 +318,35 @@ function ControlContextProvider({
734
318
  }
735
319
  }, [state.apiKey]);
736
320
  (0, import_react.useEffect)(() => {
737
- const fetchNamespaces = async () => {
738
- var _a2, _b2;
321
+ const fetchApps = async () => {
322
+ var _a2;
739
323
  try {
740
- const namespaces = await backendApiRef.current.getNamespaces(
324
+ const apps = await aomiClientRef.current.getApps(
741
325
  sessionIdRef.current,
742
- publicKeyRef.current,
743
- (_a2 = stateRef.current.apiKey) != null ? _a2 : void 0
326
+ {
327
+ publicKey: publicKeyRef.current,
328
+ apiKey: (_a2 = stateRef.current.apiKey) != null ? _a2 : void 0
329
+ }
744
330
  );
745
- const defaultNs = namespaces.includes("default") ? "default" : (_b2 = namespaces[0]) != null ? _b2 : null;
331
+ const defaultApp = getDefaultApp(apps);
746
332
  setStateInternal((prev) => __spreadProps(__spreadValues({}, prev), {
747
- authorizedNamespaces: namespaces,
748
- defaultNamespace: defaultNs
333
+ authorizedApps: apps,
334
+ defaultApp
749
335
  }));
750
336
  } catch (error) {
751
- console.error("Failed to fetch namespaces:", error);
337
+ console.error("Failed to fetch apps:", error);
752
338
  setStateInternal((prev) => __spreadProps(__spreadValues({}, prev), {
753
- authorizedNamespaces: ["default"],
754
- defaultNamespace: "default"
339
+ authorizedApps: ["default"],
340
+ defaultApp: "default"
755
341
  }));
756
342
  }
757
343
  };
758
- void fetchNamespaces();
759
- }, [state.apiKey]);
344
+ void fetchApps();
345
+ }, [state.apiKey, publicKey, sessionId]);
760
346
  (0, import_react.useEffect)(() => {
761
347
  const fetchModels = async () => {
762
348
  try {
763
- const models = await backendApiRef.current.getModels(
349
+ const models = await aomiClientRef.current.getModels(
764
350
  sessionIdRef.current
765
351
  );
766
352
  setStateInternal((prev) => {
@@ -785,7 +371,7 @@ function ControlContextProvider({
785
371
  }, []);
786
372
  const getAvailableModels = (0, import_react.useCallback)(async () => {
787
373
  try {
788
- const models = await backendApiRef.current.getModels(
374
+ const models = await aomiClientRef.current.getModels(
789
375
  sessionIdRef.current
790
376
  );
791
377
  setStateInternal((prev) => {
@@ -801,25 +387,27 @@ function ControlContextProvider({
801
387
  return [];
802
388
  }
803
389
  }, []);
804
- const getAuthorizedNamespaces = (0, import_react.useCallback)(async () => {
805
- var _a2, _b2;
390
+ const getAuthorizedApps = (0, import_react.useCallback)(async () => {
391
+ var _a2;
806
392
  try {
807
- const namespaces = await backendApiRef.current.getNamespaces(
393
+ const apps = await aomiClientRef.current.getApps(
808
394
  sessionIdRef.current,
809
- publicKeyRef.current,
810
- (_a2 = stateRef.current.apiKey) != null ? _a2 : void 0
395
+ {
396
+ publicKey: publicKeyRef.current,
397
+ apiKey: (_a2 = stateRef.current.apiKey) != null ? _a2 : void 0
398
+ }
811
399
  );
812
- const defaultNs = namespaces.includes("default") ? "default" : (_b2 = namespaces[0]) != null ? _b2 : null;
400
+ const defaultApp = getDefaultApp(apps);
813
401
  setStateInternal((prev) => __spreadProps(__spreadValues({}, prev), {
814
- authorizedNamespaces: namespaces,
815
- defaultNamespace: defaultNs
402
+ authorizedApps: apps,
403
+ defaultApp
816
404
  }));
817
- return namespaces;
405
+ return apps;
818
406
  } catch (error) {
819
- console.error("Failed to fetch namespaces:", error);
407
+ console.error("Failed to fetch apps:", error);
820
408
  setStateInternal((prev) => __spreadProps(__spreadValues({}, prev), {
821
- authorizedNamespaces: ["default"],
822
- defaultNamespace: "default"
409
+ authorizedApps: ["default"],
410
+ defaultApp: "default"
823
411
  }));
824
412
  return ["default"];
825
413
  }
@@ -829,8 +417,17 @@ function ControlContextProvider({
829
417
  const metadata = getThreadMetadataRef.current(sessionIdRef.current);
830
418
  return (_a2 = metadata == null ? void 0 : metadata.control) != null ? _a2 : initThreadControl();
831
419
  }, []);
420
+ const getCurrentThreadApp = (0, import_react.useCallback)(() => {
421
+ var _a2, _b2, _c;
422
+ const currentControl = (_b2 = (_a2 = getThreadMetadataRef.current(sessionIdRef.current)) == null ? void 0 : _a2.control) != null ? _b2 : initThreadControl();
423
+ return (_c = resolveAuthorizedApp(
424
+ currentControl.app,
425
+ stateRef.current.authorizedApps,
426
+ stateRef.current.defaultApp
427
+ )) != null ? _c : "default";
428
+ }, []);
832
429
  const onModelSelect = (0, import_react.useCallback)(async (model) => {
833
- var _a2, _b2, _c, _d, _e;
430
+ var _a2, _b2, _c, _d;
834
431
  const threadId = sessionIdRef.current;
835
432
  const currentControl = (_b2 = (_a2 = getThreadMetadataRef.current(threadId)) == null ? void 0 : _a2.control) != null ? _b2 : initThreadControl();
836
433
  const isProcessing2 = currentControl.isProcessing;
@@ -843,32 +440,35 @@ function ControlContextProvider({
843
440
  console.warn("[control-context] Cannot switch model while processing");
844
441
  return;
845
442
  }
846
- const namespace = (_d = (_c = currentControl.namespace) != null ? _c : stateRef.current.defaultNamespace) != null ? _d : "default";
443
+ const app = (_c = resolveAuthorizedApp(
444
+ currentControl.app,
445
+ stateRef.current.authorizedApps,
446
+ stateRef.current.defaultApp
447
+ )) != null ? _c : "default";
847
448
  console.log("[control-context] onModelSelect updating metadata", {
848
449
  threadId,
849
450
  model,
850
- namespace,
451
+ app,
851
452
  currentControl
852
453
  });
853
454
  updateThreadMetadataRef.current(threadId, {
854
455
  control: __spreadProps(__spreadValues({}, currentControl), {
855
456
  model,
856
- namespace,
457
+ app,
857
458
  controlDirty: true
858
459
  })
859
460
  });
860
461
  console.log("[control-context] onModelSelect calling backend setModel", {
861
462
  threadId,
862
463
  model,
863
- namespace,
864
- backendUrl: backendApiRef.current
464
+ app,
465
+ backendUrl: aomiClientRef.current
865
466
  });
866
467
  try {
867
- const result = await backendApiRef.current.setModel(
468
+ const result = await aomiClientRef.current.setModel(
868
469
  threadId,
869
470
  model,
870
- namespace,
871
- (_e = stateRef.current.apiKey) != null ? _e : void 0
471
+ { app, apiKey: (_d = stateRef.current.apiKey) != null ? _d : void 0 }
872
472
  );
873
473
  console.log("[control-context] onModelSelect backend result", result);
874
474
  } catch (err) {
@@ -876,34 +476,38 @@ function ControlContextProvider({
876
476
  throw err;
877
477
  }
878
478
  }, []);
879
- const onNamespaceSelect = (0, import_react.useCallback)((namespace) => {
479
+ const onAppSelect = (0, import_react.useCallback)((app) => {
880
480
  var _a2, _b2;
881
481
  const threadId = sessionIdRef.current;
882
482
  const currentControl = (_b2 = (_a2 = getThreadMetadataRef.current(threadId)) == null ? void 0 : _a2.control) != null ? _b2 : initThreadControl();
883
483
  const isProcessing2 = currentControl.isProcessing;
884
- console.log("[control-context] onNamespaceSelect called", {
885
- namespace,
484
+ console.log("[control-context] onAppSelect called", {
485
+ app,
886
486
  isProcessing: isProcessing2,
887
487
  threadId
888
488
  });
889
489
  if (isProcessing2) {
890
490
  console.warn(
891
- "[control-context] Cannot switch namespace while processing"
491
+ "[control-context] Cannot switch app while processing"
892
492
  );
893
493
  return;
894
494
  }
895
- console.log("[control-context] onNamespaceSelect updating metadata", {
495
+ if (stateRef.current.authorizedApps.length > 0 && !stateRef.current.authorizedApps.includes(app)) {
496
+ console.warn("[control-context] Cannot select unauthorized app", { app });
497
+ return;
498
+ }
499
+ console.log("[control-context] onAppSelect updating metadata", {
896
500
  threadId,
897
- namespace,
501
+ app,
898
502
  currentControl
899
503
  });
900
504
  updateThreadMetadataRef.current(threadId, {
901
505
  control: __spreadProps(__spreadValues({}, currentControl), {
902
- namespace,
506
+ app,
903
507
  controlDirty: true
904
508
  })
905
509
  });
906
- console.log("[control-context] onNamespaceSelect metadata updated");
510
+ console.log("[control-context] onAppSelect metadata updated");
907
511
  }, []);
908
512
  const markControlSynced = (0, import_react.useCallback)(() => {
909
513
  var _a2, _b2;
@@ -933,11 +537,11 @@ function ControlContextProvider({
933
537
  if ("apiKey" in updates) {
934
538
  setApiKey((_a2 = updates.apiKey) != null ? _a2 : null);
935
539
  }
936
- if ("namespace" in updates && updates.namespace !== void 0 && updates.namespace !== null) {
937
- onNamespaceSelect(updates.namespace);
540
+ if ("app" in updates && updates.app !== void 0 && updates.app !== null) {
541
+ onAppSelect(updates.app);
938
542
  }
939
543
  },
940
- [setApiKey, onNamespaceSelect]
544
+ [setApiKey, onAppSelect]
941
545
  );
942
546
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
943
547
  ControlContext.Provider,
@@ -946,10 +550,11 @@ function ControlContextProvider({
946
550
  state,
947
551
  setApiKey,
948
552
  getAvailableModels,
949
- getAuthorizedNamespaces,
553
+ getAuthorizedApps,
950
554
  getCurrentThreadControl,
555
+ getCurrentThreadApp,
951
556
  onModelSelect,
952
- onNamespaceSelect,
557
+ onAppSelect,
953
558
  isProcessing,
954
559
  markControlSynced,
955
560
  getControlState,
@@ -963,20 +568,7 @@ function ControlContextProvider({
963
568
 
964
569
  // packages/react/src/contexts/event-context.tsx
965
570
  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
- }
571
+ var import_client = require("@aomi-labs/client");
980
572
 
981
573
  // packages/react/src/state/event-buffer.ts
982
574
  function createEventBuffer() {
@@ -1036,7 +628,7 @@ function useEventContext() {
1036
628
  }
1037
629
  function EventContextProvider({
1038
630
  children,
1039
- backendApi,
631
+ aomiClient,
1040
632
  sessionId
1041
633
  }) {
1042
634
  const bufferRef = (0, import_react2.useRef)(null);
@@ -1048,7 +640,7 @@ function EventContextProvider({
1048
640
  (0, import_react2.useEffect)(() => {
1049
641
  setSSEStatus(buffer, "connecting");
1050
642
  setSseStatus("connecting");
1051
- const unsubscribe = backendApi.subscribeSSE(
643
+ const unsubscribe = aomiClient.subscribeSSE(
1052
644
  sessionId,
1053
645
  (event) => {
1054
646
  enqueueInbound(buffer, {
@@ -1078,7 +670,7 @@ function EventContextProvider({
1078
670
  setSSEStatus(buffer, "disconnected");
1079
671
  setSseStatus("disconnected");
1080
672
  };
1081
- }, [backendApi, sessionId, buffer]);
673
+ }, [aomiClient, sessionId, buffer]);
1082
674
  const subscribeCallback = (0, import_react2.useCallback)(
1083
675
  (type, callback) => {
1084
676
  return subscribe(buffer, type, callback);
@@ -1092,12 +684,12 @@ function EventContextProvider({
1092
684
  type: event.type,
1093
685
  payload: event.payload
1094
686
  });
1095
- await backendApi.postSystemMessage(event.sessionId, message);
687
+ await aomiClient.sendSystemMessage(event.sessionId, message);
1096
688
  } catch (error) {
1097
689
  console.error("Failed to send outbound event:", error);
1098
690
  }
1099
691
  },
1100
- [backendApi]
692
+ [aomiClient]
1101
693
  );
1102
694
  const dispatchSystemEvents = (0, import_react2.useCallback)(
1103
695
  (sessionId2, events) => {
@@ -1105,16 +697,16 @@ function EventContextProvider({
1105
697
  for (const event of events) {
1106
698
  let eventType;
1107
699
  let payload;
1108
- if (isInlineCall(event)) {
700
+ if ((0, import_client.isInlineCall)(event)) {
1109
701
  eventType = event.InlineCall.type;
1110
702
  payload = (_a = event.InlineCall.payload) != null ? _a : event.InlineCall;
1111
- } else if (isSystemNotice(event)) {
703
+ } else if ((0, import_client.isSystemNotice)(event)) {
1112
704
  eventType = "system_notice";
1113
705
  payload = { message: event.SystemNotice };
1114
- } else if (isSystemError(event)) {
706
+ } else if ((0, import_client.isSystemError)(event)) {
1115
707
  eventType = "system_error";
1116
708
  payload = { message: event.SystemError };
1117
- } else if (isAsyncCallback(event)) {
709
+ } else if ((0, import_client.isAsyncCallback)(event)) {
1118
710
  eventType = "async_callback";
1119
711
  payload = event.AsyncCallback;
1120
712
  } else {
@@ -1463,19 +1055,16 @@ var MessageController = class {
1463
1055
  lastActiveAt: (/* @__PURE__ */ new Date()).toISOString()
1464
1056
  });
1465
1057
  const backendThreadId = resolveThreadId(backendState, threadId);
1466
- const namespace = this.config.getNamespace();
1058
+ const app = this.config.getApp();
1467
1059
  const publicKey = (_b = (_a = this.config).getPublicKey) == null ? void 0 : _b.call(_a);
1468
1060
  const apiKey = (_e = (_d = (_c = this.config).getApiKey) == null ? void 0 : _d.call(_c)) != null ? _e : void 0;
1469
1061
  const userState = (_g = (_f = this.config).getUserState) == null ? void 0 : _g.call(_f);
1470
1062
  try {
1471
1063
  this.markRunning(threadId, true);
1472
- const response = await this.config.backendApiRef.current.postChatMessage(
1064
+ const response = await this.config.aomiClientRef.current.sendMessage(
1473
1065
  backendThreadId,
1474
1066
  text,
1475
- namespace,
1476
- publicKey,
1477
- apiKey,
1478
- userState
1067
+ { app, publicKey, apiKey, userState }
1479
1068
  );
1480
1069
  if (response == null ? void 0 : response.messages) {
1481
1070
  this.inbound(threadId, response.messages);
@@ -1499,7 +1088,7 @@ var MessageController = class {
1499
1088
  const backendState = this.config.backendStateRef.current;
1500
1089
  const backendThreadId = resolveThreadId(backendState, threadId);
1501
1090
  try {
1502
- const response = await this.config.backendApiRef.current.postInterrupt(backendThreadId);
1091
+ const response = await this.config.aomiClientRef.current.interrupt(backendThreadId);
1503
1092
  if (response == null ? void 0 : response.messages) {
1504
1093
  this.inbound(threadId, response.messages);
1505
1094
  }
@@ -1547,7 +1136,7 @@ var PollingController = class {
1547
1136
  threadId
1548
1137
  );
1549
1138
  const userState = (_b2 = (_a2 = this.config).getUserState) == null ? void 0 : _b2.call(_a2);
1550
- const state = await this.config.backendApiRef.current.fetchState(
1139
+ const state = await this.config.aomiClientRef.current.fetchState(
1551
1140
  backendThreadId,
1552
1141
  userState
1553
1142
  );
@@ -1595,12 +1184,12 @@ var PollingController = class {
1595
1184
  };
1596
1185
 
1597
1186
  // packages/react/src/runtime/orchestrator.ts
1598
- function useRuntimeOrchestrator(backendApi, options) {
1187
+ function useRuntimeOrchestrator(aomiClient, options) {
1599
1188
  const threadContext = useThreadContext();
1600
1189
  const threadContextRef = (0, import_react6.useRef)(threadContext);
1601
1190
  threadContextRef.current = threadContext;
1602
- const backendApiRef = (0, import_react6.useRef)(backendApi);
1603
- backendApiRef.current = backendApi;
1191
+ const aomiClientRef = (0, import_react6.useRef)(aomiClient);
1192
+ aomiClientRef.current = aomiClient;
1604
1193
  const backendStateRef = (0, import_react6.useRef)(createBackendState());
1605
1194
  const [isRunning, setIsRunning] = (0, import_react6.useState)(false);
1606
1195
  const messageControllerRef = (0, import_react6.useRef)(null);
@@ -1608,7 +1197,7 @@ function useRuntimeOrchestrator(backendApi, options) {
1608
1197
  const pendingFetches = (0, import_react6.useRef)(/* @__PURE__ */ new Set());
1609
1198
  if (!pollingRef.current) {
1610
1199
  pollingRef.current = new PollingController({
1611
- backendApiRef,
1200
+ aomiClientRef,
1612
1201
  backendStateRef,
1613
1202
  applyMessages: (threadId, msgs) => {
1614
1203
  var _a;
@@ -1630,13 +1219,13 @@ function useRuntimeOrchestrator(backendApi, options) {
1630
1219
  }
1631
1220
  if (!messageControllerRef.current) {
1632
1221
  messageControllerRef.current = new MessageController({
1633
- backendApiRef,
1222
+ aomiClientRef,
1634
1223
  backendStateRef,
1635
1224
  threadContextRef,
1636
1225
  polling: pollingRef.current,
1637
1226
  setGlobalIsRunning: setIsRunning,
1638
1227
  getPublicKey: options.getPublicKey,
1639
- getNamespace: options.getNamespace,
1228
+ getApp: options.getApp,
1640
1229
  getApiKey: options.getApiKey,
1641
1230
  getUserState: options.getUserState,
1642
1231
  onSyncEvents: options.onSyncEvents
@@ -1649,7 +1238,7 @@ function useRuntimeOrchestrator(backendApi, options) {
1649
1238
  pendingFetches.current.add(threadId);
1650
1239
  try {
1651
1240
  const userState = (_a = options.getUserState) == null ? void 0 : _a.call(options);
1652
- const state = await backendApiRef.current.fetchState(
1241
+ const state = await aomiClientRef.current.fetchState(
1653
1242
  backendThreadId,
1654
1243
  userState
1655
1244
  );
@@ -1681,7 +1270,7 @@ function useRuntimeOrchestrator(backendApi, options) {
1681
1270
  isRunning,
1682
1271
  setIsRunning,
1683
1272
  ensureInitialState,
1684
- backendApiRef
1273
+ aomiClientRef
1685
1274
  };
1686
1275
  }
1687
1276
 
@@ -1712,7 +1301,7 @@ function buildThreadLists(threadMetadata) {
1712
1301
  return { regularThreads, archivedThreads };
1713
1302
  }
1714
1303
  function buildThreadListAdapter({
1715
- backendApiRef,
1304
+ aomiClientRef,
1716
1305
  threadContext,
1717
1306
  setIsRunning
1718
1307
  }) {
@@ -1740,6 +1329,7 @@ function buildThreadListAdapter({
1740
1329
  },
1741
1330
  onSwitchToThread: (threadId) => {
1742
1331
  threadContext.setCurrentThreadId(threadId);
1332
+ threadContext.bumpThreadViewKey();
1743
1333
  },
1744
1334
  onRename: async (threadId, newTitle) => {
1745
1335
  var _a, _b;
@@ -1749,7 +1339,7 @@ function buildThreadListAdapter({
1749
1339
  title: normalizedTitle
1750
1340
  });
1751
1341
  try {
1752
- await backendApiRef.current.renameThread(threadId, newTitle);
1342
+ await aomiClientRef.current.renameThread(threadId, newTitle);
1753
1343
  } catch (error) {
1754
1344
  console.error("Failed to rename thread:", error);
1755
1345
  threadContext.updateThreadMetadata(threadId, {
@@ -1760,7 +1350,7 @@ function buildThreadListAdapter({
1760
1350
  onArchive: async (threadId) => {
1761
1351
  threadContext.updateThreadMetadata(threadId, { status: "archived" });
1762
1352
  try {
1763
- await backendApiRef.current.archiveThread(threadId);
1353
+ await aomiClientRef.current.archiveThread(threadId);
1764
1354
  } catch (error) {
1765
1355
  console.error("Failed to archive thread:", error);
1766
1356
  threadContext.updateThreadMetadata(threadId, { status: "regular" });
@@ -1769,7 +1359,7 @@ function buildThreadListAdapter({
1769
1359
  onUnarchive: async (threadId) => {
1770
1360
  threadContext.updateThreadMetadata(threadId, { status: "regular" });
1771
1361
  try {
1772
- await backendApiRef.current.unarchiveThread(threadId);
1362
+ await aomiClientRef.current.unarchiveThread(threadId);
1773
1363
  } catch (error) {
1774
1364
  console.error("Failed to unarchive thread:", error);
1775
1365
  threadContext.updateThreadMetadata(threadId, { status: "archived" });
@@ -1777,7 +1367,7 @@ function buildThreadListAdapter({
1777
1367
  },
1778
1368
  onDelete: async (threadId) => {
1779
1369
  try {
1780
- await backendApiRef.current.deleteThread(threadId);
1370
+ await aomiClientRef.current.deleteThread(threadId);
1781
1371
  threadContext.setThreadMetadata((prev) => {
1782
1372
  const next = new Map(prev);
1783
1373
  next.delete(threadId);
@@ -1832,6 +1422,7 @@ function useAomiRuntime() {
1832
1422
 
1833
1423
  // packages/react/src/handlers/wallet-handler.ts
1834
1424
  var import_react8 = require("react");
1425
+ var import_client2 = require("@aomi-labs/client");
1835
1426
 
1836
1427
  // packages/react/src/state/wallet-buffer.ts
1837
1428
  function createWalletBuffer() {
@@ -1878,7 +1469,11 @@ function useWalletHandler({
1878
1469
  const unsubscribe = subscribe2(
1879
1470
  "wallet_tx_request",
1880
1471
  (event) => {
1881
- const payload = event.payload;
1472
+ const payload = (0, import_client2.normalizeTxPayload)(event.payload);
1473
+ if (!payload) {
1474
+ console.warn("[aomi][wallet] Ignoring tx request with invalid payload", event.payload);
1475
+ return;
1476
+ }
1882
1477
  enqueue(bufferRef.current, "transaction", payload);
1883
1478
  syncState();
1884
1479
  }
@@ -1890,7 +1485,7 @@ function useWalletHandler({
1890
1485
  "wallet_eip712_request",
1891
1486
  (event) => {
1892
1487
  var _a;
1893
- const payload = (_a = event.payload) != null ? _a : {};
1488
+ const payload = (0, import_client2.normalizeEip712Payload)((_a = event.payload) != null ? _a : {});
1894
1489
  enqueue(bufferRef.current, "eip712_sign", payload);
1895
1490
  syncState();
1896
1491
  }
@@ -1980,14 +1575,14 @@ function useWalletHandler({
1980
1575
  var import_jsx_runtime6 = require("react/jsx-runtime");
1981
1576
  function AomiRuntimeCore({
1982
1577
  children,
1983
- backendApi
1578
+ aomiClient
1984
1579
  }) {
1985
1580
  const threadContext = useThreadContext();
1986
1581
  const eventContext = useEventContext();
1987
1582
  const notificationContext = useNotification();
1988
1583
  const { dispatchInboundSystem: dispatchSystemEvents } = eventContext;
1989
1584
  const { user, onUserStateChange, getUserState } = useUser();
1990
- const { getControlState, getCurrentThreadControl } = useControl();
1585
+ const { getControlState, getCurrentThreadApp } = useControl();
1991
1586
  const {
1992
1587
  backendStateRef,
1993
1588
  polling,
@@ -1995,15 +1590,12 @@ function AomiRuntimeCore({
1995
1590
  isRunning,
1996
1591
  setIsRunning,
1997
1592
  ensureInitialState,
1998
- backendApiRef
1999
- } = useRuntimeOrchestrator(backendApi, {
1593
+ aomiClientRef
1594
+ } = useRuntimeOrchestrator(aomiClient, {
2000
1595
  onSyncEvents: dispatchSystemEvents,
2001
1596
  getPublicKey: () => getUserState().address,
2002
1597
  getUserState,
2003
- getNamespace: () => {
2004
- var _a, _b;
2005
- return (_b = (_a = getCurrentThreadControl().namespace) != null ? _a : getControlState().defaultNamespace) != null ? _b : "default";
2006
- },
1598
+ getApp: getCurrentThreadApp,
2007
1599
  getApiKey: () => getControlState().apiKey
2008
1600
  });
2009
1601
  (0, import_react9.useEffect)(() => {
@@ -2018,10 +1610,10 @@ function AomiRuntimeCore({
2018
1610
  ensName: newUser.ensName
2019
1611
  }
2020
1612
  });
2021
- await backendApiRef.current.postSystemMessage(sessionId, message);
1613
+ await aomiClientRef.current.sendSystemMessage(sessionId, message);
2022
1614
  });
2023
1615
  return unsubscribe;
2024
- }, [onUserStateChange, backendApiRef, threadContext.currentThreadId]);
1616
+ }, [onUserStateChange, aomiClientRef, threadContext.currentThreadId]);
2025
1617
  const threadContextRef = (0, import_react9.useRef)(threadContext);
2026
1618
  threadContextRef.current = threadContext;
2027
1619
  const currentThreadIdRef = (0, import_react9.useRef)(threadContext.currentThreadId);
@@ -2069,21 +1661,13 @@ function AomiRuntimeCore({
2069
1661
  const currentMessages = threadContext.getThreadMessages(
2070
1662
  threadContext.currentThreadId
2071
1663
  );
2072
- const resolvedSessionId = (0, import_react9.useMemo)(
2073
- () => resolveThreadId(backendStateRef.current, threadContext.currentThreadId),
2074
- [
2075
- backendStateRef,
2076
- threadContext.currentThreadId,
2077
- threadContext.allThreadsMetadata
2078
- ]
2079
- );
2080
1664
  (0, import_react9.useEffect)(() => {
2081
1665
  const userAddress = user.address;
2082
1666
  if (!userAddress) return;
2083
1667
  const fetchThreadList = async () => {
2084
1668
  var _a, _b, _c;
2085
1669
  try {
2086
- const threadList = await backendApiRef.current.fetchThreads(userAddress);
1670
+ const threadList = await aomiClientRef.current.listThreads(userAddress);
2087
1671
  const currentContext = threadContextRef.current;
2088
1672
  const newMetadata = new Map(currentContext.allThreadsMetadata);
2089
1673
  let maxChatNum = currentContext.threadCnt;
@@ -2115,25 +1699,22 @@ function AomiRuntimeCore({
2115
1699
  }
2116
1700
  };
2117
1701
  void fetchThreadList();
2118
- }, [user.address, backendApiRef]);
1702
+ }, [user.address, aomiClientRef]);
2119
1703
  const threadListAdapter = (0, import_react9.useMemo)(
2120
1704
  () => buildThreadListAdapter({
2121
1705
  backendStateRef,
2122
- backendApiRef,
1706
+ aomiClientRef,
2123
1707
  threadContext,
2124
1708
  currentThreadIdRef,
2125
1709
  polling,
2126
1710
  userAddress: user.address,
2127
1711
  setIsRunning,
2128
- getNamespace: () => {
2129
- var _a, _b;
2130
- return (_b = (_a = getCurrentThreadControl().namespace) != null ? _a : getControlState().defaultNamespace) != null ? _b : "default";
2131
- },
1712
+ getApp: getCurrentThreadApp,
2132
1713
  getApiKey: () => getControlState().apiKey,
2133
1714
  getUserState
2134
1715
  }),
2135
1716
  [
2136
- backendApiRef,
1717
+ aomiClientRef,
2137
1718
  polling,
2138
1719
  user.address,
2139
1720
  backendStateRef,
@@ -2142,63 +1723,44 @@ function AomiRuntimeCore({
2142
1723
  threadContext.currentThreadId,
2143
1724
  threadContext.allThreadsMetadata,
2144
1725
  getControlState,
1726
+ getCurrentThreadApp,
2145
1727
  getUserState
2146
1728
  ]
2147
1729
  );
2148
1730
  (0, import_react9.useEffect)(() => {
2149
1731
  const backendState = backendStateRef.current;
2150
- const currentSessionId = threadContext.currentThreadId;
2151
- if (process.env.NODE_ENV !== "production") {
2152
- console.debug("[aomi][sse] subscribe", {
2153
- currentSessionId,
2154
- resolvedSessionId,
2155
- hasMapping: currentSessionId !== resolvedSessionId
2156
- });
2157
- }
2158
- const unsubscribe = backendApiRef.current.subscribeSSE(
2159
- resolvedSessionId,
2160
- (event) => {
2161
- const eventType = event.type;
2162
- const sessionId = event.session_id;
2163
- if (eventType === "title_changed") {
2164
- const newTitle = event.new_title;
2165
- const targetThreadId = resolveThreadId(backendState, sessionId);
2166
- const normalizedTitle = isPlaceholderTitle(newTitle) ? "" : newTitle;
2167
- if (process.env.NODE_ENV !== "production") {
2168
- console.debug("[aomi][sse] title_changed", {
2169
- sessionId,
2170
- newTitle,
2171
- normalizedTitle,
2172
- currentThreadId: threadContextRef.current.currentThreadId,
2173
- targetThreadId,
2174
- hasMapping: sessionId !== targetThreadId
2175
- });
2176
- }
2177
- threadContextRef.current.setThreadMetadata((prev) => {
2178
- var _a, _b;
2179
- const next = new Map(prev);
2180
- const existing = next.get(targetThreadId);
2181
- const nextStatus = (existing == null ? void 0 : existing.status) === "archived" ? "archived" : "regular";
2182
- next.set(targetThreadId, {
2183
- title: normalizedTitle,
2184
- status: nextStatus,
2185
- lastActiveAt: (_a = existing == null ? void 0 : existing.lastActiveAt) != null ? _a : (/* @__PURE__ */ new Date()).toISOString(),
2186
- control: (_b = existing == null ? void 0 : existing.control) != null ? _b : initThreadControl()
2187
- });
2188
- return next;
2189
- });
2190
- }
1732
+ const unsubscribe = eventContext.subscribe("title_changed", (event) => {
1733
+ const sessionId = event.sessionId;
1734
+ const payload = event.payload;
1735
+ const newTitle = payload == null ? void 0 : payload.new_title;
1736
+ if (typeof newTitle !== "string") return;
1737
+ const targetThreadId = resolveThreadId(backendState, sessionId);
1738
+ const normalizedTitle = isPlaceholderTitle(newTitle) ? "" : newTitle;
1739
+ if (process.env.NODE_ENV !== "production") {
1740
+ console.debug("[aomi][sse] title_changed", {
1741
+ sessionId,
1742
+ newTitle,
1743
+ normalizedTitle,
1744
+ currentThreadId: threadContextRef.current.currentThreadId,
1745
+ targetThreadId
1746
+ });
2191
1747
  }
2192
- );
2193
- return () => {
2194
- unsubscribe == null ? void 0 : unsubscribe();
2195
- };
2196
- }, [
2197
- backendApiRef,
2198
- backendStateRef,
2199
- threadContext.currentThreadId,
2200
- resolvedSessionId
2201
- ]);
1748
+ threadContextRef.current.setThreadMetadata((prev) => {
1749
+ var _a, _b;
1750
+ const next = new Map(prev);
1751
+ const existing = next.get(targetThreadId);
1752
+ const nextStatus = (existing == null ? void 0 : existing.status) === "archived" ? "archived" : "regular";
1753
+ next.set(targetThreadId, {
1754
+ title: normalizedTitle,
1755
+ status: nextStatus,
1756
+ lastActiveAt: (_a = existing == null ? void 0 : existing.lastActiveAt) != null ? _a : (/* @__PURE__ */ new Date()).toISOString(),
1757
+ control: (_b = existing == null ? void 0 : existing.control) != null ? _b : initThreadControl()
1758
+ });
1759
+ return next;
1760
+ });
1761
+ });
1762
+ return unsubscribe;
1763
+ }, [eventContext, backendStateRef]);
2202
1764
  (0, import_react9.useEffect)(() => {
2203
1765
  const showToolNotification = (eventType) => (event) => {
2204
1766
  const payload = event.payload;
@@ -2367,12 +1929,12 @@ function AomiRuntimeProvider({
2367
1929
  children,
2368
1930
  backendUrl = "http://localhost:8080"
2369
1931
  }) {
2370
- const backendApi = (0, import_react11.useMemo)(() => new BackendApi(backendUrl), [backendUrl]);
2371
- 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 }) }) }) });
1932
+ const aomiClient = (0, import_react11.useMemo)(() => new import_client3.AomiClient({ baseUrl: backendUrl }), [backendUrl]);
1933
+ 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 }) }) }) });
2372
1934
  }
2373
1935
  function AomiRuntimeInner({
2374
1936
  children,
2375
- backendApi
1937
+ aomiClient
2376
1938
  }) {
2377
1939
  var _a;
2378
1940
  const threadContext = useThreadContext();
@@ -2380,7 +1942,7 @@ function AomiRuntimeInner({
2380
1942
  return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
2381
1943
  ControlContextProvider,
2382
1944
  {
2383
- backendApi,
1945
+ aomiClient,
2384
1946
  sessionId: threadContext.currentThreadId,
2385
1947
  publicKey: (_a = user.address) != null ? _a : void 0,
2386
1948
  getThreadMetadata: threadContext.getThreadMetadata,
@@ -2388,9 +1950,9 @@ function AomiRuntimeInner({
2388
1950
  children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
2389
1951
  EventContextProvider,
2390
1952
  {
2391
- backendApi,
1953
+ aomiClient,
2392
1954
  sessionId: threadContext.currentThreadId,
2393
- children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(AomiRuntimeCore, { backendApi, children })
1955
+ children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(AomiRuntimeCore, { aomiClient, children })
2394
1956
  }
2395
1957
  )
2396
1958
  }
@@ -2440,8 +2002,8 @@ function useNotificationHandler({
2440
2002
  }
2441
2003
  // Annotate the CommonJS export names for ESM import in node:
2442
2004
  0 && (module.exports = {
2005
+ AomiClient,
2443
2006
  AomiRuntimeProvider,
2444
- BackendApi,
2445
2007
  ControlContextProvider,
2446
2008
  EventContextProvider,
2447
2009
  NotificationContextProvider,
@@ -2453,6 +2015,7 @@ function useNotificationHandler({
2453
2015
  getChainInfo,
2454
2016
  getNetworkName,
2455
2017
  initThreadControl,
2018
+ toViemSignTypedDataArgs,
2456
2019
  useAomiRuntime,
2457
2020
  useControl,
2458
2021
  useCurrentThreadMessages,