@autobe/ui 0.30.2 → 0.30.4-dev.20260324

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.
Files changed (69) hide show
  1. package/LICENSE +661 -661
  2. package/README.md +261 -0
  3. package/lib/components/AutoBeChatMain.d.ts +6 -0
  4. package/lib/components/AutoBeChatMain.js +46 -37
  5. package/lib/components/AutoBeChatMain.js.map +1 -1
  6. package/lib/components/AutoBeConfigModal.js +9 -9
  7. package/lib/components/events/AutoBeEventMovie.js +0 -4
  8. package/lib/components/events/AutoBeEventMovie.js.map +1 -1
  9. package/lib/components/events/AutoBeProgressEventMovie.js +0 -10
  10. package/lib/components/events/AutoBeProgressEventMovie.js.map +1 -1
  11. package/lib/components/upload/AutoBeChatUploadBox.d.ts +1 -0
  12. package/lib/components/upload/AutoBeChatUploadBox.js +11 -16
  13. package/lib/components/upload/AutoBeChatUploadBox.js.map +1 -1
  14. package/lib/context/AutoBeAgentContext.js +78 -30
  15. package/lib/context/AutoBeAgentContext.js.map +1 -1
  16. package/lib/context/SearchParamsContext.js +1 -1
  17. package/lib/context/SearchParamsContext.js.map +1 -1
  18. package/lib/structure/AutoBeListener.d.ts +1 -0
  19. package/lib/structure/AutoBeListener.js +9 -11
  20. package/lib/structure/AutoBeListener.js.map +1 -1
  21. package/package.json +2 -2
  22. package/src/components/AutoBeAssistantMessageMovie.tsx +22 -22
  23. package/src/components/AutoBeChatMain.tsx +394 -376
  24. package/src/components/AutoBeChatSidebar.tsx +414 -414
  25. package/src/components/AutoBeConfigButton.tsx +83 -83
  26. package/src/components/AutoBeConfigModal.tsx +443 -443
  27. package/src/components/AutoBeStatusButton.tsx +75 -75
  28. package/src/components/AutoBeStatusModal.tsx +486 -486
  29. package/src/components/AutoBeUserMessageMovie.tsx +27 -27
  30. package/src/components/common/ActionButton.tsx +205 -205
  31. package/src/components/common/ActionButtonGroup.tsx +80 -80
  32. package/src/components/common/AutoBeConfigInput.tsx +185 -185
  33. package/src/components/common/ChatBubble.tsx +119 -119
  34. package/src/components/common/Collapsible.tsx +95 -95
  35. package/src/components/common/CompactSessionIndicator.tsx +73 -73
  36. package/src/components/common/CompactSessionList.tsx +82 -82
  37. package/src/components/common/openai/OpenAIContent.tsx +53 -53
  38. package/src/components/common/openai/OpenAIUserAudioContent.tsx +70 -70
  39. package/src/components/common/openai/OpenAIUserFileContent.tsx +76 -76
  40. package/src/components/common/openai/OpenAIUserImageContent.tsx +34 -34
  41. package/src/components/common/openai/OpenAIUserTextContent.tsx +15 -15
  42. package/src/components/events/AutoBeCompleteEventMovie.tsx +402 -402
  43. package/src/components/events/AutoBeCorrectEventMovie.tsx +354 -354
  44. package/src/components/events/AutoBeEventGroupMovie.tsx +18 -18
  45. package/src/components/events/AutoBeEventMovie.tsx +154 -158
  46. package/src/components/events/AutoBeProgressEventMovie.tsx +207 -217
  47. package/src/components/events/AutoBeScenarioEventMovie.tsx +135 -135
  48. package/src/components/events/AutoBeStartEventMovie.tsx +82 -82
  49. package/src/components/events/AutoBeValidateEventMovie.tsx +249 -249
  50. package/src/components/events/README.md +300 -300
  51. package/src/components/events/common/CollapsibleEventGroup.tsx +211 -211
  52. package/src/components/events/common/EventCard.tsx +61 -61
  53. package/src/components/events/common/EventContent.tsx +31 -31
  54. package/src/components/events/common/EventHeader.tsx +85 -85
  55. package/src/components/events/common/EventIcon.tsx +82 -82
  56. package/src/components/events/common/ProgressBar.tsx +64 -64
  57. package/src/components/events/groups/CorrectEventGroup.tsx +183 -183
  58. package/src/components/events/groups/ValidateEventGroup.tsx +143 -143
  59. package/src/components/events/utils/eventGrouper.tsx +116 -116
  60. package/src/components/upload/AutoBeChatUploadBox.tsx +433 -425
  61. package/src/components/upload/AutoBeChatUploadSendButton.tsx +66 -66
  62. package/src/components/upload/AutoBeFileUploadBox.tsx +123 -123
  63. package/src/components/upload/AutoBeVoiceRecoderButton.tsx +100 -100
  64. package/src/context/AutoBeAgentContext.tsx +301 -245
  65. package/src/context/AutoBeAgentSessionList.tsx +58 -58
  66. package/src/context/SearchParamsContext.tsx +49 -49
  67. package/src/icons/Receipt.tsx +74 -74
  68. package/src/structure/AutoBeListener.ts +368 -373
  69. package/tsconfig.json +9 -9
