@aomi-labs/react 0.2.0 → 0.2.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.js CHANGED
@@ -18,7 +18,7 @@ var __spreadValues = (a, b) => {
18
18
  };
19
19
  var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
20
20
 
21
- // src/backend/sse.ts
21
+ // packages/react/src/backend/sse.ts
22
22
  function extractSseData(rawEvent) {
23
23
  const dataLines = rawEvent.split("\n").filter((line) => line.startsWith("data:")).map((line) => line.slice(5).trimStart());
24
24
  if (!dataLines.length) return null;
@@ -204,8 +204,9 @@ function createSseSubscriber({
204
204
  return { subscribe: subscribe2 };
205
205
  }
206
206
 
207
- // src/backend/client.ts
207
+ // packages/react/src/backend/client.ts
208
208
  var SESSION_ID_HEADER = "X-Session-Id";
209
+ var API_KEY_HEADER = "X-API-Key";
209
210
  function toQueryString(payload) {
210
211
  const params = new URLSearchParams();
211
212
  for (const [key, value] of Object.entries(payload)) {
@@ -220,12 +221,16 @@ function withSessionHeader(sessionId, init) {
220
221
  headers.set(SESSION_ID_HEADER, sessionId);
221
222
  return headers;
222
223
  }
223
- async function postState(backendUrl, path, payload, sessionId) {
224
+ async function postState(backendUrl, path, payload, sessionId, apiKey) {
224
225
  const query = toQueryString(payload);
225
226
  const url = `${backendUrl}${path}${query}`;
227
+ const headers = new Headers(withSessionHeader(sessionId));
228
+ if (apiKey) {
229
+ headers.set(API_KEY_HEADER, apiKey);
230
+ }
226
231
  const response = await fetch(url, {
227
232
  method: "POST",
228
- headers: withSessionHeader(sessionId)
233
+ headers
229
234
  });
230
235
  if (!response.ok) {
231
236
  throw new Error(`HTTP ${response.status}: ${response.statusText}`);
@@ -253,15 +258,17 @@ var BackendApi = class {
253
258
  }
254
259
  return await response.json();
255
260
  }
256
- async postChatMessage(sessionId, message, publicKey) {
261
+ async postChatMessage(sessionId, message, namespace, publicKey, apiKey) {
262
+ const payload = { message, namespace };
263
+ if (publicKey) {
264
+ payload.public_key = publicKey;
265
+ }
257
266
  return postState(
258
267
  this.backendUrl,
259
268
  "/api/chat",
260
- {
261
- message,
262
- public_key: publicKey
263
- },
264
- sessionId
269
+ payload,
270
+ sessionId,
271
+ apiKey
265
272
  );
266
273
  }
267
274
  async postSystemMessage(sessionId, message) {
@@ -379,25 +386,551 @@ var BackendApi = class {
379
386
  if (response.status === 404) return [];
380
387
  throw new Error(`Failed to get system events: HTTP ${response.status}`);
381
388
  }
382
- return await response.json();
383
- }
384
- // fetchEventsAfter removed: /api/events only supports count now
385
- };
386
-
387
- // src/runtime/aomi-runtime.tsx
388
- import { useMemo as useMemo3 } from "react";
389
+ return await response.json();
390
+ }
391
+ // ===========================================================================
392
+ // Control API
393
+ // ===========================================================================
394
+ /**
395
+ * Get allowed namespaces for the current request context.
396
+ */
397
+ async getNamespaces(sessionId, publicKey, apiKey) {
398
+ const url = new URL("/api/control/namespaces", this.backendUrl);
399
+ if (publicKey) {
400
+ url.searchParams.set("public_key", publicKey);
401
+ }
402
+ console.log("[BackendApi.getNamespaces]", {
403
+ backendUrl: this.backendUrl,
404
+ fullUrl: url.toString(),
405
+ sessionId,
406
+ publicKey
407
+ });
408
+ const headers = new Headers(withSessionHeader(sessionId));
409
+ if (apiKey) {
410
+ headers.set(API_KEY_HEADER, apiKey);
411
+ }
412
+ const response = await fetch(url.toString(), { headers });
413
+ if (!response.ok) {
414
+ throw new Error(`Failed to get namespaces: HTTP ${response.status}`);
415
+ }
416
+ return await response.json();
417
+ }
418
+ /**
419
+ * Get available models.
420
+ */
421
+ async getModels(sessionId) {
422
+ const url = new URL("/api/control/models", this.backendUrl);
423
+ console.log("[BackendApi.getModels]", {
424
+ backendUrl: this.backendUrl,
425
+ fullUrl: url.toString(),
426
+ sessionId
427
+ });
428
+ const response = await fetch(url.toString(), {
429
+ headers: withSessionHeader(sessionId)
430
+ });
431
+ if (!response.ok) {
432
+ throw new Error(`Failed to get models: HTTP ${response.status}`);
433
+ }
434
+ return await response.json();
435
+ }
436
+ /**
437
+ * Set the model selection for a session.
438
+ */
439
+ async setModel(sessionId, rig, namespace, apiKey) {
440
+ const payload = { rig };
441
+ if (namespace) {
442
+ payload.namespace = namespace;
443
+ }
444
+ return postState(this.backendUrl, "/api/control/model", payload, sessionId, apiKey);
445
+ }
446
+ };
447
+
448
+ // packages/react/src/runtime/aomi-runtime.tsx
449
+ import { useMemo as useMemo3 } from "react";
450
+
451
+ // packages/react/src/contexts/control-context.tsx
452
+ import {
453
+ createContext,
454
+ useCallback,
455
+ useContext,
456
+ useRef,
457
+ useState,
458
+ useEffect
459
+ } from "react";
460
+
461
+ // packages/react/src/utils/uuid.ts
462
+ function generateUUID() {
463
+ if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
464
+ return crypto.randomUUID();
465
+ }
466
+ return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
467
+ const r = Math.random() * 16 | 0;
468
+ const v = c === "x" ? r : r & 3 | 8;
469
+ return v.toString(16);
470
+ });
471
+ }
472
+
473
+ // packages/react/src/state/thread-store.ts
474
+ var shouldLogThreadUpdates = process.env.NODE_ENV !== "production";
475
+ var logThreadMetadataChange = (source, threadId, prev, next) => {
476
+ if (!shouldLogThreadUpdates) return;
477
+ if (!prev && !next) return;
478
+ if (!prev || !next) {
479
+ console.debug(`[aomi][thread:${source}]`, { threadId, prev, next });
480
+ return;
481
+ }
482
+ if (prev.title !== next.title || prev.status !== next.status || prev.lastActiveAt !== next.lastActiveAt) {
483
+ console.debug(`[aomi][thread:${source}]`, { threadId, prev, next });
484
+ }
485
+ };
486
+ function initThreadControl() {
487
+ return {
488
+ model: null,
489
+ namespace: null,
490
+ controlDirty: false,
491
+ isProcessing: false
492
+ };
493
+ }
494
+ var ThreadStore = class {
495
+ constructor(options) {
496
+ this.listeners = /* @__PURE__ */ new Set();
497
+ this.subscribe = (listener) => {
498
+ this.listeners.add(listener);
499
+ return () => {
500
+ this.listeners.delete(listener);
501
+ };
502
+ };
503
+ this.getSnapshot = () => this.snapshot;
504
+ this.setCurrentThreadId = (threadId) => {
505
+ this.ensureThreadExists(threadId);
506
+ this.updateState({ currentThreadId: threadId });
507
+ };
508
+ this.bumpThreadViewKey = () => {
509
+ this.updateState({ threadViewKey: this.state.threadViewKey + 1 });
510
+ };
511
+ this.setThreadCnt = (updater) => {
512
+ const nextCnt = this.resolveStateAction(updater, this.state.threadCnt);
513
+ this.updateState({ threadCnt: nextCnt });
514
+ };
515
+ this.setThreads = (updater) => {
516
+ const nextThreads = this.resolveStateAction(updater, this.state.threads);
517
+ this.updateState({ threads: new Map(nextThreads) });
518
+ };
519
+ this.setThreadMetadata = (updater) => {
520
+ const prevMetadata = this.state.threadMetadata;
521
+ const nextMetadata = this.resolveStateAction(updater, prevMetadata);
522
+ for (const [threadId, next] of nextMetadata.entries()) {
523
+ logThreadMetadataChange(
524
+ "setThreadMetadata",
525
+ threadId,
526
+ prevMetadata.get(threadId),
527
+ next
528
+ );
529
+ }
530
+ for (const [threadId, prev] of prevMetadata.entries()) {
531
+ if (!nextMetadata.has(threadId)) {
532
+ logThreadMetadataChange("setThreadMetadata", threadId, prev, void 0);
533
+ }
534
+ }
535
+ this.updateState({ threadMetadata: new Map(nextMetadata) });
536
+ };
537
+ this.setThreadMessages = (threadId, messages) => {
538
+ this.ensureThreadExists(threadId);
539
+ const nextThreads = new Map(this.state.threads);
540
+ nextThreads.set(threadId, messages);
541
+ this.updateState({ threads: nextThreads });
542
+ };
543
+ this.getThreadMessages = (threadId) => {
544
+ var _a;
545
+ return (_a = this.state.threads.get(threadId)) != null ? _a : [];
546
+ };
547
+ this.getThreadMetadata = (threadId) => {
548
+ return this.state.threadMetadata.get(threadId);
549
+ };
550
+ this.updateThreadMetadata = (threadId, updates) => {
551
+ const existing = this.state.threadMetadata.get(threadId);
552
+ if (!existing) {
553
+ return;
554
+ }
555
+ const next = __spreadValues(__spreadValues({}, existing), updates);
556
+ const nextMetadata = new Map(this.state.threadMetadata);
557
+ nextMetadata.set(threadId, next);
558
+ logThreadMetadataChange("updateThreadMetadata", threadId, existing, next);
559
+ this.updateState({ threadMetadata: nextMetadata });
560
+ };
561
+ var _a;
562
+ const initialThreadId = (_a = options == null ? void 0 : options.initialThreadId) != null ? _a : generateUUID();
563
+ this.state = {
564
+ currentThreadId: initialThreadId,
565
+ threadViewKey: 0,
566
+ threadCnt: 1,
567
+ threads: /* @__PURE__ */ new Map([[initialThreadId, []]]),
568
+ threadMetadata: /* @__PURE__ */ new Map([
569
+ [
570
+ initialThreadId,
571
+ {
572
+ title: "New Chat",
573
+ status: "pending",
574
+ lastActiveAt: (/* @__PURE__ */ new Date()).toISOString(),
575
+ control: initThreadControl()
576
+ }
577
+ ]
578
+ ])
579
+ };
580
+ this.snapshot = this.buildSnapshot();
581
+ }
582
+ emit() {
583
+ for (const listener of this.listeners) {
584
+ listener();
585
+ }
586
+ }
587
+ resolveStateAction(updater, current) {
588
+ return typeof updater === "function" ? updater(current) : updater;
589
+ }
590
+ ensureThreadExists(threadId) {
591
+ if (!this.state.threadMetadata.has(threadId)) {
592
+ const nextMetadata = new Map(this.state.threadMetadata);
593
+ nextMetadata.set(threadId, {
594
+ title: "New Chat",
595
+ status: "regular",
596
+ lastActiveAt: (/* @__PURE__ */ new Date()).toISOString(),
597
+ control: initThreadControl()
598
+ });
599
+ this.state = __spreadProps(__spreadValues({}, this.state), { threadMetadata: nextMetadata });
600
+ }
601
+ if (!this.state.threads.has(threadId)) {
602
+ const nextThreads = new Map(this.state.threads);
603
+ nextThreads.set(threadId, []);
604
+ this.state = __spreadProps(__spreadValues({}, this.state), { threads: nextThreads });
605
+ }
606
+ }
607
+ updateState(partial) {
608
+ this.state = __spreadValues(__spreadValues({}, this.state), partial);
609
+ this.snapshot = this.buildSnapshot();
610
+ this.emit();
611
+ }
612
+ buildSnapshot() {
613
+ return {
614
+ currentThreadId: this.state.currentThreadId,
615
+ setCurrentThreadId: this.setCurrentThreadId,
616
+ threadViewKey: this.state.threadViewKey,
617
+ bumpThreadViewKey: this.bumpThreadViewKey,
618
+ allThreads: this.state.threads,
619
+ setThreads: this.setThreads,
620
+ allThreadsMetadata: this.state.threadMetadata,
621
+ setThreadMetadata: this.setThreadMetadata,
622
+ threadCnt: this.state.threadCnt,
623
+ setThreadCnt: this.setThreadCnt,
624
+ getThreadMessages: this.getThreadMessages,
625
+ setThreadMessages: this.setThreadMessages,
626
+ getThreadMetadata: this.getThreadMetadata,
627
+ updateThreadMetadata: this.updateThreadMetadata
628
+ };
629
+ }
630
+ };
631
+
632
+ // packages/react/src/contexts/control-context.tsx
633
+ import { jsx } from "react/jsx-runtime";
634
+ var API_KEY_STORAGE_KEY = "aomi_api_key";
635
+ var ControlContext = createContext(null);
636
+ function useControl() {
637
+ const ctx = useContext(ControlContext);
638
+ if (!ctx) {
639
+ throw new Error("useControl must be used within ControlContextProvider");
640
+ }
641
+ return ctx;
642
+ }
643
+ function ControlContextProvider({
644
+ children,
645
+ backendApi,
646
+ sessionId,
647
+ publicKey,
648
+ getThreadMetadata,
649
+ updateThreadMetadata
650
+ }) {
651
+ var _a, _b;
652
+ const [state, setStateInternal] = useState(() => ({
653
+ apiKey: null,
654
+ availableModels: [],
655
+ authorizedNamespaces: [],
656
+ defaultModel: null,
657
+ defaultNamespace: null
658
+ }));
659
+ const stateRef = useRef(state);
660
+ stateRef.current = state;
661
+ const backendApiRef = useRef(backendApi);
662
+ backendApiRef.current = backendApi;
663
+ const sessionIdRef = useRef(sessionId);
664
+ sessionIdRef.current = sessionId;
665
+ const publicKeyRef = useRef(publicKey);
666
+ publicKeyRef.current = publicKey;
667
+ const getThreadMetadataRef = useRef(getThreadMetadata);
668
+ getThreadMetadataRef.current = getThreadMetadata;
669
+ const updateThreadMetadataRef = useRef(updateThreadMetadata);
670
+ updateThreadMetadataRef.current = updateThreadMetadata;
671
+ const callbacks = useRef(/* @__PURE__ */ new Set());
672
+ const currentThreadMetadata = getThreadMetadata(sessionId);
673
+ const isProcessing = (_b = (_a = currentThreadMetadata == null ? void 0 : currentThreadMetadata.control) == null ? void 0 : _a.isProcessing) != null ? _b : false;
674
+ useEffect(() => {
675
+ var _a2, _b2;
676
+ try {
677
+ const storedApiKey = (_b2 = (_a2 = globalThis.localStorage) == null ? void 0 : _a2.getItem(API_KEY_STORAGE_KEY)) != null ? _b2 : null;
678
+ if (storedApiKey) {
679
+ setStateInternal((prev) => __spreadProps(__spreadValues({}, prev), { apiKey: storedApiKey }));
680
+ }
681
+ } catch (e) {
682
+ }
683
+ }, []);
684
+ useEffect(() => {
685
+ var _a2, _b2;
686
+ try {
687
+ if (state.apiKey) {
688
+ (_a2 = globalThis.localStorage) == null ? void 0 : _a2.setItem(API_KEY_STORAGE_KEY, state.apiKey);
689
+ } else {
690
+ (_b2 = globalThis.localStorage) == null ? void 0 : _b2.removeItem(API_KEY_STORAGE_KEY);
691
+ }
692
+ } catch (e) {
693
+ }
694
+ }, [state.apiKey]);
695
+ useEffect(() => {
696
+ const fetchNamespaces = async () => {
697
+ var _a2, _b2;
698
+ try {
699
+ const namespaces = await backendApiRef.current.getNamespaces(
700
+ sessionIdRef.current,
701
+ publicKeyRef.current,
702
+ (_a2 = stateRef.current.apiKey) != null ? _a2 : void 0
703
+ );
704
+ const defaultNs = namespaces.includes("default") ? "default" : (_b2 = namespaces[0]) != null ? _b2 : null;
705
+ setStateInternal((prev) => __spreadProps(__spreadValues({}, prev), {
706
+ authorizedNamespaces: namespaces,
707
+ defaultNamespace: defaultNs
708
+ }));
709
+ } catch (error) {
710
+ console.error("Failed to fetch namespaces:", error);
711
+ setStateInternal((prev) => __spreadProps(__spreadValues({}, prev), {
712
+ authorizedNamespaces: ["default"],
713
+ defaultNamespace: "default"
714
+ }));
715
+ }
716
+ };
717
+ void fetchNamespaces();
718
+ }, [state.apiKey]);
719
+ useEffect(() => {
720
+ const fetchModels = async () => {
721
+ try {
722
+ const models = await backendApiRef.current.getModels(
723
+ sessionIdRef.current
724
+ );
725
+ setStateInternal((prev) => {
726
+ var _a2;
727
+ return __spreadProps(__spreadValues({}, prev), {
728
+ availableModels: models,
729
+ defaultModel: (_a2 = models[0]) != null ? _a2 : null
730
+ });
731
+ });
732
+ } catch (error) {
733
+ console.error("Failed to fetch models:", error);
734
+ }
735
+ };
736
+ void fetchModels();
737
+ }, []);
738
+ const setApiKey = useCallback((apiKey) => {
739
+ setStateInternal((prev) => {
740
+ const next = __spreadProps(__spreadValues({}, prev), { apiKey: apiKey === "" ? null : apiKey });
741
+ callbacks.current.forEach((cb) => cb(next));
742
+ return next;
743
+ });
744
+ }, []);
745
+ const getAvailableModels = useCallback(async () => {
746
+ try {
747
+ const models = await backendApiRef.current.getModels(
748
+ sessionIdRef.current
749
+ );
750
+ setStateInternal((prev) => {
751
+ var _a2, _b2;
752
+ return __spreadProps(__spreadValues({}, prev), {
753
+ availableModels: models,
754
+ defaultModel: (_b2 = (_a2 = prev.defaultModel) != null ? _a2 : models[0]) != null ? _b2 : null
755
+ });
756
+ });
757
+ return models;
758
+ } catch (error) {
759
+ console.error("Failed to fetch models:", error);
760
+ return [];
761
+ }
762
+ }, []);
763
+ const getAuthorizedNamespaces = useCallback(async () => {
764
+ var _a2, _b2;
765
+ try {
766
+ const namespaces = await backendApiRef.current.getNamespaces(
767
+ sessionIdRef.current,
768
+ publicKeyRef.current,
769
+ (_a2 = stateRef.current.apiKey) != null ? _a2 : void 0
770
+ );
771
+ const defaultNs = namespaces.includes("default") ? "default" : (_b2 = namespaces[0]) != null ? _b2 : null;
772
+ setStateInternal((prev) => __spreadProps(__spreadValues({}, prev), {
773
+ authorizedNamespaces: namespaces,
774
+ defaultNamespace: defaultNs
775
+ }));
776
+ return namespaces;
777
+ } catch (error) {
778
+ console.error("Failed to fetch namespaces:", error);
779
+ setStateInternal((prev) => __spreadProps(__spreadValues({}, prev), {
780
+ authorizedNamespaces: ["default"],
781
+ defaultNamespace: "default"
782
+ }));
783
+ return ["default"];
784
+ }
785
+ }, []);
786
+ const getCurrentThreadControl = useCallback(() => {
787
+ var _a2;
788
+ const metadata = getThreadMetadataRef.current(sessionIdRef.current);
789
+ return (_a2 = metadata == null ? void 0 : metadata.control) != null ? _a2 : initThreadControl();
790
+ }, []);
791
+ const onModelSelect = useCallback(async (model) => {
792
+ var _a2, _b2, _c, _d, _e;
793
+ const threadId = sessionIdRef.current;
794
+ const currentControl = (_b2 = (_a2 = getThreadMetadataRef.current(threadId)) == null ? void 0 : _a2.control) != null ? _b2 : initThreadControl();
795
+ const isProcessing2 = currentControl.isProcessing;
796
+ console.log("[control-context] onModelSelect called", {
797
+ model,
798
+ isProcessing: isProcessing2,
799
+ threadId
800
+ });
801
+ if (isProcessing2) {
802
+ console.warn("[control-context] Cannot switch model while processing");
803
+ return;
804
+ }
805
+ const namespace = (_d = (_c = currentControl.namespace) != null ? _c : stateRef.current.defaultNamespace) != null ? _d : "default";
806
+ console.log("[control-context] onModelSelect updating metadata", {
807
+ threadId,
808
+ model,
809
+ namespace,
810
+ currentControl
811
+ });
812
+ updateThreadMetadataRef.current(threadId, {
813
+ control: __spreadProps(__spreadValues({}, currentControl), {
814
+ model,
815
+ namespace,
816
+ controlDirty: true
817
+ })
818
+ });
819
+ console.log("[control-context] onModelSelect calling backend setModel", {
820
+ threadId,
821
+ model,
822
+ namespace,
823
+ backendUrl: backendApiRef.current
824
+ });
825
+ try {
826
+ const result = await backendApiRef.current.setModel(
827
+ threadId,
828
+ model,
829
+ namespace,
830
+ (_e = stateRef.current.apiKey) != null ? _e : void 0
831
+ );
832
+ console.log("[control-context] onModelSelect backend result", result);
833
+ } catch (err) {
834
+ console.error("[control-context] setModel failed:", err);
835
+ throw err;
836
+ }
837
+ }, []);
838
+ const onNamespaceSelect = useCallback((namespace) => {
839
+ var _a2, _b2;
840
+ const threadId = sessionIdRef.current;
841
+ const currentControl = (_b2 = (_a2 = getThreadMetadataRef.current(threadId)) == null ? void 0 : _a2.control) != null ? _b2 : initThreadControl();
842
+ const isProcessing2 = currentControl.isProcessing;
843
+ console.log("[control-context] onNamespaceSelect called", {
844
+ namespace,
845
+ isProcessing: isProcessing2,
846
+ threadId
847
+ });
848
+ if (isProcessing2) {
849
+ console.warn(
850
+ "[control-context] Cannot switch namespace while processing"
851
+ );
852
+ return;
853
+ }
854
+ console.log("[control-context] onNamespaceSelect updating metadata", {
855
+ threadId,
856
+ namespace,
857
+ currentControl
858
+ });
859
+ updateThreadMetadataRef.current(threadId, {
860
+ control: __spreadProps(__spreadValues({}, currentControl), {
861
+ namespace,
862
+ controlDirty: true
863
+ })
864
+ });
865
+ console.log("[control-context] onNamespaceSelect metadata updated");
866
+ }, []);
867
+ const markControlSynced = useCallback(() => {
868
+ var _a2, _b2;
869
+ const threadId = sessionIdRef.current;
870
+ const currentControl = (_b2 = (_a2 = getThreadMetadataRef.current(threadId)) == null ? void 0 : _a2.control) != null ? _b2 : initThreadControl();
871
+ if (currentControl.controlDirty) {
872
+ updateThreadMetadataRef.current(threadId, {
873
+ control: __spreadProps(__spreadValues({}, currentControl), {
874
+ controlDirty: false
875
+ })
876
+ });
877
+ }
878
+ }, []);
879
+ const getControlState = useCallback(() => stateRef.current, []);
880
+ const onControlStateChange = useCallback(
881
+ (callback) => {
882
+ callbacks.current.add(callback);
883
+ return () => {
884
+ callbacks.current.delete(callback);
885
+ };
886
+ },
887
+ []
888
+ );
889
+ const setState = useCallback(
890
+ (updates) => {
891
+ var _a2;
892
+ if ("apiKey" in updates) {
893
+ setApiKey((_a2 = updates.apiKey) != null ? _a2 : null);
894
+ }
895
+ if ("namespace" in updates && updates.namespace !== void 0 && updates.namespace !== null) {
896
+ onNamespaceSelect(updates.namespace);
897
+ }
898
+ },
899
+ [setApiKey, onNamespaceSelect]
900
+ );
901
+ return /* @__PURE__ */ jsx(
902
+ ControlContext.Provider,
903
+ {
904
+ value: {
905
+ state,
906
+ setApiKey,
907
+ getAvailableModels,
908
+ getAuthorizedNamespaces,
909
+ getCurrentThreadControl,
910
+ onModelSelect,
911
+ onNamespaceSelect,
912
+ isProcessing,
913
+ markControlSynced,
914
+ getControlState,
915
+ onControlStateChange,
916
+ setState
917
+ },
918
+ children
919
+ }
920
+ );
921
+ }
389
922
 
390
- // src/contexts/event-context.tsx
923
+ // packages/react/src/contexts/event-context.tsx
391
924
  import {
392
- createContext,
393
- useCallback,
394
- useContext,
395
- useEffect,
396
- useRef,
397
- useState
925
+ createContext as createContext2,
926
+ useCallback as useCallback2,
927
+ useContext as useContext2,
928
+ useEffect as useEffect2,
929
+ useRef as useRef2,
930
+ useState as useState2
398
931
  } from "react";
399
932
 
400
- // src/backend/types.ts
933
+ // packages/react/src/backend/types.ts
401
934
  function isInlineCall(event) {
402
935
  return "InlineCall" in event;
403
936
  }
@@ -411,7 +944,7 @@ function isAsyncCallback(event) {
411
944
  return "AsyncCallback" in event;
412
945
  }
413
946
 
414
- // src/state/event-buffer.ts
947
+ // packages/react/src/state/event-buffer.ts
415
948
  function createEventBuffer() {
416
949
  return {
417
950
  inboundQueue: [],
@@ -455,11 +988,11 @@ function setSSEStatus(state, status) {
455
988
  state.sseStatus = status;
456
989
  }
457
990
 
458
- // src/contexts/event-context.tsx
459
- import { jsx } from "react/jsx-runtime";
460
- var EventContextState = createContext(null);
991
+ // packages/react/src/contexts/event-context.tsx
992
+ import { jsx as jsx2 } from "react/jsx-runtime";
993
+ var EventContextState = createContext2(null);
461
994
  function useEventContext() {
462
- const context = useContext(EventContextState);
995
+ const context = useContext2(EventContextState);
463
996
  if (!context) {
464
997
  throw new Error(
465
998
  "useEventContext must be used within EventContextProvider. Wrap your app with <EventContextProvider>...</EventContextProvider>"
@@ -472,13 +1005,13 @@ function EventContextProvider({
472
1005
  backendApi,
473
1006
  sessionId
474
1007
  }) {
475
- const bufferRef = useRef(null);
1008
+ const bufferRef = useRef2(null);
476
1009
  if (!bufferRef.current) {
477
1010
  bufferRef.current = createEventBuffer();
478
1011
  }
479
1012
  const buffer = bufferRef.current;
480
- const [sseStatus, setSseStatus] = useState("disconnected");
481
- useEffect(() => {
1013
+ const [sseStatus, setSseStatus] = useState2("disconnected");
1014
+ useEffect2(() => {
482
1015
  setSSEStatus(buffer, "connecting");
483
1016
  setSseStatus("connecting");
484
1017
  const unsubscribe = backendApi.subscribeSSE(
@@ -512,13 +1045,13 @@ function EventContextProvider({
512
1045
  setSseStatus("disconnected");
513
1046
  };
514
1047
  }, [backendApi, sessionId, buffer]);
515
- const subscribeCallback = useCallback(
1048
+ const subscribeCallback = useCallback2(
516
1049
  (type, callback) => {
517
1050
  return subscribe(buffer, type, callback);
518
1051
  },
519
1052
  [buffer]
520
1053
  );
521
- const sendOutbound = useCallback(
1054
+ const sendOutbound = useCallback2(
522
1055
  async (event) => {
523
1056
  try {
524
1057
  const message = JSON.stringify({
@@ -532,7 +1065,7 @@ function EventContextProvider({
532
1065
  },
533
1066
  [backendApi]
534
1067
  );
535
- const dispatchSystemEvents = useCallback(
1068
+ const dispatchSystemEvents = useCallback2(
536
1069
  (sessionId2, events) => {
537
1070
  var _a;
538
1071
  for (const event of events) {
@@ -577,20 +1110,20 @@ function EventContextProvider({
577
1110
  dispatchInboundSystem: dispatchSystemEvents,
578
1111
  sseStatus
579
1112
  };
580
- return /* @__PURE__ */ jsx(EventContextState.Provider, { value: contextValue, children });
1113
+ return /* @__PURE__ */ jsx2(EventContextState.Provider, { value: contextValue, children });
581
1114
  }
582
1115
 
583
- // src/contexts/notification-context.tsx
1116
+ // packages/react/src/contexts/notification-context.tsx
584
1117
  import {
585
- createContext as createContext2,
586
- useCallback as useCallback2,
587
- useContext as useContext2,
588
- useState as useState2
1118
+ createContext as createContext3,
1119
+ useCallback as useCallback3,
1120
+ useContext as useContext3,
1121
+ useState as useState3
589
1122
  } from "react";
590
- import { jsx as jsx2 } from "react/jsx-runtime";
591
- var NotificationContext = createContext2(null);
1123
+ import { jsx as jsx3 } from "react/jsx-runtime";
1124
+ var NotificationContext = createContext3(null);
592
1125
  function useNotification() {
593
- const context = useContext2(NotificationContext);
1126
+ const context = useContext3(NotificationContext);
594
1127
  if (!context) {
595
1128
  throw new Error(
596
1129
  "useNotification must be used within NotificationContextProvider"
@@ -605,8 +1138,8 @@ function generateId() {
605
1138
  function NotificationContextProvider({
606
1139
  children
607
1140
  }) {
608
- const [notifications, setNotifications] = useState2([]);
609
- const showNotification = useCallback2((params) => {
1141
+ const [notifications, setNotifications] = useState3([]);
1142
+ const showNotification = useCallback3((params) => {
610
1143
  const id = generateId();
611
1144
  const notification = __spreadProps(__spreadValues({}, params), {
612
1145
  id,
@@ -615,10 +1148,10 @@ function NotificationContextProvider({
615
1148
  setNotifications((prev) => [notification, ...prev]);
616
1149
  return id;
617
1150
  }, []);
618
- const dismissNotification = useCallback2((id) => {
1151
+ const dismissNotification = useCallback3((id) => {
619
1152
  setNotifications((prev) => prev.filter((n) => n.id !== id));
620
1153
  }, []);
621
- const clearAll = useCallback2(() => {
1154
+ const clearAll = useCallback3(() => {
622
1155
  setNotifications([]);
623
1156
  }, []);
624
1157
  const value = {
@@ -627,172 +1160,21 @@ function NotificationContextProvider({
627
1160
  dismissNotification,
628
1161
  clearAll
629
1162
  };
630
- return /* @__PURE__ */ jsx2(NotificationContext.Provider, { value, children });
1163
+ return /* @__PURE__ */ jsx3(NotificationContext.Provider, { value, children });
631
1164
  }
632
1165
 
633
- // src/contexts/thread-context.tsx
1166
+ // packages/react/src/contexts/thread-context.tsx
634
1167
  import {
635
- createContext as createContext3,
636
- useContext as useContext3,
1168
+ createContext as createContext4,
1169
+ useContext as useContext4,
637
1170
  useMemo,
638
- useRef as useRef2,
1171
+ useRef as useRef3,
639
1172
  useSyncExternalStore
640
1173
  } from "react";
641
-
642
- // src/state/thread-store.ts
643
- var shouldLogThreadUpdates = process.env.NODE_ENV !== "production";
644
- var logThreadMetadataChange = (source, threadId, prev, next) => {
645
- if (!shouldLogThreadUpdates) return;
646
- if (!prev && !next) return;
647
- if (!prev || !next) {
648
- console.debug(`[aomi][thread:${source}]`, { threadId, prev, next });
649
- return;
650
- }
651
- if (prev.title !== next.title || prev.status !== next.status || prev.lastActiveAt !== next.lastActiveAt) {
652
- console.debug(`[aomi][thread:${source}]`, { threadId, prev, next });
653
- }
654
- };
655
- var ThreadStore = class {
656
- constructor(options) {
657
- this.listeners = /* @__PURE__ */ new Set();
658
- this.subscribe = (listener) => {
659
- this.listeners.add(listener);
660
- return () => {
661
- this.listeners.delete(listener);
662
- };
663
- };
664
- this.getSnapshot = () => this.snapshot;
665
- this.setCurrentThreadId = (threadId) => {
666
- this.ensureThreadExists(threadId);
667
- this.updateState({ currentThreadId: threadId });
668
- };
669
- this.bumpThreadViewKey = () => {
670
- this.updateState({ threadViewKey: this.state.threadViewKey + 1 });
671
- };
672
- this.setThreadCnt = (updater) => {
673
- const nextCnt = this.resolveStateAction(updater, this.state.threadCnt);
674
- this.updateState({ threadCnt: nextCnt });
675
- };
676
- this.setThreads = (updater) => {
677
- const nextThreads = this.resolveStateAction(updater, this.state.threads);
678
- this.updateState({ threads: new Map(nextThreads) });
679
- };
680
- this.setThreadMetadata = (updater) => {
681
- const prevMetadata = this.state.threadMetadata;
682
- const nextMetadata = this.resolveStateAction(updater, prevMetadata);
683
- for (const [threadId, next] of nextMetadata.entries()) {
684
- logThreadMetadataChange(
685
- "setThreadMetadata",
686
- threadId,
687
- prevMetadata.get(threadId),
688
- next
689
- );
690
- }
691
- for (const [threadId, prev] of prevMetadata.entries()) {
692
- if (!nextMetadata.has(threadId)) {
693
- logThreadMetadataChange("setThreadMetadata", threadId, prev, void 0);
694
- }
695
- }
696
- this.updateState({ threadMetadata: new Map(nextMetadata) });
697
- };
698
- this.setThreadMessages = (threadId, messages) => {
699
- this.ensureThreadExists(threadId);
700
- const nextThreads = new Map(this.state.threads);
701
- nextThreads.set(threadId, messages);
702
- this.updateState({ threads: nextThreads });
703
- };
704
- this.getThreadMessages = (threadId) => {
705
- var _a;
706
- return (_a = this.state.threads.get(threadId)) != null ? _a : [];
707
- };
708
- this.getThreadMetadata = (threadId) => {
709
- return this.state.threadMetadata.get(threadId);
710
- };
711
- this.updateThreadMetadata = (threadId, updates) => {
712
- const existing = this.state.threadMetadata.get(threadId);
713
- if (!existing) {
714
- return;
715
- }
716
- const next = __spreadValues(__spreadValues({}, existing), updates);
717
- const nextMetadata = new Map(this.state.threadMetadata);
718
- nextMetadata.set(threadId, next);
719
- logThreadMetadataChange("updateThreadMetadata", threadId, existing, next);
720
- this.updateState({ threadMetadata: nextMetadata });
721
- };
722
- var _a;
723
- const initialThreadId = (_a = options == null ? void 0 : options.initialThreadId) != null ? _a : crypto.randomUUID();
724
- this.state = {
725
- currentThreadId: initialThreadId,
726
- threadViewKey: 0,
727
- threadCnt: 1,
728
- threads: /* @__PURE__ */ new Map([[initialThreadId, []]]),
729
- threadMetadata: /* @__PURE__ */ new Map([
730
- [
731
- initialThreadId,
732
- {
733
- title: "New Chat",
734
- status: "pending",
735
- lastActiveAt: (/* @__PURE__ */ new Date()).toISOString()
736
- }
737
- ]
738
- ])
739
- };
740
- this.snapshot = this.buildSnapshot();
741
- }
742
- emit() {
743
- for (const listener of this.listeners) {
744
- listener();
745
- }
746
- }
747
- resolveStateAction(updater, current) {
748
- return typeof updater === "function" ? updater(current) : updater;
749
- }
750
- ensureThreadExists(threadId) {
751
- if (!this.state.threadMetadata.has(threadId)) {
752
- const nextMetadata = new Map(this.state.threadMetadata);
753
- nextMetadata.set(threadId, {
754
- title: "New Chat",
755
- status: "regular",
756
- lastActiveAt: (/* @__PURE__ */ new Date()).toISOString()
757
- });
758
- this.state = __spreadProps(__spreadValues({}, this.state), { threadMetadata: nextMetadata });
759
- }
760
- if (!this.state.threads.has(threadId)) {
761
- const nextThreads = new Map(this.state.threads);
762
- nextThreads.set(threadId, []);
763
- this.state = __spreadProps(__spreadValues({}, this.state), { threads: nextThreads });
764
- }
765
- }
766
- updateState(partial) {
767
- this.state = __spreadValues(__spreadValues({}, this.state), partial);
768
- this.snapshot = this.buildSnapshot();
769
- this.emit();
770
- }
771
- buildSnapshot() {
772
- return {
773
- currentThreadId: this.state.currentThreadId,
774
- setCurrentThreadId: this.setCurrentThreadId,
775
- threadViewKey: this.state.threadViewKey,
776
- bumpThreadViewKey: this.bumpThreadViewKey,
777
- allThreads: this.state.threads,
778
- setThreads: this.setThreads,
779
- allThreadsMetadata: this.state.threadMetadata,
780
- setThreadMetadata: this.setThreadMetadata,
781
- threadCnt: this.state.threadCnt,
782
- setThreadCnt: this.setThreadCnt,
783
- getThreadMessages: this.getThreadMessages,
784
- setThreadMessages: this.setThreadMessages,
785
- getThreadMetadata: this.getThreadMetadata,
786
- updateThreadMetadata: this.updateThreadMetadata
787
- };
788
- }
789
- };
790
-
791
- // src/contexts/thread-context.tsx
792
- import { jsx as jsx3 } from "react/jsx-runtime";
793
- var ThreadContextState = createContext3(null);
1174
+ import { jsx as jsx4 } from "react/jsx-runtime";
1175
+ var ThreadContextState = createContext4(null);
794
1176
  function useThreadContext() {
795
- const context = useContext3(ThreadContextState);
1177
+ const context = useContext4(ThreadContextState);
796
1178
  if (!context) {
797
1179
  throw new Error(
798
1180
  "useThreadContext must be used within ThreadContextProvider. Wrap your app with <ThreadContextProvider>...</ThreadContextProvider>"
@@ -804,7 +1186,7 @@ function ThreadContextProvider({
804
1186
  children,
805
1187
  initialThreadId
806
1188
  }) {
807
- const storeRef = useRef2(null);
1189
+ const storeRef = useRef3(null);
808
1190
  if (!storeRef.current) {
809
1191
  storeRef.current = new ThreadStore({ initialThreadId });
810
1192
  }
@@ -814,7 +1196,7 @@ function ThreadContextProvider({
814
1196
  store.getSnapshot,
815
1197
  store.getSnapshot
816
1198
  );
817
- return /* @__PURE__ */ jsx3(ThreadContextState.Provider, { value, children });
1199
+ return /* @__PURE__ */ jsx4(ThreadContextState.Provider, { value, children });
818
1200
  }
819
1201
  function useCurrentThreadMessages() {
820
1202
  const { currentThreadId, getThreadMessages } = useThreadContext();
@@ -831,18 +1213,18 @@ function useCurrentThreadMetadata() {
831
1213
  );
832
1214
  }
833
1215
 
834
- // src/contexts/user-context.tsx
1216
+ // packages/react/src/contexts/user-context.tsx
835
1217
  import {
836
- createContext as createContext4,
837
- useCallback as useCallback3,
838
- useContext as useContext4,
839
- useRef as useRef3,
840
- useState as useState3
1218
+ createContext as createContext5,
1219
+ useCallback as useCallback4,
1220
+ useContext as useContext5,
1221
+ useRef as useRef4,
1222
+ useState as useState4
841
1223
  } from "react";
842
- import { jsx as jsx4 } from "react/jsx-runtime";
843
- var UserContext = createContext4(void 0);
1224
+ import { jsx as jsx5 } from "react/jsx-runtime";
1225
+ var UserContext = createContext5(void 0);
844
1226
  function useUser() {
845
- const context = useContext4(UserContext);
1227
+ const context = useContext5(UserContext);
846
1228
  if (!context) {
847
1229
  throw new Error("useUser must be used within UserContextProvider");
848
1230
  }
@@ -854,18 +1236,18 @@ function useUser() {
854
1236
  };
855
1237
  }
856
1238
  function UserContextProvider({ children }) {
857
- const [user, setUserState] = useState3({
1239
+ const [user, setUserState] = useState4({
858
1240
  isConnected: false,
859
1241
  address: void 0,
860
1242
  chainId: void 0,
861
1243
  ensName: void 0
862
1244
  });
863
- const userRef = useRef3(user);
1245
+ const userRef = useRef4(user);
864
1246
  userRef.current = user;
865
- const StateChangeCallbacks = useRef3(
1247
+ const StateChangeCallbacks = useRef4(
866
1248
  /* @__PURE__ */ new Set()
867
1249
  );
868
- const setUser = useCallback3((data) => {
1250
+ const setUser = useCallback4((data) => {
869
1251
  setUserState((prev) => {
870
1252
  const next = __spreadValues(__spreadValues({}, prev), data);
871
1253
  StateChangeCallbacks.current.forEach((callback) => {
@@ -874,8 +1256,8 @@ function UserContextProvider({ children }) {
874
1256
  return next;
875
1257
  });
876
1258
  }, []);
877
- const getUserState = useCallback3(() => userRef.current, []);
878
- const onUserStateChange = useCallback3(
1259
+ const getUserState = useCallback4(() => userRef.current, []);
1260
+ const onUserStateChange = useCallback4(
879
1261
  (callback) => {
880
1262
  StateChangeCallbacks.current.add(callback);
881
1263
  return () => {
@@ -884,7 +1266,7 @@ function UserContextProvider({ children }) {
884
1266
  },
885
1267
  []
886
1268
  );
887
- return /* @__PURE__ */ jsx4(
1269
+ return /* @__PURE__ */ jsx5(
888
1270
  UserContext.Provider,
889
1271
  {
890
1272
  value: {
@@ -898,17 +1280,17 @@ function UserContextProvider({ children }) {
898
1280
  );
899
1281
  }
900
1282
 
901
- // src/runtime/core.tsx
902
- import { useCallback as useCallback5, useEffect as useEffect2, useMemo as useMemo2, useRef as useRef5 } from "react";
1283
+ // packages/react/src/runtime/core.tsx
1284
+ import { useCallback as useCallback6, useEffect as useEffect3, useMemo as useMemo2, useRef as useRef6 } from "react";
903
1285
  import {
904
1286
  AssistantRuntimeProvider,
905
1287
  useExternalStoreRuntime
906
1288
  } from "@assistant-ui/react";
907
1289
 
908
- // src/runtime/orchestrator.ts
909
- import { useCallback as useCallback4, useRef as useRef4, useState as useState4 } from "react";
1290
+ // packages/react/src/runtime/orchestrator.ts
1291
+ import { useCallback as useCallback5, useRef as useRef5, useState as useState5 } from "react";
910
1292
 
911
- // src/runtime/utils.ts
1293
+ // packages/react/src/runtime/utils.ts
912
1294
  import { clsx } from "clsx";
913
1295
  import { twMerge } from "tailwind-merge";
914
1296
  function cn(...inputs) {
@@ -1001,7 +1383,7 @@ var getNetworkName = (chainId) => {
1001
1383
  };
1002
1384
  var formatAddress = (addr) => addr ? `${addr.slice(0, 6)}...${addr.slice(-4)}` : "Connect Wallet";
1003
1385
 
1004
- // src/state/backend-state.ts
1386
+ // packages/react/src/state/backend-state.ts
1005
1387
  function createBackendState() {
1006
1388
  return {
1007
1389
  skipInitialFetch: /* @__PURE__ */ new Set(),
@@ -1052,7 +1434,7 @@ function hasPendingChat(state, threadId) {
1052
1434
  return ((_b = (_a = state.pendingChat.get(threadId)) == null ? void 0 : _a.length) != null ? _b : 0) > 0;
1053
1435
  }
1054
1436
 
1055
- // src/runtime/message-controller.ts
1437
+ // packages/react/src/runtime/message-controller.ts
1056
1438
  var MessageController = class {
1057
1439
  constructor(config) {
1058
1440
  this.config = config;
@@ -1073,7 +1455,7 @@ var MessageController = class {
1073
1455
  this.getThreadContextApi().setThreadMessages(threadId, threadMessages);
1074
1456
  }
1075
1457
  async outbound(message, threadId) {
1076
- var _a, _b, _c;
1458
+ var _a, _b, _c, _d, _e, _f;
1077
1459
  const backendState = this.config.backendStateRef.current;
1078
1460
  const text = message.content.filter(
1079
1461
  (part) => part.type === "text"
@@ -1098,21 +1480,22 @@ var MessageController = class {
1098
1480
  return;
1099
1481
  }
1100
1482
  const backendThreadId = resolveThreadId(backendState, threadId);
1483
+ const namespace = this.config.getNamespace();
1101
1484
  const publicKey = (_b = (_a = this.config).getPublicKey) == null ? void 0 : _b.call(_a);
1485
+ const apiKey = (_e = (_d = (_c = this.config).getApiKey) == null ? void 0 : _d.call(_c)) != null ? _e : void 0;
1102
1486
  try {
1103
1487
  this.markRunning(threadId, true);
1104
- const response = publicKey ? await this.config.backendApiRef.current.postChatMessage(
1488
+ const response = await this.config.backendApiRef.current.postChatMessage(
1105
1489
  backendThreadId,
1106
1490
  text,
1107
- publicKey
1108
- ) : await this.config.backendApiRef.current.postChatMessage(
1109
- backendThreadId,
1110
- text
1491
+ namespace,
1492
+ publicKey,
1493
+ apiKey
1111
1494
  );
1112
1495
  if (response == null ? void 0 : response.messages) {
1113
1496
  this.inbound(threadId, response.messages);
1114
1497
  }
1115
- if (((_c = response == null ? void 0 : response.system_events) == null ? void 0 : _c.length) && this.config.onSyncEvents) {
1498
+ if (((_f = response == null ? void 0 : response.system_events) == null ? void 0 : _f.length) && this.config.onSyncEvents) {
1116
1499
  this.config.onSyncEvents(backendThreadId, response.system_events);
1117
1500
  }
1118
1501
  if (response == null ? void 0 : response.is_processing) {
@@ -1126,26 +1509,23 @@ var MessageController = class {
1126
1509
  }
1127
1510
  }
1128
1511
  async flushPendingChat(threadId) {
1129
- var _a, _b;
1512
+ var _a, _b, _c, _d, _e;
1130
1513
  const backendState = this.config.backendStateRef.current;
1131
1514
  const pending = dequeuePendingChat(backendState, threadId);
1132
1515
  if (!pending.length) return;
1133
1516
  const backendThreadId = resolveThreadId(backendState, threadId);
1517
+ const namespace = this.config.getNamespace();
1134
1518
  const publicKey = (_b = (_a = this.config).getPublicKey) == null ? void 0 : _b.call(_a);
1519
+ const apiKey = (_e = (_d = (_c = this.config).getApiKey) == null ? void 0 : _d.call(_c)) != null ? _e : void 0;
1135
1520
  for (const text of pending) {
1136
1521
  try {
1137
- if (publicKey) {
1138
- await this.config.backendApiRef.current.postChatMessage(
1139
- backendThreadId,
1140
- text,
1141
- publicKey
1142
- );
1143
- } else {
1144
- await this.config.backendApiRef.current.postChatMessage(
1145
- backendThreadId,
1146
- text
1147
- );
1148
- }
1522
+ await this.config.backendApiRef.current.postChatMessage(
1523
+ backendThreadId,
1524
+ text,
1525
+ namespace,
1526
+ publicKey,
1527
+ apiKey
1528
+ );
1149
1529
  } catch (error) {
1150
1530
  console.error("Failed to send queued message:", error);
1151
1531
  }
@@ -1184,7 +1564,7 @@ var MessageController = class {
1184
1564
  }
1185
1565
  };
1186
1566
 
1187
- // src/runtime/polling-controller.ts
1567
+ // packages/react/src/runtime/polling-controller.ts
1188
1568
  var PollingController = class {
1189
1569
  constructor(config) {
1190
1570
  this.config = config;
@@ -1255,18 +1635,18 @@ var PollingController = class {
1255
1635
  }
1256
1636
  };
1257
1637
 
1258
- // src/runtime/orchestrator.ts
1638
+ // packages/react/src/runtime/orchestrator.ts
1259
1639
  function useRuntimeOrchestrator(backendApi, options) {
1260
1640
  const threadContext = useThreadContext();
1261
- const threadContextRef = useRef4(threadContext);
1641
+ const threadContextRef = useRef5(threadContext);
1262
1642
  threadContextRef.current = threadContext;
1263
- const backendApiRef = useRef4(backendApi);
1643
+ const backendApiRef = useRef5(backendApi);
1264
1644
  backendApiRef.current = backendApi;
1265
- const backendStateRef = useRef4(createBackendState());
1266
- const [isRunning, setIsRunning] = useState4(false);
1267
- const messageControllerRef = useRef4(null);
1268
- const pollingRef = useRef4(null);
1269
- const pendingFetches = useRef4(/* @__PURE__ */ new Set());
1645
+ const backendStateRef = useRef5(createBackendState());
1646
+ const [isRunning, setIsRunning] = useState5(false);
1647
+ const messageControllerRef = useRef5(null);
1648
+ const pollingRef = useRef5(null);
1649
+ const pendingFetches = useRef5(/* @__PURE__ */ new Set());
1270
1650
  if (!pollingRef.current) {
1271
1651
  pollingRef.current = new PollingController({
1272
1652
  backendApiRef,
@@ -1275,8 +1655,8 @@ function useRuntimeOrchestrator(backendApi, options) {
1275
1655
  var _a;
1276
1656
  (_a = messageControllerRef.current) == null ? void 0 : _a.inbound(threadId, msgs);
1277
1657
  },
1278
- onSyncEvents: options == null ? void 0 : options.onSyncEvents,
1279
- getUserState: options == null ? void 0 : options.getUserState,
1658
+ onSyncEvents: options.onSyncEvents,
1659
+ getUserState: options.getUserState,
1280
1660
  onStart: (threadId) => {
1281
1661
  if (threadContextRef.current.currentThreadId === threadId) {
1282
1662
  setIsRunning(true);
@@ -1296,11 +1676,13 @@ function useRuntimeOrchestrator(backendApi, options) {
1296
1676
  threadContextRef,
1297
1677
  polling: pollingRef.current,
1298
1678
  setGlobalIsRunning: setIsRunning,
1299
- getPublicKey: options == null ? void 0 : options.getPublicKey,
1300
- onSyncEvents: options == null ? void 0 : options.onSyncEvents
1679
+ getPublicKey: options.getPublicKey,
1680
+ getNamespace: options.getNamespace,
1681
+ getApiKey: options.getApiKey,
1682
+ onSyncEvents: options.onSyncEvents
1301
1683
  });
1302
1684
  }
1303
- const ensureInitialState = useCallback4(async (threadId) => {
1685
+ const ensureInitialState = useCallback5(async (threadId) => {
1304
1686
  var _a, _b, _c, _d;
1305
1687
  const backendState = backendStateRef.current;
1306
1688
  if (shouldSkipInitialFetch(backendState, threadId)) {
@@ -1320,13 +1702,13 @@ function useRuntimeOrchestrator(backendApi, options) {
1320
1702
  const backendThreadId = resolveThreadId(backendState, threadId);
1321
1703
  pendingFetches.current.add(threadId);
1322
1704
  try {
1323
- const userState = (_a = options == null ? void 0 : options.getUserState) == null ? void 0 : _a.call(options);
1705
+ const userState = (_a = options.getUserState) == null ? void 0 : _a.call(options);
1324
1706
  const state = await backendApiRef.current.fetchState(
1325
1707
  backendThreadId,
1326
1708
  userState
1327
1709
  );
1328
1710
  (_b = messageControllerRef.current) == null ? void 0 : _b.inbound(threadId, state.messages);
1329
- if (((_c = state.system_events) == null ? void 0 : _c.length) && (options == null ? void 0 : options.onSyncEvents)) {
1711
+ if (((_c = state.system_events) == null ? void 0 : _c.length) && options.onSyncEvents) {
1330
1712
  options.onSyncEvents(backendThreadId, state.system_events);
1331
1713
  }
1332
1714
  if (threadContextRef.current.currentThreadId === threadId) {
@@ -1357,7 +1739,7 @@ function useRuntimeOrchestrator(backendApi, options) {
1357
1739
  };
1358
1740
  }
1359
1741
 
1360
- // src/runtime/threadlist-adapter.ts
1742
+ // packages/react/src/runtime/threadlist-adapter.ts
1361
1743
  var sortByLastActiveDesc = ([, metaA], [, metaB]) => {
1362
1744
  const tsA = parseTimestamp(metaA.lastActiveAt);
1363
1745
  const tsB = parseTimestamp(metaB.lastActiveAt);
@@ -1390,7 +1772,9 @@ function buildThreadListAdapter({
1390
1772
  currentThreadIdRef,
1391
1773
  polling,
1392
1774
  userAddress,
1393
- setIsRunning
1775
+ setIsRunning,
1776
+ getNamespace,
1777
+ getApiKey
1394
1778
  }) {
1395
1779
  const backendState = backendStateRef.current;
1396
1780
  const { regularThreads, archivedThreads } = buildThreadLists(
@@ -1418,7 +1802,8 @@ function buildThreadListAdapter({
1418
1802
  (prev) => new Map(prev).set(threadId, {
1419
1803
  title: "New Chat",
1420
1804
  status: "pending",
1421
- lastActiveAt: (/* @__PURE__ */ new Date()).toISOString()
1805
+ lastActiveAt: (/* @__PURE__ */ new Date()).toISOString(),
1806
+ control: initThreadControl()
1422
1807
  })
1423
1808
  );
1424
1809
  threadContext.setThreadMessages(threadId, []);
@@ -1445,15 +1830,13 @@ function buildThreadListAdapter({
1445
1830
  return;
1446
1831
  }
1447
1832
  if (backendState.createThreadPromise) {
1448
- preparePendingThread(
1449
- (_a = backendState.creatingThreadId) != null ? _a : crypto.randomUUID()
1450
- );
1833
+ preparePendingThread((_a = backendState.creatingThreadId) != null ? _a : generateUUID());
1451
1834
  return;
1452
1835
  }
1453
- const threadId = crypto.randomUUID();
1836
+ const threadId = generateUUID();
1454
1837
  preparePendingThread(threadId);
1455
1838
  const createPromise = backendApiRef.current.createThread(threadId, userAddress).then(async (newThread) => {
1456
- var _a2;
1839
+ var _a2, _b;
1457
1840
  const uiThreadId = (_a2 = backendState.creatingThreadId) != null ? _a2 : threadId;
1458
1841
  const backendId = newThread.session_id;
1459
1842
  if (uiThreadId !== backendId) {
@@ -1464,14 +1847,15 @@ function buildThreadListAdapter({
1464
1847
  }
1465
1848
  markSkipInitialFetch(backendState, uiThreadId);
1466
1849
  threadContext.setThreadMetadata((prev) => {
1467
- var _a3, _b;
1850
+ var _a3, _b2, _c;
1468
1851
  const next = new Map(prev);
1469
1852
  const existing = next.get(uiThreadId);
1470
1853
  const nextStatus = (existing == null ? void 0 : existing.status) === "archived" ? "archived" : "regular";
1471
1854
  next.set(uiThreadId, {
1472
1855
  title: (_a3 = existing == null ? void 0 : existing.title) != null ? _a3 : "New Chat",
1473
1856
  status: nextStatus,
1474
- lastActiveAt: (_b = existing == null ? void 0 : existing.lastActiveAt) != null ? _b : (/* @__PURE__ */ new Date()).toISOString()
1857
+ lastActiveAt: (_b2 = existing == null ? void 0 : existing.lastActiveAt) != null ? _b2 : (/* @__PURE__ */ new Date()).toISOString(),
1858
+ control: (_c = existing == null ? void 0 : existing.control) != null ? _c : initThreadControl()
1475
1859
  });
1476
1860
  return next;
1477
1861
  });
@@ -1481,9 +1865,17 @@ function buildThreadListAdapter({
1481
1865
  const pendingMessages = backendState.pendingChat.get(uiThreadId);
1482
1866
  if (pendingMessages == null ? void 0 : pendingMessages.length) {
1483
1867
  backendState.pendingChat.delete(uiThreadId);
1868
+ const namespace = getNamespace();
1869
+ const apiKey = (_b = getApiKey == null ? void 0 : getApiKey()) != null ? _b : void 0;
1484
1870
  for (const text of pendingMessages) {
1485
1871
  try {
1486
- await backendApiRef.current.postChatMessage(backendId, text);
1872
+ await backendApiRef.current.postChatMessage(
1873
+ backendId,
1874
+ text,
1875
+ namespace,
1876
+ userAddress,
1877
+ apiKey
1878
+ );
1487
1879
  } catch (error) {
1488
1880
  console.error("Failed to send queued message:", error);
1489
1881
  }
@@ -1582,7 +1974,8 @@ function buildThreadListAdapter({
1582
1974
  (prev) => new Map(prev).set(defaultId, {
1583
1975
  title: "New Chat",
1584
1976
  status: "regular",
1585
- lastActiveAt: (/* @__PURE__ */ new Date()).toISOString()
1977
+ lastActiveAt: (/* @__PURE__ */ new Date()).toISOString(),
1978
+ control: initThreadControl()
1586
1979
  })
1587
1980
  );
1588
1981
  threadContext.setThreadMessages(defaultId, []);
@@ -1597,12 +1990,12 @@ function buildThreadListAdapter({
1597
1990
  };
1598
1991
  }
1599
1992
 
1600
- // src/interface.tsx
1601
- import { createContext as createContext5, useContext as useContext5 } from "react";
1602
- var AomiRuntimeContext = createContext5(null);
1993
+ // packages/react/src/interface.tsx
1994
+ import { createContext as createContext6, useContext as useContext6 } from "react";
1995
+ var AomiRuntimeContext = createContext6(null);
1603
1996
  var AomiRuntimeApiProvider = AomiRuntimeContext.Provider;
1604
1997
  function useAomiRuntime() {
1605
- const context = useContext5(AomiRuntimeContext);
1998
+ const context = useContext6(AomiRuntimeContext);
1606
1999
  if (!context) {
1607
2000
  throw new Error(
1608
2001
  "useAomiRuntime must be used within AomiRuntimeProvider. Wrap your app with <AomiRuntimeProvider>...</AomiRuntimeProvider>"
@@ -1611,8 +2004,8 @@ function useAomiRuntime() {
1611
2004
  return context;
1612
2005
  }
1613
2006
 
1614
- // src/runtime/core.tsx
1615
- import { jsx as jsx5 } from "react/jsx-runtime";
2007
+ // packages/react/src/runtime/core.tsx
2008
+ import { jsx as jsx6 } from "react/jsx-runtime";
1616
2009
  function AomiRuntimeCore({
1617
2010
  children,
1618
2011
  backendApi
@@ -1622,6 +2015,7 @@ function AomiRuntimeCore({
1622
2015
  const notificationContext = useNotification();
1623
2016
  const { dispatchInboundSystem: dispatchSystemEvents } = eventContext;
1624
2017
  const { user, onUserStateChange, getUserState } = useUser();
2018
+ const { getControlState, getCurrentThreadControl } = useControl();
1625
2019
  const {
1626
2020
  backendStateRef,
1627
2021
  polling,
@@ -1633,9 +2027,14 @@ function AomiRuntimeCore({
1633
2027
  } = useRuntimeOrchestrator(backendApi, {
1634
2028
  onSyncEvents: dispatchSystemEvents,
1635
2029
  getPublicKey: () => getUserState().address,
1636
- getUserState
2030
+ getUserState,
2031
+ getNamespace: () => {
2032
+ var _a, _b;
2033
+ return (_b = (_a = getCurrentThreadControl().namespace) != null ? _a : getControlState().defaultNamespace) != null ? _b : "default";
2034
+ },
2035
+ getApiKey: () => getControlState().apiKey
1637
2036
  });
1638
- useEffect2(() => {
2037
+ useEffect3(() => {
1639
2038
  const unsubscribe = onUserStateChange(async (newUser) => {
1640
2039
  const sessionId = threadContext.currentThreadId;
1641
2040
  const message = JSON.stringify({
@@ -1651,19 +2050,30 @@ function AomiRuntimeCore({
1651
2050
  });
1652
2051
  return unsubscribe;
1653
2052
  }, [onUserStateChange, backendApiRef, threadContext.currentThreadId]);
1654
- const threadContextRef = useRef5(threadContext);
2053
+ const threadContextRef = useRef6(threadContext);
1655
2054
  threadContextRef.current = threadContext;
1656
- const currentThreadIdRef = useRef5(threadContext.currentThreadId);
1657
- useEffect2(() => {
2055
+ const currentThreadIdRef = useRef6(threadContext.currentThreadId);
2056
+ useEffect3(() => {
1658
2057
  currentThreadIdRef.current = threadContext.currentThreadId;
1659
2058
  }, [threadContext.currentThreadId]);
1660
- useEffect2(() => {
2059
+ useEffect3(() => {
1661
2060
  void ensureInitialState(threadContext.currentThreadId);
1662
2061
  }, [ensureInitialState, threadContext.currentThreadId]);
1663
- useEffect2(() => {
2062
+ useEffect3(() => {
1664
2063
  const threadId = threadContext.currentThreadId;
1665
2064
  setIsRunning(isThreadRunning(backendStateRef.current, threadId));
1666
2065
  }, [backendStateRef, setIsRunning, threadContext.currentThreadId]);
2066
+ useEffect3(() => {
2067
+ const threadId = threadContext.currentThreadId;
2068
+ const currentMeta = threadContext.getThreadMetadata(threadId);
2069
+ if (currentMeta && currentMeta.control.isProcessing !== isRunning) {
2070
+ threadContext.updateThreadMetadata(threadId, {
2071
+ control: __spreadProps(__spreadValues({}, currentMeta.control), {
2072
+ isProcessing: isRunning
2073
+ })
2074
+ });
2075
+ }
2076
+ }, [isRunning, threadContext]);
1667
2077
  const currentMessages = threadContext.getThreadMessages(
1668
2078
  threadContext.currentThreadId
1669
2079
  );
@@ -1675,11 +2085,11 @@ function AomiRuntimeCore({
1675
2085
  threadContext.allThreadsMetadata
1676
2086
  ]
1677
2087
  );
1678
- useEffect2(() => {
2088
+ useEffect3(() => {
1679
2089
  const userAddress = user.address;
1680
2090
  if (!userAddress) return;
1681
2091
  const fetchThreadList = async () => {
1682
- var _a, _b;
2092
+ var _a, _b, _c;
1683
2093
  try {
1684
2094
  const threadList = await backendApiRef.current.fetchThreads(userAddress);
1685
2095
  const currentContext = threadContextRef.current;
@@ -1689,10 +2099,12 @@ function AomiRuntimeCore({
1689
2099
  const rawTitle = (_a = thread.title) != null ? _a : "";
1690
2100
  const title = isPlaceholderTitle(rawTitle) ? "" : rawTitle;
1691
2101
  const lastActive = ((_b = newMetadata.get(thread.session_id)) == null ? void 0 : _b.lastActiveAt) || (/* @__PURE__ */ new Date()).toISOString();
2102
+ const existingControl = (_c = newMetadata.get(thread.session_id)) == null ? void 0 : _c.control;
1692
2103
  newMetadata.set(thread.session_id, {
1693
2104
  title,
1694
2105
  status: thread.is_archived ? "archived" : "regular",
1695
- lastActiveAt: lastActive
2106
+ lastActiveAt: lastActive,
2107
+ control: existingControl != null ? existingControl : initThreadControl()
1696
2108
  });
1697
2109
  const match = title.match(/^Chat (\d+)$/);
1698
2110
  if (match) {
@@ -1720,7 +2132,12 @@ function AomiRuntimeCore({
1720
2132
  currentThreadIdRef,
1721
2133
  polling,
1722
2134
  userAddress: user.address,
1723
- setIsRunning
2135
+ setIsRunning,
2136
+ getNamespace: () => {
2137
+ var _a, _b;
2138
+ return (_b = (_a = getCurrentThreadControl().namespace) != null ? _a : getControlState().defaultNamespace) != null ? _b : "default";
2139
+ },
2140
+ getApiKey: () => getControlState().apiKey
1724
2141
  }),
1725
2142
  [
1726
2143
  backendApiRef,
@@ -1730,10 +2147,11 @@ function AomiRuntimeCore({
1730
2147
  setIsRunning,
1731
2148
  threadContext,
1732
2149
  threadContext.currentThreadId,
1733
- threadContext.allThreadsMetadata
2150
+ threadContext.allThreadsMetadata,
2151
+ getControlState
1734
2152
  ]
1735
2153
  );
1736
- useEffect2(() => {
2154
+ useEffect3(() => {
1737
2155
  const backendState = backendStateRef.current;
1738
2156
  const currentSessionId = threadContext.currentThreadId;
1739
2157
  if (process.env.NODE_ENV !== "production") {
@@ -1764,14 +2182,15 @@ function AomiRuntimeCore({
1764
2182
  });
1765
2183
  }
1766
2184
  threadContextRef.current.setThreadMetadata((prev) => {
1767
- var _a;
2185
+ var _a, _b;
1768
2186
  const next = new Map(prev);
1769
2187
  const existing = next.get(targetThreadId);
1770
2188
  const nextStatus = (existing == null ? void 0 : existing.status) === "archived" ? "archived" : "regular";
1771
2189
  next.set(targetThreadId, {
1772
2190
  title: normalizedTitle,
1773
2191
  status: nextStatus,
1774
- lastActiveAt: (_a = existing == null ? void 0 : existing.lastActiveAt) != null ? _a : (/* @__PURE__ */ new Date()).toISOString()
2192
+ lastActiveAt: (_a = existing == null ? void 0 : existing.lastActiveAt) != null ? _a : (/* @__PURE__ */ new Date()).toISOString(),
2193
+ control: (_b = existing == null ? void 0 : existing.control) != null ? _b : initThreadControl()
1775
2194
  });
1776
2195
  return next;
1777
2196
  });
@@ -1790,12 +2209,12 @@ function AomiRuntimeCore({
1790
2209
  threadContext.currentThreadId,
1791
2210
  resolvedSessionId
1792
2211
  ]);
1793
- useEffect2(() => {
2212
+ useEffect3(() => {
1794
2213
  const threadId = threadContext.currentThreadId;
1795
2214
  if (!isThreadReady(backendStateRef.current, threadId)) return;
1796
2215
  void messageController.flushPendingChat(threadId);
1797
2216
  }, [messageController, backendStateRef, threadContext.currentThreadId]);
1798
- useEffect2(() => {
2217
+ useEffect3(() => {
1799
2218
  const showToolNotification = (eventType) => (event) => {
1800
2219
  const payload = event.payload;
1801
2220
  const toolName = typeof (payload == null ? void 0 : payload.tool_name) === "string" ? payload.tool_name : void 0;
@@ -1820,15 +2239,10 @@ function AomiRuntimeCore({
1820
2239
  unsubscribeComplete();
1821
2240
  };
1822
2241
  }, [eventContext, notificationContext]);
1823
- useEffect2(() => {
2242
+ useEffect3(() => {
1824
2243
  const unsubscribe = eventContext.subscribe("system_notice", (event) => {
1825
2244
  const payload = event.payload;
1826
2245
  const message = payload == null ? void 0 : payload.message;
1827
- notificationContext.showNotification({
1828
- type: "notice",
1829
- title: "System notice",
1830
- message
1831
- });
1832
2246
  });
1833
2247
  return unsubscribe;
1834
2248
  }, [eventContext, notificationContext]);
@@ -1841,13 +2255,13 @@ function AomiRuntimeCore({
1841
2255
  convertMessage: (msg) => msg,
1842
2256
  adapters: { threadList: threadListAdapter }
1843
2257
  });
1844
- useEffect2(() => {
2258
+ useEffect3(() => {
1845
2259
  return () => {
1846
2260
  polling.stopAll();
1847
2261
  };
1848
2262
  }, [polling]);
1849
2263
  const userContext = useUser();
1850
- const sendMessage = useCallback5(
2264
+ const sendMessage = useCallback6(
1851
2265
  async (text) => {
1852
2266
  const appendMessage = {
1853
2267
  role: "user",
@@ -1860,39 +2274,39 @@ function AomiRuntimeCore({
1860
2274
  },
1861
2275
  [messageController, threadContext.currentThreadId]
1862
2276
  );
1863
- const cancelGeneration = useCallback5(() => {
2277
+ const cancelGeneration = useCallback6(() => {
1864
2278
  messageController.cancel(threadContext.currentThreadId);
1865
2279
  }, [messageController, threadContext.currentThreadId]);
1866
- const getMessages = useCallback5(
2280
+ const getMessages = useCallback6(
1867
2281
  (threadId) => {
1868
2282
  const id = threadId != null ? threadId : threadContext.currentThreadId;
1869
2283
  return threadContext.getThreadMessages(id);
1870
2284
  },
1871
2285
  [threadContext]
1872
2286
  );
1873
- const createThread = useCallback5(async () => {
2287
+ const createThread = useCallback6(async () => {
1874
2288
  await threadListAdapter.onSwitchToNewThread();
1875
2289
  return threadContextRef.current.currentThreadId;
1876
2290
  }, [threadListAdapter]);
1877
- const deleteThread = useCallback5(
2291
+ const deleteThread = useCallback6(
1878
2292
  async (threadId) => {
1879
2293
  await threadListAdapter.onDelete(threadId);
1880
2294
  },
1881
2295
  [threadListAdapter]
1882
2296
  );
1883
- const renameThread = useCallback5(
2297
+ const renameThread = useCallback6(
1884
2298
  async (threadId, title) => {
1885
2299
  await threadListAdapter.onRename(threadId, title);
1886
2300
  },
1887
2301
  [threadListAdapter]
1888
2302
  );
1889
- const archiveThread = useCallback5(
2303
+ const archiveThread = useCallback6(
1890
2304
  async (threadId) => {
1891
2305
  await threadListAdapter.onArchive(threadId);
1892
2306
  },
1893
2307
  [threadListAdapter]
1894
2308
  );
1895
- const selectThread = useCallback5(
2309
+ const selectThread = useCallback6(
1896
2310
  (threadId) => {
1897
2311
  if (threadContext.allThreadsMetadata.has(threadId)) {
1898
2312
  threadListAdapter.onSwitchToThread(threadId);
@@ -1953,45 +2367,57 @@ function AomiRuntimeCore({
1953
2367
  eventContext
1954
2368
  ]
1955
2369
  );
1956
- return /* @__PURE__ */ jsx5(AomiRuntimeApiProvider, { value: aomiRuntimeApi, children: /* @__PURE__ */ jsx5(AssistantRuntimeProvider, { runtime, children }) });
2370
+ return /* @__PURE__ */ jsx6(AomiRuntimeApiProvider, { value: aomiRuntimeApi, children: /* @__PURE__ */ jsx6(AssistantRuntimeProvider, { runtime, children }) });
1957
2371
  }
1958
2372
 
1959
- // src/runtime/aomi-runtime.tsx
1960
- import { jsx as jsx6 } from "react/jsx-runtime";
2373
+ // packages/react/src/runtime/aomi-runtime.tsx
2374
+ import { jsx as jsx7 } from "react/jsx-runtime";
1961
2375
  function AomiRuntimeProvider({
1962
2376
  children,
1963
2377
  backendUrl = "http://localhost:8080"
1964
2378
  }) {
1965
2379
  const backendApi = useMemo3(() => new BackendApi(backendUrl), [backendUrl]);
1966
- return /* @__PURE__ */ jsx6(ThreadContextProvider, { children: /* @__PURE__ */ jsx6(NotificationContextProvider, { children: /* @__PURE__ */ jsx6(UserContextProvider, { children: /* @__PURE__ */ jsx6(AomiRuntimeInner, { backendApi, children }) }) }) });
2380
+ return /* @__PURE__ */ jsx7(ThreadContextProvider, { children: /* @__PURE__ */ jsx7(NotificationContextProvider, { children: /* @__PURE__ */ jsx7(UserContextProvider, { children: /* @__PURE__ */ jsx7(AomiRuntimeInner, { backendApi, children }) }) }) });
1967
2381
  }
1968
2382
  function AomiRuntimeInner({
1969
2383
  children,
1970
2384
  backendApi
1971
2385
  }) {
2386
+ var _a;
1972
2387
  const threadContext = useThreadContext();
1973
- return /* @__PURE__ */ jsx6(
1974
- EventContextProvider,
2388
+ const { user } = useUser();
2389
+ return /* @__PURE__ */ jsx7(
2390
+ ControlContextProvider,
1975
2391
  {
1976
2392
  backendApi,
1977
2393
  sessionId: threadContext.currentThreadId,
1978
- children: /* @__PURE__ */ jsx6(AomiRuntimeCore, { backendApi, children })
2394
+ publicKey: (_a = user.address) != null ? _a : void 0,
2395
+ getThreadMetadata: threadContext.getThreadMetadata,
2396
+ updateThreadMetadata: threadContext.updateThreadMetadata,
2397
+ children: /* @__PURE__ */ jsx7(
2398
+ EventContextProvider,
2399
+ {
2400
+ backendApi,
2401
+ sessionId: threadContext.currentThreadId,
2402
+ children: /* @__PURE__ */ jsx7(AomiRuntimeCore, { backendApi, children })
2403
+ }
2404
+ )
1979
2405
  }
1980
2406
  );
1981
2407
  }
1982
2408
 
1983
- // src/handlers/wallet-handler.ts
1984
- import { useCallback as useCallback6, useEffect as useEffect3, useState as useState5 } from "react";
2409
+ // packages/react/src/handlers/wallet-handler.ts
2410
+ import { useCallback as useCallback7, useEffect as useEffect4, useState as useState6 } from "react";
1985
2411
  function useWalletHandler({
1986
2412
  sessionId,
1987
2413
  onTxRequest
1988
2414
  }) {
1989
2415
  const { subscribe: subscribe2, sendOutboundSystem: sendOutbound } = useEventContext();
1990
2416
  const { setUser, getUserState } = useUser();
1991
- const [pendingTxRequests, setPendingTxRequests] = useState5(
2417
+ const [pendingTxRequests, setPendingTxRequests] = useState6(
1992
2418
  []
1993
2419
  );
1994
- useEffect3(() => {
2420
+ useEffect4(() => {
1995
2421
  const unsubscribe = subscribe2(
1996
2422
  "wallet_tx_request",
1997
2423
  (event) => {
@@ -2002,7 +2428,7 @@ function useWalletHandler({
2002
2428
  );
2003
2429
  return unsubscribe;
2004
2430
  }, [subscribe2, onTxRequest]);
2005
- useEffect3(() => {
2431
+ useEffect4(() => {
2006
2432
  const unsubscribe = subscribe2(
2007
2433
  "user_state_request",
2008
2434
  (event) => {
@@ -2015,7 +2441,7 @@ function useWalletHandler({
2015
2441
  );
2016
2442
  return unsubscribe;
2017
2443
  }, [subscribe2, onTxRequest]);
2018
- const sendTxComplete = useCallback6(
2444
+ const sendTxComplete = useCallback7(
2019
2445
  (tx) => {
2020
2446
  sendOutbound({
2021
2447
  type: "wallet:tx_complete",
@@ -2025,7 +2451,7 @@ function useWalletHandler({
2025
2451
  },
2026
2452
  [sendOutbound, sessionId]
2027
2453
  );
2028
- const sendConnectionChange = useCallback6(
2454
+ const sendConnectionChange = useCallback7(
2029
2455
  (status, address, chainId) => {
2030
2456
  if (status === "connected") {
2031
2457
  setUser({
@@ -2048,7 +2474,7 @@ function useWalletHandler({
2048
2474
  },
2049
2475
  [setUser, sendOutbound, sessionId]
2050
2476
  );
2051
- const clearTxRequest = useCallback6((index) => {
2477
+ const clearTxRequest = useCallback7((index) => {
2052
2478
  setPendingTxRequests((prev) => prev.filter((_, i) => i !== index));
2053
2479
  }, []);
2054
2480
  return {
@@ -2059,8 +2485,8 @@ function useWalletHandler({
2059
2485
  };
2060
2486
  }
2061
2487
 
2062
- // src/handlers/notification-handler.ts
2063
- import { useCallback as useCallback7, useEffect as useEffect4, useState as useState6 } from "react";
2488
+ // packages/react/src/handlers/notification-handler.ts
2489
+ import { useCallback as useCallback8, useEffect as useEffect5, useState as useState7 } from "react";
2064
2490
  var notificationIdCounter2 = 0;
2065
2491
  function generateNotificationId() {
2066
2492
  return `notif-${Date.now()}-${++notificationIdCounter2}`;
@@ -2069,8 +2495,8 @@ function useNotificationHandler({
2069
2495
  onNotification
2070
2496
  } = {}) {
2071
2497
  const { subscribe: subscribe2 } = useEventContext();
2072
- const [notifications, setNotifications] = useState6([]);
2073
- useEffect4(() => {
2498
+ const [notifications, setNotifications] = useState7([]);
2499
+ useEffect5(() => {
2074
2500
  const unsubscribe = subscribe2("notification", (event) => {
2075
2501
  var _a, _b;
2076
2502
  const payload = event.payload;
@@ -2089,7 +2515,7 @@ function useNotificationHandler({
2089
2515
  return unsubscribe;
2090
2516
  }, [subscribe2, onNotification]);
2091
2517
  const unhandledCount = notifications.filter((n) => !n.handled).length;
2092
- const markHandled = useCallback7((id) => {
2518
+ const markHandled = useCallback8((id) => {
2093
2519
  setNotifications(
2094
2520
  (prev) => prev.map((n) => n.id === id ? __spreadProps(__spreadValues({}, n), { handled: true }) : n)
2095
2521
  );
@@ -2103,6 +2529,7 @@ function useNotificationHandler({
2103
2529
  export {
2104
2530
  AomiRuntimeProvider,
2105
2531
  BackendApi,
2532
+ ControlContextProvider,
2106
2533
  EventContextProvider,
2107
2534
  NotificationContextProvider,
2108
2535
  ThreadContextProvider,
@@ -2110,7 +2537,9 @@ export {
2110
2537
  cn,
2111
2538
  formatAddress,
2112
2539
  getNetworkName,
2540
+ initThreadControl,
2113
2541
  useAomiRuntime,
2542
+ useControl,
2114
2543
  useCurrentThreadMessages,
2115
2544
  useCurrentThreadMetadata,
2116
2545
  useEventContext,