bs-agent 0.0.9 → 0.0.12

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 DELETED
@@ -1,886 +0,0 @@
1
- // src/agent-context.tsx
2
- import {
3
- createContext,
4
- useContext,
5
- useCallback as useCallback4,
6
- useRef as useRef3,
7
- useState as useState3,
8
- useEffect as useEffect3,
9
- useMemo as useMemo2
10
- } from "react";
11
-
12
- // src/use-agent.ts
13
- import { useCallback as useCallback2, useRef as useRef2, useState, useEffect } from "react";
14
- import { fetchEventSource } from "@microsoft/fetch-event-source";
15
-
16
- // src/constants.ts
17
- var AGENT_SESSIONS_KEY = "buildship:agent:conversations";
18
- var AGENT_DEBUG_DATA_KEY = "buildship:agent:debug";
19
- var DEFAULT_SESSION_NAME = "New Chat";
20
- var TEMPORARY_SESSION_ID = "sess_temp";
21
-
22
- // src/session-utils.ts
23
- import { useCallback, useMemo, useRef } from "react";
24
- var useSessionUtils = (agentId, allSessions, setAllSessions, currentSessionId, setCurrentSessionId, messagesRef) => {
25
- const agentSessions = useMemo(() => allSessions[agentId] || {}, [agentId, allSessions]);
26
- const syncSessionRef = useRef();
27
- syncSessionRef.current = (updatedMessages) => {
28
- if (!currentSessionId || currentSessionId === TEMPORARY_SESSION_ID) {
29
- return;
30
- }
31
- setAllSessions((prev) => ({
32
- ...prev,
33
- [agentId]: {
34
- ...prev[agentId],
35
- [currentSessionId]: {
36
- ...prev[agentId]?.[currentSessionId],
37
- messages: updatedMessages ?? messagesRef.current,
38
- updatedAt: Date.now()
39
- }
40
- }
41
- }));
42
- };
43
- const getInitialSessionId = () => {
44
- const sessions = Object.values(agentSessions);
45
- if (sessions.length > 0) {
46
- return sessions.sort((a, b) => b.updatedAt - a.updatedAt)[0].id;
47
- }
48
- return TEMPORARY_SESSION_ID;
49
- };
50
- const switchSession = useCallback(
51
- (sessionId = TEMPORARY_SESSION_ID) => {
52
- setCurrentSessionId(sessionId);
53
- },
54
- [setCurrentSessionId]
55
- );
56
- const deleteSession = useCallback(
57
- (sessionId) => {
58
- if (!sessionId || sessionId === TEMPORARY_SESSION_ID) {
59
- return;
60
- }
61
- setAllSessions((prev) => {
62
- const updatedAgentSessions = { ...prev[agentId] };
63
- delete updatedAgentSessions[sessionId];
64
- return {
65
- ...prev,
66
- [agentId]: updatedAgentSessions
67
- };
68
- });
69
- if (sessionId === currentSessionId) {
70
- const remainingSessions = Object.values(agentSessions).filter((s) => s.id !== sessionId);
71
- if (remainingSessions.length > 0) {
72
- const mostRecent = remainingSessions.sort((a, b) => b.updatedAt - a.updatedAt)[0];
73
- setCurrentSessionId(mostRecent.id);
74
- } else {
75
- setCurrentSessionId(TEMPORARY_SESSION_ID);
76
- }
77
- }
78
- },
79
- [agentId, currentSessionId, agentSessions, setAllSessions, setCurrentSessionId]
80
- );
81
- const sessionsList = useMemo(
82
- () => Object.values(agentSessions).sort((a, b) => b.updatedAt - a.updatedAt),
83
- [agentSessions]
84
- );
85
- const createSessionFromResponse = (sessionId, sessionName, currentMessages) => {
86
- setAllSessions((prev) => ({
87
- ...prev,
88
- [agentId]: {
89
- ...prev[agentId],
90
- [sessionId]: {
91
- id: sessionId,
92
- createdAt: Date.now(),
93
- updatedAt: Date.now(),
94
- messages: currentMessages,
95
- name: sessionName
96
- }
97
- }
98
- }));
99
- };
100
- return {
101
- agentSessions,
102
- syncSessionRef,
103
- getInitialSessionId,
104
- switchSession,
105
- deleteSession,
106
- sessionsList,
107
- createSessionFromResponse
108
- };
109
- };
110
-
111
- // src/debug-handlers.ts
112
- var createDebugHandlers = (setDebugData) => {
113
- const handleDebugToolExecutionStarted = (parsed) => {
114
- const executionId = parsed.meta.executionId;
115
- setDebugData((prev) => ({
116
- ...prev,
117
- [executionId]: [
118
- ...prev[executionId] || [],
119
- {
120
- itemType: "tool_call",
121
- toolId: parsed.data.toolId || "unknown",
122
- toolCallId: parsed.data.toolCallId,
123
- status: "progress"
124
- }
125
- ]
126
- }));
127
- };
128
- const handleDebugToolExecutionInputs = (parsed) => {
129
- const executionId = parsed.meta.executionId;
130
- const toolCallId = parsed.data.toolCallId;
131
- setDebugData((prev) => {
132
- const currentData = [...prev[executionId] || []];
133
- for (let i = currentData.length - 1; i >= 0; i--) {
134
- if (currentData[i].itemType === "tool_call") {
135
- const toolItem = currentData[i];
136
- if (toolItem.toolCallId === toolCallId) {
137
- currentData[i] = {
138
- ...toolItem,
139
- inputs: parsed.data.value
140
- };
141
- break;
142
- }
143
- }
144
- }
145
- return {
146
- ...prev,
147
- [executionId]: currentData
148
- };
149
- });
150
- };
151
- const handleDebugToolExecutionFinished = (parsed) => {
152
- const executionId = parsed.meta.executionId;
153
- const toolCallId = parsed.data.toolCallId;
154
- setDebugData((prev) => {
155
- const currentData = [...prev[executionId] || []];
156
- for (let i = currentData.length - 1; i >= 0; i--) {
157
- if (currentData[i].itemType === "tool_call") {
158
- const toolItem = currentData[i];
159
- if (toolItem.toolCallId === toolCallId) {
160
- currentData[i] = {
161
- ...toolItem,
162
- status: "complete",
163
- output: parsed.data.value
164
- };
165
- break;
166
- }
167
- }
168
- }
169
- return {
170
- ...prev,
171
- [executionId]: currentData
172
- };
173
- });
174
- };
175
- const handleDebugToolExecutionError = (parsed) => {
176
- const executionId = parsed.meta.executionId;
177
- const toolCallId = parsed.data.toolCallId;
178
- setDebugData((prev) => {
179
- const currentData = [...prev[executionId] || []];
180
- for (let i = currentData.length - 1; i >= 0; i--) {
181
- if (currentData[i].itemType === "tool_call") {
182
- const toolItem = currentData[i];
183
- if (toolItem.toolCallId === toolCallId) {
184
- currentData[i] = {
185
- ...toolItem,
186
- status: "error",
187
- output: parsed.data.value
188
- };
189
- break;
190
- }
191
- }
192
- }
193
- return {
194
- ...prev,
195
- [executionId]: currentData
196
- };
197
- });
198
- };
199
- const handleDebugToolLog = (parsed) => {
200
- const executionId = parsed.meta.executionId;
201
- const toolCallId = parsed.data.toolCallId;
202
- setDebugData((prev) => {
203
- const currentData = [...prev[executionId] || []];
204
- for (let i = currentData.length - 1; i >= 0; i--) {
205
- if (currentData[i].itemType === "tool_call") {
206
- const toolItem = currentData[i];
207
- if (toolItem.toolCallId === toolCallId) {
208
- const currentLogs = toolItem.logs || [];
209
- currentData[i] = {
210
- ...toolItem,
211
- logs: [...currentLogs, parsed.data.value[0]]
212
- };
213
- break;
214
- }
215
- }
216
- }
217
- return {
218
- ...prev,
219
- [executionId]: currentData
220
- };
221
- });
222
- };
223
- let lastReasoningIndex = -1;
224
- const handleDebugReasoningStep = (parsed) => {
225
- const executionId = parsed.meta.executionId;
226
- const { delta, index } = parsed.data;
227
- setDebugData((prev) => {
228
- const currentData = [...prev[executionId] || []];
229
- if (lastReasoningIndex < index) {
230
- currentData.push({ itemType: "reasoning", reasoning: "" });
231
- lastReasoningIndex = index;
232
- }
233
- for (let i = currentData.length - 1; i >= 0; i--) {
234
- if (currentData[i].itemType === "reasoning") {
235
- currentData[i] = {
236
- itemType: "reasoning",
237
- reasoning: currentData[i].reasoning + delta
238
- };
239
- break;
240
- }
241
- }
242
- return {
243
- ...prev,
244
- [executionId]: currentData
245
- };
246
- });
247
- };
248
- const handleAgentHandoff = (parsed) => {
249
- const executionId = parsed.meta.executionId;
250
- setDebugData((prev) => ({
251
- ...prev,
252
- [executionId]: [
253
- ...prev[executionId] || [],
254
- {
255
- itemType: "handoff",
256
- agentName: parsed.data.agentName
257
- }
258
- ]
259
- }));
260
- };
261
- const handleMCPToolCallStart = (parsed) => {
262
- const executionId = parsed.meta.executionId;
263
- setDebugData((prev) => ({
264
- ...prev,
265
- [executionId]: [
266
- ...prev[executionId] || [],
267
- {
268
- itemType: "mcp_tool_call",
269
- toolName: parsed.data.toolName,
270
- serverName: parsed.data.serverName,
271
- callId: parsed.data.callId,
272
- status: "progress",
273
- inputs: parsed.data.inputs
274
- }
275
- ]
276
- }));
277
- };
278
- const handleMCPToolCallEnd = (parsed) => {
279
- const executionId = parsed.meta.executionId;
280
- const callId = parsed.data.callId;
281
- setDebugData((prev) => {
282
- const currentData = [...prev[executionId] || []];
283
- for (let i = currentData.length - 1; i >= 0; i--) {
284
- if (currentData[i].itemType === "mcp_tool_call") {
285
- const mcpToolItem = currentData[i];
286
- if (mcpToolItem.callId === callId) {
287
- currentData[i] = {
288
- ...mcpToolItem,
289
- status: parsed.data.error ? "error" : "complete",
290
- output: parsed.data.result,
291
- error: parsed.data.error
292
- };
293
- break;
294
- }
295
- }
296
- }
297
- return {
298
- ...prev,
299
- [executionId]: currentData
300
- };
301
- });
302
- };
303
- const handleDebugEvent = (parsed) => {
304
- switch (parsed.type) {
305
- case "debug_tool_execution_started":
306
- handleDebugToolExecutionStarted(parsed);
307
- break;
308
- case "debug_tool_execution_inputs":
309
- handleDebugToolExecutionInputs(parsed);
310
- break;
311
- case "debug_tool_execution_finished":
312
- handleDebugToolExecutionFinished(parsed);
313
- break;
314
- case "debug_tool_execution_error":
315
- handleDebugToolExecutionError(parsed);
316
- break;
317
- case "debug_tool_log":
318
- handleDebugToolLog(parsed);
319
- break;
320
- case "llm_reasoning_delta":
321
- handleDebugReasoningStep(parsed);
322
- break;
323
- case "agent_handoff":
324
- handleAgentHandoff(parsed);
325
- break;
326
- case "mcp_tool_call_start":
327
- handleMCPToolCallStart(parsed);
328
- break;
329
- case "mcp_tool_call_end":
330
- handleMCPToolCallEnd(parsed);
331
- break;
332
- }
333
- };
334
- return {
335
- handleDebugEvent
336
- };
337
- };
338
-
339
- // src/utils/schema.ts
340
- function cleanSchema(obj) {
341
- if (Array.isArray(obj)) {
342
- return obj.map(cleanSchema);
343
- } else if (obj !== null && typeof obj === "object") {
344
- const newObj = {};
345
- const currentObj = obj;
346
- for (const key in currentObj) {
347
- if (key === "propertyNames" || key === "$schema") {
348
- continue;
349
- }
350
- newObj[key] = cleanSchema(currentObj[key]);
351
- }
352
- if (newObj.type === "object") {
353
- if (newObj.additionalProperties === void 0 || newObj.additionalProperties && typeof newObj.additionalProperties === "object" && Object.keys(newObj.additionalProperties).length === 0) {
354
- newObj.additionalProperties = false;
355
- }
356
- if (newObj.additionalProperties === false && newObj.properties) {
357
- newObj.required = Object.keys(newObj.properties);
358
- }
359
- }
360
- return newObj;
361
- }
362
- return obj;
363
- }
364
- function tryParseJSON(value) {
365
- if (typeof value === "string") {
366
- try {
367
- return JSON.parse(value);
368
- } catch {
369
- return value;
370
- }
371
- }
372
- return value;
373
- }
374
-
375
- // src/utils/message.ts
376
- function updateAgentMessageParts(parts, newPart) {
377
- const sorted = [...parts, newPart].sort((a, b) => {
378
- const aStart = a.type === "text" ? a.firstSequence : a.sequence;
379
- const bStart = b.type === "text" ? b.firstSequence : b.sequence;
380
- return aStart - bStart;
381
- });
382
- return sorted.reduce((acc, current) => {
383
- const last = acc[acc.length - 1];
384
- const canMerge = last?.type === "text" && current.type === "text" && current.firstSequence === last.lastSequence + 1;
385
- if (canMerge) {
386
- acc[acc.length - 1] = {
387
- ...last,
388
- text: last.text + current.text,
389
- lastSequence: current.lastSequence
390
- };
391
- return acc;
392
- }
393
- acc.push(current);
394
- return acc;
395
- }, []);
396
- }
397
-
398
- // src/use-agent.ts
399
- function useAgent(agentId, agentUrl, accessKey) {
400
- const { allSessions, setAllSessions, debugData, setDebugData } = useAgentGlobalState();
401
- const [inProgress, setInProgress] = useState(false);
402
- const [messages, setMessages] = useState([]);
403
- const messagesRef = useRef2([]);
404
- const [currentSessionId, setCurrentSessionId] = useState(TEMPORARY_SESSION_ID);
405
- const sessionUtils = useSessionUtils(
406
- agentId,
407
- allSessions,
408
- setAllSessions,
409
- currentSessionId,
410
- setCurrentSessionId,
411
- messagesRef
412
- );
413
- useEffect(() => {
414
- const initialSessionId = sessionUtils.getInitialSessionId();
415
- setCurrentSessionId(initialSessionId);
416
- }, []);
417
- const debugHandlers = createDebugHandlers(setDebugData);
418
- useEffect(() => {
419
- messagesRef.current = messages;
420
- }, [messages]);
421
- useEffect(() => {
422
- if (inProgress) {
423
- return;
424
- }
425
- const session = sessionUtils.agentSessions[currentSessionId];
426
- if (session) {
427
- setMessages(session.messages);
428
- } else {
429
- setMessages([]);
430
- }
431
- }, [currentSessionId, sessionUtils.agentSessions, agentId, inProgress]);
432
- useEffect(() => {
433
- return () => {
434
- if (messagesRef.current.length > 0 && sessionUtils.syncSessionRef.current) {
435
- sessionUtils.syncSessionRef.current();
436
- }
437
- };
438
- }, []);
439
- const controller = useRef2();
440
- const runAgent = useCallback2(
441
- async (input, options) => {
442
- setInProgress(true);
443
- if (controller.current) {
444
- controller.current.abort();
445
- }
446
- controller.current = new AbortController();
447
- const headers = {
448
- "Content-Type": "application/json",
449
- ...options?.additionalHeaders || {},
450
- ...accessKey ? { Authorization: `Bearer ${accessKey}` } : {}
451
- };
452
- if (currentSessionId) {
453
- headers["x-buildship-agent-session-id"] = currentSessionId;
454
- }
455
- const body = {
456
- stream: true,
457
- input,
458
- context: options?.context || {},
459
- testBuildId: options?.testBuildId,
460
- tools: options?.tools?.map((t) => ({
461
- ...t,
462
- parameters: cleanSchema(t.parameters)
463
- })),
464
- clientTools: options?.clientTools?.map((t) => ({
465
- ...t,
466
- parameters: cleanSchema(t.parameters)
467
- }))
468
- };
469
- try {
470
- await fetchEventSource(agentUrl, {
471
- method: "POST",
472
- headers,
473
- signal: controller.current.signal,
474
- openWhenHidden: true,
475
- body: JSON.stringify(body),
476
- onopen: async (resp) => {
477
- if (resp.status >= 400) {
478
- console.log(`AI onopen error with status: ${resp.status}`);
479
- if (resp.status === 404) {
480
- throw new Error(`Not Found (${resp.statusText})`);
481
- }
482
- throw new Error(`Error status ${resp.status}`);
483
- }
484
- if (!currentSessionId || currentSessionId === TEMPORARY_SESSION_ID) {
485
- const sessionId = resp.headers.get("x-buildship-agent-session-id");
486
- if (sessionId) {
487
- const currentMessages = messagesRef.current;
488
- const sessionName = resp.headers.get("x-buildship-agent-session-name") || DEFAULT_SESSION_NAME;
489
- sessionUtils.createSessionFromResponse(sessionId, sessionName, currentMessages);
490
- setCurrentSessionId(sessionId);
491
- }
492
- }
493
- const executionId = resp.headers.get("x-buildship-agent-execution-id");
494
- if (executionId) {
495
- setMessages((prev) => {
496
- const lastMessage = prev[prev.length - 1];
497
- if (lastMessage?.role === "user") {
498
- const updatedMessage = {
499
- ...lastMessage,
500
- executionId
501
- };
502
- const updatedMessages = [...prev.slice(0, -1), updatedMessage];
503
- if (sessionUtils.syncSessionRef.current) {
504
- sessionUtils.syncSessionRef.current(updatedMessages);
505
- }
506
- return updatedMessages;
507
- }
508
- return prev;
509
- });
510
- }
511
- },
512
- onmessage: (event) => {
513
- try {
514
- const parsed = JSON.parse(event.data);
515
- if (parsed.type === "llm_text_delta") {
516
- setMessages((prev) => {
517
- const lastMessage = prev[prev.length - 1];
518
- const sequence = parsed.meta.sequence;
519
- const newPart = {
520
- type: "text",
521
- text: parsed.data,
522
- firstSequence: sequence,
523
- lastSequence: sequence
524
- };
525
- let updatedMessages;
526
- if (lastMessage?.role === "agent") {
527
- const updatedMessage = {
528
- ...lastMessage,
529
- content: lastMessage.content + parsed.data,
530
- // content is still useful for simple displays
531
- parts: updateAgentMessageParts(lastMessage.parts || [], newPart)
532
- };
533
- updatedMessages = [...prev.slice(0, -1), updatedMessage];
534
- } else {
535
- const updatedMessage = {
536
- role: "agent",
537
- content: parsed.data,
538
- parts: [newPart],
539
- executionId: parsed.meta.executionId
540
- };
541
- updatedMessages = [...prev, updatedMessage];
542
- }
543
- if (sessionUtils.syncSessionRef.current) {
544
- sessionUtils.syncSessionRef.current(updatedMessages);
545
- }
546
- return updatedMessages;
547
- });
548
- } else if (parsed.type === "client_tool_call") {
549
- setMessages((prev) => {
550
- const lastMessage = prev[prev.length - 1];
551
- const newPart = {
552
- type: "widget",
553
- toolName: parsed.data.toolName,
554
- callId: parsed.data.callId,
555
- inputs: tryParseJSON(parsed.data.inputs),
556
- sequence: parsed.meta.sequence
557
- };
558
- let updatedMessages;
559
- if (lastMessage?.role === "agent") {
560
- const updatedMessage = {
561
- ...lastMessage,
562
- parts: updateAgentMessageParts(lastMessage.parts || [], newPart)
563
- };
564
- updatedMessages = [...prev.slice(0, -1), updatedMessage];
565
- } else {
566
- const updatedMessage = {
567
- role: "agent",
568
- content: "",
569
- parts: [newPart],
570
- executionId: parsed.meta.executionId
571
- };
572
- updatedMessages = [...prev, updatedMessage];
573
- }
574
- if (sessionUtils.syncSessionRef.current) {
575
- sessionUtils.syncSessionRef.current(updatedMessages);
576
- }
577
- return updatedMessages;
578
- });
579
- } else if (parsed.type.startsWith("debug_") || parsed.type === "llm_reasoning_delta" || parsed.type === "agent_handoff" || parsed.type === "mcp_tool_call_start" || parsed.type === "mcp_tool_call_end") {
580
- debugHandlers.handleDebugEvent(parsed);
581
- }
582
- } catch (e) {
583
- console.log("Failed to parse agent message", e);
584
- }
585
- },
586
- onclose: () => {
587
- console.log("Agent closed");
588
- setInProgress(false);
589
- if (sessionUtils.syncSessionRef.current) {
590
- sessionUtils.syncSessionRef.current();
591
- }
592
- },
593
- onerror: (e) => {
594
- console.log("Agent error", e);
595
- setInProgress(false);
596
- if (sessionUtils.syncSessionRef.current) {
597
- sessionUtils.syncSessionRef.current(messagesRef.current);
598
- }
599
- throw new Error("Failed to execute agent");
600
- }
601
- });
602
- } catch (error) {
603
- console.log("Agent execution failed", error);
604
- setInProgress(false);
605
- if (sessionUtils.syncSessionRef.current) {
606
- sessionUtils.syncSessionRef.current(messagesRef.current);
607
- }
608
- throw error;
609
- }
610
- },
611
- [agentUrl, accessKey, currentSessionId, sessionUtils, debugHandlers]
612
- );
613
- const handleSend = useCallback2(
614
- async (input, options) => {
615
- const userMessage = {
616
- role: "user",
617
- content: input,
618
- executionId: Date.now().toString()
619
- };
620
- if (!options?.skipUserMessage) {
621
- setMessages((prev) => {
622
- const updatedMessages = [...prev, userMessage];
623
- if (sessionUtils.syncSessionRef.current) {
624
- sessionUtils.syncSessionRef.current(updatedMessages);
625
- }
626
- return updatedMessages;
627
- });
628
- }
629
- try {
630
- await runAgent(input, options);
631
- } catch (error) {
632
- if (!options?.skipUserMessage) {
633
- setMessages((prev) => {
634
- const updatedMessages = prev.some((m) => m === userMessage) ? prev : [...prev, userMessage];
635
- if (sessionUtils.syncSessionRef.current) {
636
- sessionUtils.syncSessionRef.current(updatedMessages);
637
- }
638
- return updatedMessages;
639
- });
640
- }
641
- throw error;
642
- }
643
- },
644
- [runAgent, sessionUtils.syncSessionRef]
645
- );
646
- const addOptimisticMessage = useCallback2(
647
- (input) => {
648
- const userMessage = {
649
- role: "user",
650
- content: input,
651
- executionId: Date.now().toString()
652
- };
653
- setMessages((prev) => {
654
- const updatedMessages = [...prev, userMessage];
655
- if (sessionUtils.syncSessionRef.current) {
656
- sessionUtils.syncSessionRef.current(updatedMessages);
657
- }
658
- return updatedMessages;
659
- });
660
- },
661
- [sessionUtils.syncSessionRef]
662
- );
663
- const abort = useCallback2(() => {
664
- if (controller.current) {
665
- controller.current.abort();
666
- }
667
- setInProgress(false);
668
- if (sessionUtils.syncSessionRef.current) {
669
- sessionUtils.syncSessionRef.current(messagesRef.current);
670
- }
671
- }, [sessionUtils.syncSessionRef]);
672
- return {
673
- inProgress,
674
- messages,
675
- handleSend,
676
- addOptimisticMessage,
677
- abort,
678
- sessionId: currentSessionId,
679
- switchSession: sessionUtils.switchSession,
680
- deleteSession: sessionUtils.deleteSession,
681
- sessions: sessionUtils.sessionsList,
682
- debugData
683
- };
684
- }
685
-
686
- // src/utils/use-synced-local-storage.ts
687
- import { useState as useState2, useEffect as useEffect2, useCallback as useCallback3 } from "react";
688
- function parseJSON(value, defaultValue) {
689
- if (value === null) return defaultValue;
690
- try {
691
- return JSON.parse(value);
692
- } catch {
693
- return defaultValue;
694
- }
695
- }
696
- function useSyncedLocalStorage(key, initialValue) {
697
- const [storedValue, setStoredValue] = useState2(() => {
698
- if (typeof window === "undefined") {
699
- return initialValue;
700
- }
701
- try {
702
- const item = window.localStorage.getItem(key);
703
- return parseJSON(item, initialValue);
704
- } catch (error) {
705
- console.warn(`Error reading localStorage key "${key}":`, error);
706
- return initialValue;
707
- }
708
- });
709
- const setValue = useCallback3(
710
- (value) => {
711
- try {
712
- setStoredValue((prev) => {
713
- const valueToStore = value instanceof Function ? value(prev) : value;
714
- if (typeof window !== "undefined") {
715
- window.localStorage.setItem(key, JSON.stringify(valueToStore));
716
- window.dispatchEvent(
717
- new StorageEvent("storage", { key, newValue: JSON.stringify(valueToStore) })
718
- );
719
- }
720
- return valueToStore;
721
- });
722
- } catch (error) {
723
- console.warn(`Error setting localStorage key "${key}":`, error);
724
- }
725
- },
726
- [key]
727
- );
728
- useEffect2(() => {
729
- const handleStorageChange = (event) => {
730
- if (event.key === key) {
731
- setStoredValue(parseJSON(event.newValue, initialValue));
732
- }
733
- };
734
- window.addEventListener("storage", handleStorageChange);
735
- return () => window.removeEventListener("storage", handleStorageChange);
736
- }, [key, initialValue]);
737
- return [storedValue, setValue];
738
- }
739
-
740
- // src/agent-context.tsx
741
- import { jsx, jsxs } from "react/jsx-runtime";
742
- var AgentContext = createContext(null);
743
- function AgentContextProvider({ children }) {
744
- const activeAgentsRef = useRef3(/* @__PURE__ */ new Map());
745
- const runnersRef = useRef3(/* @__PURE__ */ new Map());
746
- const listenersRef = useRef3(/* @__PURE__ */ new Map());
747
- const [, forceUpdate] = useState3({});
748
- const [allSessions, setAllSessions] = useSyncedLocalStorage(AGENT_SESSIONS_KEY, {});
749
- const [debugData, setDebugData] = useSyncedLocalStorage(
750
- AGENT_DEBUG_DATA_KEY,
751
- {}
752
- );
753
- const initializeAgent = useCallback4((agentId, agentUrl, accessKey) => {
754
- const existing = activeAgentsRef.current.get(agentId);
755
- if (!existing) {
756
- activeAgentsRef.current.set(agentId, { agentUrl, accessKey });
757
- forceUpdate({});
758
- } else if (existing.agentUrl !== agentUrl || existing.accessKey !== accessKey) {
759
- activeAgentsRef.current.set(agentId, { agentUrl, accessKey });
760
- forceUpdate({});
761
- }
762
- }, []);
763
- const registerRunner = useCallback4((agentId, runner) => {
764
- runnersRef.current.set(agentId, runner);
765
- const listeners = listenersRef.current.get(agentId);
766
- if (listeners) {
767
- listeners.forEach((callback) => callback());
768
- }
769
- }, []);
770
- const getRunner = useCallback4((agentId) => {
771
- return runnersRef.current.get(agentId) || null;
772
- }, []);
773
- const contextValue = useMemo2(
774
- () => ({
775
- initializeAgent,
776
- registerRunner,
777
- getRunner,
778
- allSessions,
779
- setAllSessions,
780
- debugData,
781
- setDebugData,
782
- runnersRef,
783
- listenersRef
784
- }),
785
- [
786
- initializeAgent,
787
- registerRunner,
788
- getRunner,
789
- allSessions,
790
- setAllSessions,
791
- debugData,
792
- setDebugData
793
- ]
794
- );
795
- return /* @__PURE__ */ jsxs(AgentContext.Provider, { value: contextValue, children: [
796
- children,
797
- Array.from(activeAgentsRef.current.entries()).map(([agentId, { agentUrl, accessKey }]) => /* @__PURE__ */ jsx(AgentRunnerInstance, { agentId, agentUrl, accessKey }, agentId))
798
- ] });
799
- }
800
- function AgentRunnerInstance({
801
- agentId,
802
- agentUrl,
803
- accessKey
804
- }) {
805
- const agent = useAgent(agentId, agentUrl, accessKey);
806
- const context = useContext(AgentContext);
807
- if (!context) return null;
808
- useEffect3(() => {
809
- context.registerRunner(agentId, agent);
810
- }, [agentId, agent, context]);
811
- return null;
812
- }
813
- function useAgentContext(agentId, agentUrl, accessKey) {
814
- const context = useContext(AgentContext);
815
- if (!context) {
816
- throw new Error("useAgentContext must be used within AgentContextProvider");
817
- }
818
- const { initializeAgent, getRunner, listenersRef } = context;
819
- useEffect3(() => {
820
- initializeAgent(agentId, agentUrl, accessKey);
821
- }, [agentId, agentUrl, initializeAgent]);
822
- const [runner, setRunner] = useState3(() => getRunner(agentId));
823
- useEffect3(() => {
824
- const currentRunner = getRunner(agentId);
825
- if (currentRunner !== runner) {
826
- setRunner(currentRunner);
827
- }
828
- const callback = () => {
829
- setRunner(getRunner(agentId));
830
- };
831
- if (!listenersRef.current.has(agentId)) {
832
- listenersRef.current.set(agentId, /* @__PURE__ */ new Set());
833
- }
834
- listenersRef.current.get(agentId)?.add(callback);
835
- return () => {
836
- listenersRef.current.get(agentId)?.delete(callback);
837
- };
838
- }, [agentId, getRunner]);
839
- const placeholder = useMemo2(
840
- () => ({
841
- messages: [],
842
- inProgress: false,
843
- sessionId: "",
844
- sessions: [],
845
- debugData: {},
846
- handleSend: async () => {
847
- },
848
- switchSession: () => {
849
- },
850
- deleteSession: () => {
851
- },
852
- addOptimisticMessage: () => {
853
- },
854
- abort: () => {
855
- }
856
- }),
857
- []
858
- );
859
- return runner || placeholder;
860
- }
861
- function useAgentGlobalState() {
862
- const context = useContext(AgentContext);
863
- if (!context) {
864
- throw new Error("useAgentGlobalState must be used within AgentContextProvider");
865
- }
866
- return {
867
- allSessions: context.allSessions,
868
- setAllSessions: context.setAllSessions,
869
- debugData: context.debugData,
870
- setDebugData: context.setDebugData
871
- };
872
- }
873
- export {
874
- AGENT_DEBUG_DATA_KEY,
875
- AGENT_SESSIONS_KEY,
876
- AgentContextProvider,
877
- DEFAULT_SESSION_NAME,
878
- TEMPORARY_SESSION_ID,
879
- cleanSchema,
880
- tryParseJSON,
881
- updateAgentMessageParts,
882
- useAgent,
883
- useAgentContext,
884
- useAgentGlobalState
885
- };
886
- //# sourceMappingURL=index.js.map