@@ -1,245 +1,301 @@
1
- import { IAutoBeRpcService, IAutoBeTokenUsageJson } from "@autobe/interface";
2
- import {
3
- ReactNode,
4
- createContext,
5
- useCallback,
6
- useContext,
7
- useEffect,
8
- useState,
9
- } from "react";
10
-
11
- import {
12
- AutoBeListener,
13
- AutoBeListenerState,
14
- IAutoBeAgentSessionStorageStrategy,
15
- IAutoBeEventGroup,
16
- } from "../structure";
17
- import { IAutoBeConfig } from "../types/config";
18
- import { useAutoBeAgentSessionList } from "./AutoBeAgentSessionList";
19
- import { useSearchParams } from "./SearchParamsContext";
20
-
21
- export interface IAutoBeServiceData {
22
- service: IAutoBeRpcService;
23
- listener: AutoBeListener;
24
- close: () => void | Promise<void>;
25
- sessionId: string;
26
- }
27
-
28
- export type AutoBeServiceFactory = (
29
- config: IAutoBeConfig,
30
- ) => Promise<IAutoBeServiceData>;
31
-
32
- export type AutoBeConnectionStatus =
33
- | "disconnected"
34
- | "connecting"
35
- | "connected";
36
-
37
- interface AutoBeAgentContextType {
38
- // Service state
39
- connectionStatus: AutoBeConnectionStatus;
40
-
41
- // Service data (available when ready)
42
- eventGroups: IAutoBeEventGroup[];
43
- tokenUsage: IAutoBeTokenUsageJson | null;
44
- state: AutoBeListenerState | null;
45
- service: IAutoBeRpcService | null;
46
- listener: AutoBeListener | null;
47
-
48
- // Service management
49
- getAutoBeService: (config?: IAutoBeConfig) => Promise<IAutoBeServiceData>;
50
- resetService: () => void;
51
- }
52
-
53
- const AutoBeAgentContext = createContext<AutoBeAgentContextType | null>(null);
54
-
55
- export function AutoBeAgentProvider({
56
- children,
57
- serviceFactory,
58
- storageStrategy,
59
- }: {
60
- serviceFactory: AutoBeServiceFactory;
61
- children: ReactNode;
62
- storageStrategy: IAutoBeAgentSessionStorageStrategy;
63
- }) {
64
- // Service state
65
- const [connectionStatus, setConnectionStatus] =
66
- useState<AutoBeConnectionStatus>("disconnected");
67
-
68
- // Service data
69
- const { searchParams, setSearchParams } = useSearchParams();
70
- // Use URL parameter for conversation ID - enables bookmark/share support
71
- const activeConversationId = searchParams.get("session-id") ?? null;
72
-
73
- const [tokenUsage, setTokenUsage] = useState<IAutoBeTokenUsageJson | null>(
74
- null,
75
- );
76
- const [eventGroups, setEventGroups] = useState<IAutoBeEventGroup[]>([]);
77
-
78
- // Context-scoped service instance (contains service, listener, header)
79
- const [serviceInstance, setServiceInstance] =
80
- useState<IAutoBeServiceData | null>(null);
81
-
82
- const { refreshSessionList } = useAutoBeAgentSessionList();
83
- // Context-scoped service getter
84
- const getAutoBeService = useCallback(
85
- async (
86
- config: IAutoBeConfig = {} as IAutoBeConfig,
87
- ): Promise<IAutoBeServiceData> => {
88
- // Return existing instance if available
89
- if (serviceInstance && connectionStatus === "connected") {
90
- return serviceInstance;
91
- }
92
-
93
- // Prevent multiple concurrent creations
94
- if (connectionStatus === "connecting") {
95
- throw new Error("Service is already connecting. Please wait.");
96
- }
97
-
98
- if (!serviceFactory) {
99
- throw new Error("No service factory provided. Cannot create service.");
100
- }
101
-
102
- try {
103
- setConnectionStatus("connecting");
104
-
105
- // Create new service instance
106
- const newServiceData = await serviceFactory({
107
- ...config,
108
- sessionId: activeConversationId,
109
- });
110
- setServiceInstance(newServiceData);
111
-
112
- setSearchParams((sp) => {
113
- const newSp = new URLSearchParams(sp);
114
- newSp.set("session-id", newServiceData.sessionId);
115
- return newSp;
116
- });
117
- setConnectionStatus("connected");
118
-
119
- return newServiceData;
120
- } catch (error) {
121
- setConnectionStatus("disconnected");
122
- throw error;
123
- }
124
- },
125
- [
126
- serviceFactory,
127
- serviceInstance,
128
- connectionStatus,
129
- activeConversationId,
130
- searchParams,
131
- ],
132
- );
133
-
134
- // Reset service (for reconnection, etc.)
135
- const resetService = useCallback(() => {
136
- setServiceInstance(null);
137
- setConnectionStatus("disconnected");
138
- setEventGroups([]);
139
- setTokenUsage(null);
140
- }, []);
141
-
142
- useEffect(() => {
143
- if (activeConversationId === null) {
144
- setEventGroups([]);
145
- setTokenUsage(null);
146
- return;
147
- }
148
-
149
- storageStrategy
150
- .getSession({
151
- id: activeConversationId,
152
- })
153
- .then((v) => {
154
- if (v === null) {
155
- return null;
156
- }
157
- refreshSessionList();
158
- setEventGroups(v.events);
159
- setTokenUsage(v.tokenUsage);
160
- })
161
- .catch(console.error);
162
- }, [activeConversationId]);
163
-
164
- useEffect(() => {
165
- if (serviceInstance === null) {
166
- return;
167
- }
168
-
169
- serviceInstance.listener.on(async (e) => {
170
- serviceInstance.service
171
- .getTokenUsage()
172
- .then(setTokenUsage)
173
- .catch(() => {});
174
- setEventGroups(e);
175
- });
176
-
177
- serviceInstance.service
178
- .getTokenUsage()
179
- .then(setTokenUsage)
180
- .catch(() => {});
181
- }, [serviceInstance]);
182
-
183
- useEffect(() => {
184
- if (activeConversationId === null || serviceInstance === null) {
185
- return;
186
- }
187
-
188
- const originConversate = serviceInstance.service.conversate;
189
- serviceInstance.service.conversate = async (content) => {
190
- const result = await originConversate(content);
191
- await storageStrategy.appendHistory({
192
- id: activeConversationId,
193
- history: result,
194
- });
195
- return result;
196
- };
197
-
198
- const registerEvent = async (e: IAutoBeEventGroup[]) => {
199
- await storageStrategy.appendEvent({
200
- id: activeConversationId,
201
- events: e,
202
- });
203
- await storageStrategy.setTokenUsage({
204
- id: activeConversationId,
205
- tokenUsage: await serviceInstance.service.getTokenUsage(),
206
- });
207
- };
208
-
209
- serviceInstance.listener.on(registerEvent);
210
- return () => {
211
- serviceInstance.service.conversate = originConversate;
212
- serviceInstance.listener.off(registerEvent);
213
- };
214
- }, [activeConversationId, serviceInstance]);
215
-
216
- return (
217
- <AutoBeAgentContext.Provider
218
- value={{
219
- // Service state
220
- connectionStatus,
221
-
222
- // Service data
223
- eventGroups,
224
- tokenUsage,
225
- state: serviceInstance?.listener?.getState() ?? null,
226
- service: serviceInstance?.service ?? null,
227
- listener: serviceInstance?.listener ?? null,
228
-
229
- // Service management
230
- getAutoBeService,
231
- resetService,
232
- }}
233
- >
234
- {children}
235
- </AutoBeAgentContext.Provider>
236
- );
237
- }
238
-
239
- export function useAutoBeAgent() {
240
- const context = useContext(AutoBeAgentContext);
241
- if (!context) {
242
- throw new Error("useAutoBeAgent must be used within a AutoBeAgentProvider");
243
- }
244
- return context;
245
- }
1
+ import { IAutoBeRpcService, IAutoBeTokenUsageJson } from "@autobe/interface";
2
+ import {
3
+ ReactNode,
4
+ createContext,
5
+ useCallback,
6
+ useContext,
7
+ useEffect,
8
+ useRef,
9
+ useState,
10
+ } from "react";
11
+
12
+ import {
13
+ AutoBeListener,
14
+ AutoBeListenerState,
15
+ IAutoBeAgentSessionStorageStrategy,
16
+ IAutoBeEventGroup,
17
+ } from "../structure";
18
+ import { IAutoBeConfig } from "../types/config";
19
+ import { useAutoBeAgentSessionList } from "./AutoBeAgentSessionList";
20
+ import { useSearchParams } from "./SearchParamsContext";
21
+
22
+ export interface IAutoBeServiceData {
23
+ service: IAutoBeRpcService;
24
+ listener: AutoBeListener;
25
+ close: () => void | Promise<void>;
26
+ sessionId: string;
27
+ }
28
+
29
+ export type AutoBeServiceFactory = (
30
+ config: IAutoBeConfig,
31
+ ) => Promise<IAutoBeServiceData>;
32
+
33
+ export type AutoBeConnectionStatus =
34
+ | "disconnected"
35
+ | "connecting"
36
+ | "connected";
37
+
38
+ interface AutoBeAgentContextType {
39
+ // Service state
40
+ connectionStatus: AutoBeConnectionStatus;
41
+
42
+ // Service data (available when ready)
43
+ eventGroups: IAutoBeEventGroup[];
44
+ tokenUsage: IAutoBeTokenUsageJson | null;
45
+ state: AutoBeListenerState | null;
46
+ service: IAutoBeRpcService | null;
47
+ listener: AutoBeListener | null;
48
+
49
+ // Service management
50
+ getAutoBeService: (config?: IAutoBeConfig) => Promise<IAutoBeServiceData>;
51
+ resetService: () => void;
52
+ }
53
+
54
+ const AutoBeAgentContext = createContext<AutoBeAgentContextType | null>(null);
55
+
56
+ export function AutoBeAgentProvider({
57
+ children,
58
+ serviceFactory,
59
+ storageStrategy,
60
+ }: {
61
+ serviceFactory: AutoBeServiceFactory;
62
+ children: ReactNode;
63
+ storageStrategy: IAutoBeAgentSessionStorageStrategy;
64
+ }) {
65
+ // Service state
66
+ const [connectionStatus, setConnectionStatus] =
67
+ useState<AutoBeConnectionStatus>("disconnected");
68
+
69
+ // Service data
70
+ const { searchParams, setSearchParams } = useSearchParams();
71
+ // Use URL parameter for conversation ID - enables bookmark/share support
72
+ const activeConversationId = searchParams.get("session-id") ?? null;
73
+
74
+ const [tokenUsage, setTokenUsage] = useState<IAutoBeTokenUsageJson | null>(
75
+ null,
76
+ );
77
+ const [eventGroups, setEventGroups] = useState<IAutoBeEventGroup[]>([]);
78
+
79
+ // Store service instance in a ref to avoid React dev mode inspecting
80
+ // the TGrid driver Proxy (which crashes on Symbol property access).
81
+ // connectionStatus state changes drive re-renders instead.
82
+ const serviceInstanceRef = useRef<IAutoBeServiceData | null>(null);
83
+
84
+ const { refreshSessionList } = useAutoBeAgentSessionList();
85
+ // Context-scoped service getter
86
+ const getAutoBeService = useCallback(
87
+ async (
88
+ config: IAutoBeConfig = {} as IAutoBeConfig,
89
+ ): Promise<IAutoBeServiceData> => {
90
+ // Return existing instance if available
91
+ if (serviceInstanceRef.current && connectionStatus === "connected") {
92
+ return serviceInstanceRef.current;
93
+ }
94
+
95
+ // Prevent multiple concurrent creations
96
+ if (connectionStatus === "connecting") {
97
+ throw new Error("Service is already connecting. Please wait.");
98
+ }
99
+
100
+ if (!serviceFactory) {
101
+ throw new Error("No service factory provided. Cannot create service.");
102
+ }
103
+
104
+ try {
105
+ setConnectionStatus("connecting");
106
+
107
+ // Create new service instance
108
+ const newServiceData = await serviceFactory({
109
+ ...config,
110
+ sessionId: activeConversationId,
111
+ });
112
+ // Wrap the TGrid driver proxy to handle Symbol access from
113
+ // React dev-mode's render logging without crashing.
114
+ newServiceData.service = wrapServiceProxy(newServiceData.service);
115
+ serviceInstanceRef.current = newServiceData;
116
+
117
+ setSearchParams((sp) => {
118
+ const newSp = new URLSearchParams(sp);
119
+ newSp.set("session-id", newServiceData.sessionId);
120
+ return newSp;
121
+ });
122
+ setConnectionStatus("connected");
123
+
124
+ return newServiceData;
125
+ } catch (error) {
126
+ setConnectionStatus("disconnected");
127
+ throw error;
128
+ }
129
+ },
130
+ [
131
+ serviceFactory,
132
+ connectionStatus,
133
+ activeConversationId,
134
+ searchParams,
135
+ ],
136
+ );
137
+
138
+ // Reset service (for reconnection, etc.)
139
+ const resetService = useCallback(() => {
140
+ serviceInstanceRef.current = null;
141
+ setConnectionStatus("disconnected");
142
+ setEventGroups([]);
143
+ setTokenUsage(null);
144
+ }, []);
145
+
146
+ useEffect(() => {
147
+ // Close existing connection when switching sessions,
148
+ // but skip if the current service already owns this session
149
+ // (happens when getAutoBeService just created it and set the URL).
150
+ const prev = serviceInstanceRef.current;
151
+ if (prev) {
152
+ if (prev.sessionId === activeConversationId) {
153
+ // Same session — do not tear down the connection we just created
154
+ return;
155
+ }
156
+ void Promise.resolve(prev.close()).catch(() => {});
157
+ serviceInstanceRef.current = null;
158
+ setConnectionStatus("disconnected");
159
+ }
160
+
161
+ // Clear stale events immediately
162
+ setEventGroups([]);
163
+ setTokenUsage(null);
164
+
165
+ if (activeConversationId === null) {
166
+ return;
167
+ }
168
+
169
+ storageStrategy
170
+ .getSession({
171
+ id: activeConversationId,
172
+ })
173
+ .then((v) => {
174
+ if (v === null) {
175
+ return null;
176
+ }
177
+ refreshSessionList();
178
+ // Avoid wiping live websocket replay events with empty storage data.
179
+ // Some strategies only persist histories/token usage and leave events
180
+ // empty, so replacing current groups here can erase already-delivered
181
+ // replay messages such as early userMessage events.
182
+ if (v.events.length > 0) {
183
+ setEventGroups(v.events);
184
+ }
185
+ setTokenUsage(v.tokenUsage);
186
+ })
187
+ .catch(console.error);
188
+ }, [activeConversationId]);
189
+
190
+ // Register listener when service connects
191
+ useEffect(() => {
192
+ const instance = serviceInstanceRef.current;
193
+ if (connectionStatus !== "connected" || instance === null) {
194
+ return;
195
+ }
196
+
197
+ const onEvent = async (e: IAutoBeEventGroup[]) => {
198
+ setEventGroups(e);
199
+ setTimeout(() => {
200
+ instance.service
201
+ .getTokenUsage()
202
+ .then(setTokenUsage)
203
+ .catch(() => {});
204
+ }, 0);
205
+ };
206
+
207
+ instance.listener.on(onEvent);
208
+
209
+ instance.service
210
+ .getTokenUsage()
211
+ .then(setTokenUsage)
212
+ .catch(() => {});
213
+
214
+ return () => {
215
+ instance.listener.off(onEvent);
216
+ };
217
+ }, [connectionStatus]);
218
+
219
+ useEffect(() => {
220
+ const instance = serviceInstanceRef.current;
221
+ if (activeConversationId === null || connectionStatus !== "connected" || instance === null) {
222
+ return;
223
+ }
224
+
225
+ const originConversate = instance.service.conversate;
226
+ instance.service.conversate = async (content) => {
227
+ const result = await originConversate(content);
228
+ await storageStrategy.appendHistory({
229
+ id: activeConversationId,
230
+ history: result,
231
+ });
232
+ return result;
233
+ };
234
+
235
+ const registerEvent = async (e: IAutoBeEventGroup[]) => {
236
+ await storageStrategy.appendEvent({
237
+ id: activeConversationId,
238
+ events: e,
239
+ });
240
+ await storageStrategy.setTokenUsage({
241
+ id: activeConversationId,
242
+ tokenUsage: await instance.service.getTokenUsage(),
243
+ });
244
+ };
245
+
246
+ instance.listener.on(registerEvent);
247
+ return () => {
248
+ instance.service.conversate = originConversate;
249
+ instance.listener.off(registerEvent);
250
+ };
251
+ }, [activeConversationId, connectionStatus]);
252
+
253
+ const currentInstance = serviceInstanceRef.current;
254
+
255
+ return (
256
+ <AutoBeAgentContext.Provider
257
+ value={{
258
+ // Service state
259
+ connectionStatus,
260
+
261
+ // Service data
262
+ eventGroups,
263
+ tokenUsage,
264
+ state: currentInstance?.listener?.getState() ?? null,
265
+ service: currentInstance?.service ?? null,
266
+ listener: currentInstance?.listener ?? null,
267
+
268
+ // Service management
269
+ getAutoBeService,
270
+ resetService,
271
+ }}
272
+ >
273
+ {children}
274
+ </AutoBeAgentContext.Provider>
275
+ );
276
+ }
277
+
278
+ export function useAutoBeAgent() {
279
+ const context = useContext(AutoBeAgentContext);
280
+ if (!context) {
281
+ throw new Error("useAutoBeAgent must be used within a AutoBeAgentProvider");
282
+ }
283
+ return context;
284
+ }
285
+
286
+ /**
287
+ * Wrap a TGrid driver Proxy into a plain object so that React dev-mode
288
+ * render logging never touches the Proxy (which crashes on Symbol
289
+ * property access: "Cannot convert a Symbol value to a string").
290
+ */
291
+ function wrapServiceProxy(
292
+ service: IAutoBeRpcService,
293
+ ): IAutoBeRpcService {
294
+ return {
295
+ conversate: (content) => service.conversate(content),
296
+ getFiles: (options) => service.getFiles(options),
297
+ getHistories: () => service.getHistories(),
298
+ getTokenUsage: () => service.getTokenUsage(),
299
+ getPhase: () => service.getPhase(),
300
+ };
301
+ }
@@ -1,58 +1,58 @@
1
- import {
2
- ReactNode,
3
- createContext,
4
- useCallback,
5
- useContext,
6
- useEffect,
7
- useState,
8
- } from "react";
9
-
10
- import {
11
- IAutoBeAgentSession,
12
- IAutoBeAgentSessionStorageStrategy,
13
- } from "../structure";
14
-
15
- interface AutoBeAgentSessionListContextType {
16
- sessionList: IAutoBeAgentSession[];
17
- refreshSessionList: () => Promise<void>;
18
- }
19
-
20
- const AutoBeAgentSessionListContext =
21
- createContext<AutoBeAgentSessionListContextType | null>(null);
22
-
23
- export function AutoBeAgentSessionListProvider({
24
- children,
25
- storageStrategy,
26
- }: {
27
- storageStrategy: IAutoBeAgentSessionStorageStrategy;
28
- children: ReactNode;
29
- }) {
30
- const [sessionList, setSessionList] = useState<IAutoBeAgentSession[]>([]);
31
-
32
- const refreshSessionList = useCallback(async () => {
33
- await storageStrategy.getSessionList().then(setSessionList);
34
- }, [storageStrategy]);
35
-
36
- useEffect(() => {
37
- refreshSessionList();
38
- }, [storageStrategy]);
39
-
40
- return (
41
- <AutoBeAgentSessionListContext.Provider
42
- value={{
43
- sessionList,
44
- refreshSessionList,
45
- }}
46
- >
47
- {children}
48
- </AutoBeAgentSessionListContext.Provider>
49
- );
50
- }
51
-
52
- export function useAutoBeAgentSessionList() {
53
- const context = useContext(AutoBeAgentSessionListContext);
54
- if (!context) {
55
- throw new Error("useAutoBeAgent must be used within a AutoBeAgentProvider");
56
- }
57
- return context;
58
- }
1
+ import {
2
+ ReactNode,
3
+ createContext,
4
+ useCallback,
5
+ useContext,
6
+ useEffect,
7
+ useState,
8
+ } from "react";
9
+
10
+ import {
11
+ IAutoBeAgentSession,
12
+ IAutoBeAgentSessionStorageStrategy,
13
+ } from "../structure";
14
+
15
+ interface AutoBeAgentSessionListContextType {
16
+ sessionList: IAutoBeAgentSession[];
17
+ refreshSessionList: () => Promise<void>;
18
+ }
19
+
20
+ const AutoBeAgentSessionListContext =
21
+ createContext<AutoBeAgentSessionListContextType | null>(null);
22
+
23
+ export function AutoBeAgentSessionListProvider({
24
+ children,
25
+ storageStrategy,
26
+ }: {
27
+ storageStrategy: IAutoBeAgentSessionStorageStrategy;
28
+ children: ReactNode;
29
+ }) {
30
+ const [sessionList, setSessionList] = useState<IAutoBeAgentSession[]>([]);
31
+
32
+ const refreshSessionList = useCallback(async () => {
33
+ await storageStrategy.getSessionList().then(setSessionList);
34
+ }, [storageStrategy]);
35
+
36
+ useEffect(() => {
37
+ refreshSessionList();
38
+ }, [storageStrategy]);
39
+
40
+ return (
41
+ <AutoBeAgentSessionListContext.Provider
42
+ value={{
43
+ sessionList,
44
+ refreshSessionList,
45
+ }}
46
+ >
47
+ {children}
48
+ </AutoBeAgentSessionListContext.Provider>
49
+ );
50
+ }
51
+
52
+ export function useAutoBeAgentSessionList() {
53
+ const context = useContext(AutoBeAgentSessionListContext);
54
+ if (!context) {
55
+ throw new Error("useAutoBeAgent must be used within a AutoBeAgentProvider");
56
+ }
57
+ return context;
58
+ }