@aomi-labs/react 0.3.0 → 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
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
  };
@@ -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 {
@@ -1463,19 +1019,16 @@ var MessageController = class {
1463
1019
  lastActiveAt: (/* @__PURE__ */ new Date()).toISOString()
1464
1020
  });
1465
1021
  const backendThreadId = resolveThreadId(backendState, threadId);
1466
- const namespace = this.config.getNamespace();
1022
+ const app = this.config.getApp();
1467
1023
  const publicKey = (_b = (_a = this.config).getPublicKey) == null ? void 0 : _b.call(_a);
1468
1024
  const apiKey = (_e = (_d = (_c = this.config).getApiKey) == null ? void 0 : _d.call(_c)) != null ? _e : void 0;
1469
1025
  const userState = (_g = (_f = this.config).getUserState) == null ? void 0 : _g.call(_f);
1470
1026
  try {
1471
1027
  this.markRunning(threadId, true);
1472
- const response = await this.config.backendApiRef.current.postChatMessage(
1028
+ const response = await this.config.aomiClientRef.current.sendMessage(
1473
1029
  backendThreadId,
1474
1030
  text,
1475
- namespace,
1476
- publicKey,
1477
- apiKey,
1478
- userState
1031
+ { app, publicKey, apiKey, userState }
1479
1032
  );
1480
1033
  if (response == null ? void 0 : response.messages) {
1481
1034
  this.inbound(threadId, response.messages);
@@ -1499,7 +1052,7 @@ var MessageController = class {
1499
1052
  const backendState = this.config.backendStateRef.current;
1500
1053
  const backendThreadId = resolveThreadId(backendState, threadId);
1501
1054
  try {
1502
- const response = await this.config.backendApiRef.current.postInterrupt(backendThreadId);
1055
+ const response = await this.config.aomiClientRef.current.interrupt(backendThreadId);
1503
1056
  if (response == null ? void 0 : response.messages) {
1504
1057
  this.inbound(threadId, response.messages);
1505
1058
  }
@@ -1547,7 +1100,7 @@ var PollingController = class {
1547
1100
  threadId
1548
1101
  );
1549
1102
  const userState = (_b2 = (_a2 = this.config).getUserState) == null ? void 0 : _b2.call(_a2);
1550
- const state = await this.config.backendApiRef.current.fetchState(
1103
+ const state = await this.config.aomiClientRef.current.fetchState(
1551
1104
  backendThreadId,
1552
1105
  userState
1553
1106
  );
@@ -1595,12 +1148,12 @@ var PollingController = class {
1595
1148
  };
1596
1149
 
1597
1150
  // packages/react/src/runtime/orchestrator.ts
1598
- function useRuntimeOrchestrator(backendApi, options) {
1151
+ function useRuntimeOrchestrator(aomiClient, options) {
1599
1152
  const threadContext = useThreadContext();
1600
1153
  const threadContextRef = (0, import_react6.useRef)(threadContext);
1601
1154
  threadContextRef.current = threadContext;
1602
- const backendApiRef = (0, import_react6.useRef)(backendApi);
1603
- backendApiRef.current = backendApi;
1155
+ const aomiClientRef = (0, import_react6.useRef)(aomiClient);
1156
+ aomiClientRef.current = aomiClient;
1604
1157
  const backendStateRef = (0, import_react6.useRef)(createBackendState());
1605
1158
  const [isRunning, setIsRunning] = (0, import_react6.useState)(false);
1606
1159
  const messageControllerRef = (0, import_react6.useRef)(null);
@@ -1608,7 +1161,7 @@ function useRuntimeOrchestrator(backendApi, options) {
1608
1161
  const pendingFetches = (0, import_react6.useRef)(/* @__PURE__ */ new Set());
1609
1162
  if (!pollingRef.current) {
1610
1163
  pollingRef.current = new PollingController({
1611
- backendApiRef,
1164
+ aomiClientRef,
1612
1165
  backendStateRef,
1613
1166
  applyMessages: (threadId, msgs) => {
1614
1167
  var _a;
@@ -1630,13 +1183,13 @@ function useRuntimeOrchestrator(backendApi, options) {
1630
1183
  }
1631
1184
  if (!messageControllerRef.current) {
1632
1185
  messageControllerRef.current = new MessageController({
1633
- backendApiRef,
1186
+ aomiClientRef,
1634
1187
  backendStateRef,
1635
1188
  threadContextRef,
1636
1189
  polling: pollingRef.current,
1637
1190
  setGlobalIsRunning: setIsRunning,
1638
1191
  getPublicKey: options.getPublicKey,
1639
- getNamespace: options.getNamespace,
1192
+ getApp: options.getApp,
1640
1193
  getApiKey: options.getApiKey,
1641
1194
  getUserState: options.getUserState,
1642
1195
  onSyncEvents: options.onSyncEvents
@@ -1649,7 +1202,7 @@ function useRuntimeOrchestrator(backendApi, options) {
1649
1202
  pendingFetches.current.add(threadId);
1650
1203
  try {
1651
1204
  const userState = (_a = options.getUserState) == null ? void 0 : _a.call(options);
1652
- const state = await backendApiRef.current.fetchState(
1205
+ const state = await aomiClientRef.current.fetchState(
1653
1206
  backendThreadId,
1654
1207
  userState
1655
1208
  );
@@ -1681,7 +1234,7 @@ function useRuntimeOrchestrator(backendApi, options) {
1681
1234
  isRunning,
1682
1235
  setIsRunning,
1683
1236
  ensureInitialState,
1684
- backendApiRef
1237
+ aomiClientRef
1685
1238
  };
1686
1239
  }
1687
1240
 
@@ -1712,7 +1265,7 @@ function buildThreadLists(threadMetadata) {
1712
1265
  return { regularThreads, archivedThreads };
1713
1266
  }
1714
1267
  function buildThreadListAdapter({
1715
- backendApiRef,
1268
+ aomiClientRef,
1716
1269
  threadContext,
1717
1270
  setIsRunning
1718
1271
  }) {
@@ -1740,6 +1293,7 @@ function buildThreadListAdapter({
1740
1293
  },
1741
1294
  onSwitchToThread: (threadId) => {
1742
1295
  threadContext.setCurrentThreadId(threadId);
1296
+ threadContext.bumpThreadViewKey();
1743
1297
  },
1744
1298
  onRename: async (threadId, newTitle) => {
1745
1299
  var _a, _b;
@@ -1749,7 +1303,7 @@ function buildThreadListAdapter({
1749
1303
  title: normalizedTitle
1750
1304
  });
1751
1305
  try {
1752
- await backendApiRef.current.renameThread(threadId, newTitle);
1306
+ await aomiClientRef.current.renameThread(threadId, newTitle);
1753
1307
  } catch (error) {
1754
1308
  console.error("Failed to rename thread:", error);
1755
1309
  threadContext.updateThreadMetadata(threadId, {
@@ -1760,7 +1314,7 @@ function buildThreadListAdapter({
1760
1314
  onArchive: async (threadId) => {
1761
1315
  threadContext.updateThreadMetadata(threadId, { status: "archived" });
1762
1316
  try {
1763
- await backendApiRef.current.archiveThread(threadId);
1317
+ await aomiClientRef.current.archiveThread(threadId);
1764
1318
  } catch (error) {
1765
1319
  console.error("Failed to archive thread:", error);
1766
1320
  threadContext.updateThreadMetadata(threadId, { status: "regular" });
@@ -1769,7 +1323,7 @@ function buildThreadListAdapter({
1769
1323
  onUnarchive: async (threadId) => {
1770
1324
  threadContext.updateThreadMetadata(threadId, { status: "regular" });
1771
1325
  try {
1772
- await backendApiRef.current.unarchiveThread(threadId);
1326
+ await aomiClientRef.current.unarchiveThread(threadId);
1773
1327
  } catch (error) {
1774
1328
  console.error("Failed to unarchive thread:", error);
1775
1329
  threadContext.updateThreadMetadata(threadId, { status: "archived" });
@@ -1777,7 +1331,7 @@ function buildThreadListAdapter({
1777
1331
  },
1778
1332
  onDelete: async (threadId) => {
1779
1333
  try {
1780
- await backendApiRef.current.deleteThread(threadId);
1334
+ await aomiClientRef.current.deleteThread(threadId);
1781
1335
  threadContext.setThreadMetadata((prev) => {
1782
1336
  const next = new Map(prev);
1783
1337
  next.delete(threadId);
@@ -1864,6 +1418,68 @@ function getAll(buffer) {
1864
1418
  }
1865
1419
 
1866
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
+ }
1867
1483
  function useWalletHandler({
1868
1484
  sessionId,
1869
1485
  onRequestComplete
@@ -1878,7 +1494,11 @@ function useWalletHandler({
1878
1494
  const unsubscribe = subscribe2(
1879
1495
  "wallet_tx_request",
1880
1496
  (event) => {
1881
- const payload = event.payload;
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
+ }
1882
1502
  enqueue(bufferRef.current, "transaction", payload);
1883
1503
  syncState();
1884
1504
  }
@@ -1890,7 +1510,7 @@ function useWalletHandler({
1890
1510
  "wallet_eip712_request",
1891
1511
  (event) => {
1892
1512
  var _a;
1893
- const payload = (_a = event.payload) != null ? _a : {};
1513
+ const payload = normalizeEip712Payload((_a = event.payload) != null ? _a : {});
1894
1514
  enqueue(bufferRef.current, "eip712_sign", payload);
1895
1515
  syncState();
1896
1516
  }
@@ -1980,7 +1600,7 @@ function useWalletHandler({
1980
1600
  var import_jsx_runtime6 = require("react/jsx-runtime");
1981
1601
  function AomiRuntimeCore({
1982
1602
  children,
1983
- backendApi
1603
+ aomiClient
1984
1604
  }) {
1985
1605
  const threadContext = useThreadContext();
1986
1606
  const eventContext = useEventContext();
@@ -1995,14 +1615,14 @@ function AomiRuntimeCore({
1995
1615
  isRunning,
1996
1616
  setIsRunning,
1997
1617
  ensureInitialState,
1998
- backendApiRef
1999
- } = useRuntimeOrchestrator(backendApi, {
1618
+ aomiClientRef
1619
+ } = useRuntimeOrchestrator(aomiClient, {
2000
1620
  onSyncEvents: dispatchSystemEvents,
2001
1621
  getPublicKey: () => getUserState().address,
2002
1622
  getUserState,
2003
- getNamespace: () => {
1623
+ getApp: () => {
2004
1624
  var _a, _b;
2005
- 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";
2006
1626
  },
2007
1627
  getApiKey: () => getControlState().apiKey
2008
1628
  });
@@ -2018,10 +1638,10 @@ function AomiRuntimeCore({
2018
1638
  ensName: newUser.ensName
2019
1639
  }
2020
1640
  });
2021
- await backendApiRef.current.postSystemMessage(sessionId, message);
1641
+ await aomiClientRef.current.sendSystemMessage(sessionId, message);
2022
1642
  });
2023
1643
  return unsubscribe;
2024
- }, [onUserStateChange, backendApiRef, threadContext.currentThreadId]);
1644
+ }, [onUserStateChange, aomiClientRef, threadContext.currentThreadId]);
2025
1645
  const threadContextRef = (0, import_react9.useRef)(threadContext);
2026
1646
  threadContextRef.current = threadContext;
2027
1647
  const currentThreadIdRef = (0, import_react9.useRef)(threadContext.currentThreadId);
@@ -2069,21 +1689,13 @@ function AomiRuntimeCore({
2069
1689
  const currentMessages = threadContext.getThreadMessages(
2070
1690
  threadContext.currentThreadId
2071
1691
  );
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
1692
  (0, import_react9.useEffect)(() => {
2081
1693
  const userAddress = user.address;
2082
1694
  if (!userAddress) return;
2083
1695
  const fetchThreadList = async () => {
2084
1696
  var _a, _b, _c;
2085
1697
  try {
2086
- const threadList = await backendApiRef.current.fetchThreads(userAddress);
1698
+ const threadList = await aomiClientRef.current.listThreads(userAddress);
2087
1699
  const currentContext = threadContextRef.current;
2088
1700
  const newMetadata = new Map(currentContext.allThreadsMetadata);
2089
1701
  let maxChatNum = currentContext.threadCnt;
@@ -2115,25 +1727,25 @@ function AomiRuntimeCore({
2115
1727
  }
2116
1728
  };
2117
1729
  void fetchThreadList();
2118
- }, [user.address, backendApiRef]);
1730
+ }, [user.address, aomiClientRef]);
2119
1731
  const threadListAdapter = (0, import_react9.useMemo)(
2120
1732
  () => buildThreadListAdapter({
2121
1733
  backendStateRef,
2122
- backendApiRef,
1734
+ aomiClientRef,
2123
1735
  threadContext,
2124
1736
  currentThreadIdRef,
2125
1737
  polling,
2126
1738
  userAddress: user.address,
2127
1739
  setIsRunning,
2128
- getNamespace: () => {
1740
+ getApp: () => {
2129
1741
  var _a, _b;
2130
- 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";
2131
1743
  },
2132
1744
  getApiKey: () => getControlState().apiKey,
2133
1745
  getUserState
2134
1746
  }),
2135
1747
  [
2136
- backendApiRef,
1748
+ aomiClientRef,
2137
1749
  polling,
2138
1750
  user.address,
2139
1751
  backendStateRef,
@@ -2147,58 +1759,38 @@ function AomiRuntimeCore({
2147
1759
  );
2148
1760
  (0, import_react9.useEffect)(() => {
2149
1761
  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
- }
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
+ });
2191
1777
  }
2192
- );
2193
- return () => {
2194
- unsubscribe == null ? void 0 : unsubscribe();
2195
- };
2196
- }, [
2197
- backendApiRef,
2198
- backendStateRef,
2199
- threadContext.currentThreadId,
2200
- resolvedSessionId
2201
- ]);
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]);
2202
1794
  (0, import_react9.useEffect)(() => {
2203
1795
  const showToolNotification = (eventType) => (event) => {
2204
1796
  const payload = event.payload;
@@ -2367,12 +1959,12 @@ function AomiRuntimeProvider({
2367
1959
  children,
2368
1960
  backendUrl = "http://localhost:8080"
2369
1961
  }) {
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 }) }) }) });
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 }) }) }) });
2372
1964
  }
2373
1965
  function AomiRuntimeInner({
2374
1966
  children,
2375
- backendApi
1967
+ aomiClient
2376
1968
  }) {
2377
1969
  var _a;
2378
1970
  const threadContext = useThreadContext();
@@ -2380,7 +1972,7 @@ function AomiRuntimeInner({
2380
1972
  return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
2381
1973
  ControlContextProvider,
2382
1974
  {
2383
- backendApi,
1975
+ aomiClient,
2384
1976
  sessionId: threadContext.currentThreadId,
2385
1977
  publicKey: (_a = user.address) != null ? _a : void 0,
2386
1978
  getThreadMetadata: threadContext.getThreadMetadata,
@@ -2388,9 +1980,9 @@ function AomiRuntimeInner({
2388
1980
  children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
2389
1981
  EventContextProvider,
2390
1982
  {
2391
- backendApi,
1983
+ aomiClient,
2392
1984
  sessionId: threadContext.currentThreadId,
2393
- children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(AomiRuntimeCore, { backendApi, children })
1985
+ children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(AomiRuntimeCore, { aomiClient, children })
2394
1986
  }
2395
1987
  )
2396
1988
  }
@@ -2440,8 +2032,8 @@ function useNotificationHandler({
2440
2032
  }
2441
2033
  // Annotate the CommonJS export names for ESM import in node:
2442
2034
  0 && (module.exports = {
2035
+ AomiClient,
2443
2036
  AomiRuntimeProvider,
2444
- BackendApi,
2445
2037
  ControlContextProvider,
2446
2038
  EventContextProvider,
2447
2039
  NotificationContextProvider,