bs-agent 0.0.28 → 0.0.30

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.
@@ -10,11 +10,10 @@ import {
10
10
  } from "react";
11
11
 
12
12
  // src/react/use-agent.ts
13
- import { useCallback as useCallback3, useRef as useRef2, useState, useEffect, useContext as useContext2, useMemo as useMemo2 } from "react";
13
+ import { useCallback as useCallback3, useRef as useRef2, useState, useEffect, useContext as useContext2 } from "react";
14
14
 
15
15
  // src/react/constants.ts
16
16
  var AGENT_SESSIONS_KEY = "buildship:agent:conversations";
17
- var AGENT_DEBUG_DATA_KEY = "buildship:agent:debug";
18
17
  var DEFAULT_SESSION_NAME = "New Chat";
19
18
  var TEMPORARY_SESSION_ID = "sess_temp";
20
19
 
@@ -120,122 +119,6 @@ var useSessionUtils = (agentId, allSessions, setAllSessions, currentSessionId, s
120
119
  };
121
120
  };
122
121
 
123
- // src/react/debug-handlers.ts
124
- var createDebugHandlers = (setDebugData) => {
125
- const handleStreamEvent = (event) => {
126
- const executionId = event.meta.executionId;
127
- switch (event.type) {
128
- case "tool_call_start": {
129
- const { callId, toolName, toolType, inputs, serverName } = event.data;
130
- setDebugData((prev) => ({
131
- ...prev,
132
- [executionId]: [
133
- ...prev[executionId] || [],
134
- {
135
- itemType: "tool_call",
136
- toolName,
137
- callId,
138
- toolType,
139
- status: "progress",
140
- inputs,
141
- serverName
142
- }
143
- ]
144
- }));
145
- break;
146
- }
147
- case "tool_call_end": {
148
- const { callId, result, error } = event.data;
149
- setDebugData((prev) => {
150
- const currentData = [...prev[executionId] || []];
151
- for (let i = currentData.length - 1; i >= 0; i--) {
152
- if (currentData[i].itemType === "tool_call") {
153
- const toolItem = currentData[i];
154
- if (toolItem.callId === callId) {
155
- currentData[i] = {
156
- ...toolItem,
157
- status: error ? "error" : "complete",
158
- output: result,
159
- error
160
- };
161
- break;
162
- }
163
- }
164
- }
165
- return {
166
- ...prev,
167
- [executionId]: currentData
168
- };
169
- });
170
- break;
171
- }
172
- case "reasoning_delta": {
173
- const { delta, index } = event.data;
174
- setDebugData((prev) => {
175
- const currentData = [...prev[executionId] || []];
176
- let existingItemIndex = -1;
177
- for (let i = currentData.length - 1; i >= 0; i--) {
178
- const item = currentData[i];
179
- if (item.itemType === "reasoning" && item.index === index) {
180
- existingItemIndex = i;
181
- break;
182
- }
183
- }
184
- if (existingItemIndex === -1) {
185
- currentData.push({ itemType: "reasoning", reasoning: delta, index });
186
- } else {
187
- const hasInterleavedItems = currentData.slice(existingItemIndex + 1).some((item) => item.itemType !== "reasoning");
188
- if (hasInterleavedItems) {
189
- currentData.push({ itemType: "reasoning", reasoning: delta, index });
190
- } else {
191
- currentData[existingItemIndex] = {
192
- itemType: "reasoning",
193
- reasoning: currentData[existingItemIndex].reasoning + delta,
194
- index
195
- };
196
- }
197
- }
198
- return {
199
- ...prev,
200
- [executionId]: currentData
201
- };
202
- });
203
- break;
204
- }
205
- case "agent_handoff": {
206
- setDebugData((prev) => ({
207
- ...prev,
208
- [executionId]: [
209
- ...prev[executionId] || [],
210
- {
211
- itemType: "handoff",
212
- agentName: event.data.agentName
213
- }
214
- ]
215
- }));
216
- break;
217
- }
218
- case "run_error": {
219
- setDebugData((prev) => ({
220
- ...prev,
221
- [executionId]: [
222
- ...prev[executionId] || [],
223
- {
224
- itemType: "run_error",
225
- message: event.data.message,
226
- code: event.data.code
227
- }
228
- ]
229
- }));
230
- break;
231
- }
232
- }
233
- };
234
- return {
235
- handleStreamEvent
236
- };
237
- };
238
-
239
122
  // src/react/client-tools.ts
240
123
  import { useCallback as useCallback2 } from "react";
241
124
  import { toJSONSchema } from "zod";
@@ -340,7 +223,7 @@ function updateAgentMessageParts(parts, newPart) {
340
223
  }
341
224
 
342
225
  // src/react/stream-callbacks.ts
343
- function buildStreamCallbacks(deps, debugKey) {
226
+ function buildStreamCallbacks(deps) {
344
227
  const {
345
228
  setMessages,
346
229
  setInProgress,
@@ -355,16 +238,10 @@ function buildStreamCallbacks(deps, debugKey) {
355
238
  onComplete: () => {
356
239
  console.log("Agent closed");
357
240
  setInProgress(false);
358
- if (syncSessionRef.current) {
359
- syncSessionRef.current(messagesRef.current);
360
- }
361
241
  },
362
242
  onError: (error) => {
363
243
  console.log("Agent error", error);
364
244
  setInProgress(false);
365
- if (syncSessionRef.current) {
366
- syncSessionRef.current(messagesRef.current);
367
- }
368
245
  },
369
246
  onEvent: (event) => {
370
247
  if (event.type === "text_delta") {
@@ -378,33 +255,36 @@ function buildStreamCallbacks(deps, debugKey) {
378
255
  );
379
256
  } else if (event.type === "tool_call_start" && event.data.toolType === "client") {
380
257
  handleClientToolCall(event, setMessages, syncSessionRef, toolContext, agentId);
381
- if (debugKey) {
382
- const debugMeta = { ...event.meta, executionId: debugKey };
383
- deps.debugHandlers.handleStreamEvent({
384
- ...event,
385
- meta: debugMeta
386
- });
387
- if (!event.data.paused) {
388
- deps.debugHandlers.handleStreamEvent({
389
- type: "tool_call_end",
390
- data: {
391
- callId: event.data.callId,
392
- toolName: event.data.toolName,
393
- toolType: event.data.toolType
394
- },
395
- meta: debugMeta
396
- });
397
- }
398
- }
399
- } else if (debugKey) {
400
- deps.debugHandlers.handleStreamEvent({
401
- ...event,
402
- meta: { ...event.meta, executionId: debugKey }
403
- });
258
+ } else if (event.type === "tool_call_start") {
259
+ handleToolCallStart(event, setMessages, syncSessionRef);
260
+ } else if (event.type === "tool_call_end") {
261
+ handleToolCallEnd(event, setMessages, syncSessionRef);
262
+ } else if (event.type === "reasoning_delta") {
263
+ handleReasoningDelta(event, setMessages, syncSessionRef);
264
+ } else if (event.type === "agent_handoff") {
265
+ handleAgentHandoff(event, setMessages, syncSessionRef);
266
+ } else if (event.type === "run_error") {
267
+ handleRunError(event, setMessages, syncSessionRef);
404
268
  }
405
269
  }
406
270
  };
407
271
  }
272
+ function ensureAgentMessage(prev, executionId) {
273
+ const last = prev[prev.length - 1];
274
+ if (last?.role === "agent") {
275
+ return [prev, last];
276
+ }
277
+ const newMsg = {
278
+ role: "agent",
279
+ content: "",
280
+ parts: [],
281
+ executionId
282
+ };
283
+ return [[...prev, newMsg], newMsg];
284
+ }
285
+ function replaceLastAgent(prev, updated) {
286
+ return [...prev.slice(0, -1), updated];
287
+ }
408
288
  function handleTextDelta(event, setMessages, syncSessionRef, modifier, fullTextModifier, agentId) {
409
289
  const sequence = event.meta.sequence;
410
290
  const originalText = event.data;
@@ -525,11 +405,138 @@ function handleClientToolCall(event, setMessages, syncSessionRef, toolContext, a
525
405
  return updatedMessages;
526
406
  });
527
407
  }
408
+ function handleToolCallStart(event, setMessages, syncSessionRef) {
409
+ const { callId, toolName, toolType, inputs, serverName } = event.data;
410
+ setMessages((prev) => {
411
+ const [msgs, agentMsg] = ensureAgentMessage(prev, event.meta.executionId);
412
+ const newPart = {
413
+ type: "tool_call",
414
+ toolName,
415
+ callId,
416
+ toolType,
417
+ status: "progress",
418
+ inputs,
419
+ serverName,
420
+ sequence: event.meta.sequence
421
+ };
422
+ const updated = {
423
+ ...agentMsg,
424
+ parts: [...agentMsg.parts || [], newPart]
425
+ };
426
+ const updatedMessages = replaceLastAgent(msgs, updated);
427
+ if (syncSessionRef.current) syncSessionRef.current(updatedMessages);
428
+ return updatedMessages;
429
+ });
430
+ }
431
+ function handleToolCallEnd(event, setMessages, syncSessionRef) {
432
+ const { callId, result, error } = event.data;
433
+ setMessages((prev) => {
434
+ const last = prev[prev.length - 1];
435
+ if (last?.role !== "agent" || !last.parts) return prev;
436
+ const updatedParts = [...last.parts];
437
+ for (let i = updatedParts.length - 1; i >= 0; i--) {
438
+ const part = updatedParts[i];
439
+ if (part.type === "tool_call" && part.callId === callId) {
440
+ updatedParts[i] = {
441
+ ...part,
442
+ status: error ? "error" : "complete",
443
+ output: result,
444
+ error
445
+ };
446
+ break;
447
+ }
448
+ }
449
+ for (let i = updatedParts.length - 1; i >= 0; i--) {
450
+ const part = updatedParts[i];
451
+ if (part.type === "widget" && part.callId === callId) {
452
+ updatedParts[i] = {
453
+ ...part,
454
+ status: error ? "error" : "submitted",
455
+ ...result !== void 0 ? { result } : {},
456
+ ...error ? { error } : {}
457
+ };
458
+ break;
459
+ }
460
+ }
461
+ const updated = { ...last, parts: updatedParts };
462
+ const updatedMessages = replaceLastAgent(prev, updated);
463
+ if (syncSessionRef.current) syncSessionRef.current(updatedMessages);
464
+ return updatedMessages;
465
+ });
466
+ }
467
+ function handleReasoningDelta(event, setMessages, syncSessionRef) {
468
+ const { delta, index } = event.data;
469
+ setMessages((prev) => {
470
+ const [msgs, agentMsg] = ensureAgentMessage(prev, event.meta.executionId);
471
+ const parts = [...agentMsg.parts || []];
472
+ let existingIdx = -1;
473
+ for (let i = parts.length - 1; i >= 0; i--) {
474
+ const p = parts[i];
475
+ if (p.type === "reasoning" && p.index === index) {
476
+ existingIdx = i;
477
+ break;
478
+ }
479
+ }
480
+ if (existingIdx === -1) {
481
+ parts.push({ type: "reasoning", reasoning: delta, index, sequence: event.meta.sequence });
482
+ } else {
483
+ const hasInterleavedItems = parts.slice(existingIdx + 1).some((p) => p.type !== "reasoning");
484
+ if (hasInterleavedItems) {
485
+ parts.push({ type: "reasoning", reasoning: delta, index, sequence: event.meta.sequence });
486
+ } else {
487
+ const existing = parts[existingIdx];
488
+ parts[existingIdx] = {
489
+ ...existing,
490
+ reasoning: existing.reasoning + delta
491
+ };
492
+ }
493
+ }
494
+ const updated = { ...agentMsg, parts };
495
+ const updatedMessages = replaceLastAgent(msgs, updated);
496
+ if (syncSessionRef.current) syncSessionRef.current(updatedMessages);
497
+ return updatedMessages;
498
+ });
499
+ }
500
+ function handleAgentHandoff(event, setMessages, syncSessionRef) {
501
+ setMessages((prev) => {
502
+ const [msgs, agentMsg] = ensureAgentMessage(prev, event.meta.executionId);
503
+ const newPart = {
504
+ type: "handoff",
505
+ agentName: event.data.agentName,
506
+ sequence: event.meta.sequence
507
+ };
508
+ const updated = {
509
+ ...agentMsg,
510
+ parts: [...agentMsg.parts || [], newPart]
511
+ };
512
+ const updatedMessages = replaceLastAgent(msgs, updated);
513
+ if (syncSessionRef.current) syncSessionRef.current(updatedMessages);
514
+ return updatedMessages;
515
+ });
516
+ }
517
+ function handleRunError(event, setMessages, syncSessionRef) {
518
+ setMessages((prev) => {
519
+ const [msgs, agentMsg] = ensureAgentMessage(prev, event.meta.executionId);
520
+ const newPart = {
521
+ type: "run_error",
522
+ message: event.data.message,
523
+ code: event.data.code,
524
+ sequence: event.meta.sequence
525
+ };
526
+ const updated = {
527
+ ...agentMsg,
528
+ parts: [...agentMsg.parts || [], newPart]
529
+ };
530
+ const updatedMessages = replaceLastAgent(msgs, updated);
531
+ if (syncSessionRef.current) syncSessionRef.current(updatedMessages);
532
+ return updatedMessages;
533
+ });
534
+ }
528
535
 
529
536
  // src/react/use-agent.ts
530
537
  function useAgent(agent, options) {
531
538
  const agentId = agent._agentId;
532
- const { allSessions, setAllSessions, debugData, setDebugData } = useAgentGlobalState();
539
+ const { allSessions, setAllSessions } = useAgentGlobalState();
533
540
  const toolContext = useContext2(AgentToolContext);
534
541
  const [inProgress, setInProgress] = useState(false);
535
542
  const [messages, setMessages] = useState([]);
@@ -547,7 +554,6 @@ function useAgent(agent, options) {
547
554
  const initialSessionId = sessionUtils.getInitialSessionId();
548
555
  setCurrentSessionId(initialSessionId);
549
556
  }, [agentId]);
550
- const debugHandlers = useMemo2(() => createDebugHandlers(setDebugData), [setDebugData]);
551
557
  useEffect(() => {
552
558
  messagesRef.current = messages;
553
559
  }, [messages]);
@@ -580,7 +586,6 @@ function useAgent(agent, options) {
580
586
  async (input, runOptions) => {
581
587
  const isNewSession = !currentSessionId || currentSessionId === TEMPORARY_SESSION_ID;
582
588
  setInProgress(true);
583
- const debugKey = runOptions?.optimisticExecutionId || messagesRef.current.findLast((m) => m.role === "user")?.executionId;
584
589
  const deps = {
585
590
  agentId,
586
591
  currentSessionId,
@@ -588,12 +593,11 @@ function useAgent(agent, options) {
588
593
  setMessages,
589
594
  setInProgress,
590
595
  syncSessionRef: sessionUtils.syncSessionRef,
591
- debugHandlers,
592
596
  toolContext,
593
597
  textDeltaModifier: optionsRef.current?.textDeltaModifier,
594
598
  fullTextModifier: optionsRef.current?.fullTextModifier
595
599
  };
596
- const callbacks = buildStreamCallbacks(deps, debugKey);
600
+ const callbacks = buildStreamCallbacks(deps);
597
601
  const executeOptions = {
598
602
  context: runOptions?.context,
599
603
  headers: runOptions?.additionalHeaders,
@@ -655,7 +659,7 @@ function useAgent(agent, options) {
655
659
  activeSessionRef.current = null;
656
660
  }
657
661
  },
658
- [currentSessionId, sessionUtils, debugHandlers, agentId, toolContext, agent, getClientToolsMap]
662
+ [currentSessionId, sessionUtils, agentId, toolContext, agent, getClientToolsMap]
659
663
  );
660
664
  const handleSend = useCallback3(
661
665
  async (input, options2) => {
@@ -754,14 +758,6 @@ function useAgent(agent, options) {
754
758
  return updatedMessages;
755
759
  });
756
760
  const lastUserMessage = messagesRef.current.findLast((m) => m.role === "user");
757
- const debugKey = lastUserMessage?.executionId;
758
- if (debugKey) {
759
- debugHandlers.handleStreamEvent({
760
- type: "tool_call_end",
761
- data: { callId, toolName: "", toolType: "client", result },
762
- meta: { executionId: debugKey, sequence: 0 }
763
- });
764
- }
765
761
  await runAgent(void 0, {
766
762
  resumeToolCallId: callId,
767
763
  resumeToolResult: result,
@@ -770,7 +766,7 @@ function useAgent(agent, options) {
770
766
  context: lastUserMessage?.context ?? lastRunOptionsRef.current.context
771
767
  });
772
768
  },
773
- [runAgent, sessionUtils.syncSessionRef, debugHandlers]
769
+ [runAgent, sessionUtils.syncSessionRef]
774
770
  );
775
771
  const addOptimisticMessage = useCallback3(
776
772
  (input) => {
@@ -826,8 +822,7 @@ function useAgent(agent, options) {
826
822
  sessionId: currentSessionId,
827
823
  switchSession: sessionUtils.switchSession,
828
824
  deleteSession: sessionUtils.deleteSession,
829
- sessions: sessionUtils.sessionsList,
830
- debugData
825
+ sessions: sessionUtils.sessionsList
831
826
  };
832
827
  }
833
828
 
@@ -1037,7 +1032,17 @@ function handleEvent(event, _fullText, callbacks, clientTools, onPaused, onAutoR
1037
1032
  meta: event.meta
1038
1033
  });
1039
1034
  return { callId, result };
1040
- } catch (error) {
1035
+ } catch (handlerError) {
1036
+ callbacks.onEvent?.({
1037
+ type: "tool_call_end",
1038
+ data: {
1039
+ callId,
1040
+ toolName,
1041
+ toolType: "client",
1042
+ error: handlerError instanceof Error ? handlerError.message : String(handlerError)
1043
+ },
1044
+ meta: event.meta
1045
+ });
1041
1046
  callbacks.onPaused?.(toolName, inputs);
1042
1047
  onPaused?.({ callId, toolName, args: inputs });
1043
1048
  return null;
@@ -1435,10 +1440,6 @@ function AgentContextProvider({ children }) {
1435
1440
  const toolRegistryRef = useRef3(/* @__PURE__ */ new Map());
1436
1441
  const [, forceUpdate] = useState3({});
1437
1442
  const [allSessions, setAllSessions] = useSyncedLocalStorage(AGENT_SESSIONS_KEY, {});
1438
- const [debugData, setDebugData] = useSyncedLocalStorage(
1439
- AGENT_DEBUG_DATA_KEY,
1440
- {}
1441
- );
1442
1443
  const initializeAgent = useCallback5(
1443
1444
  (agentId, agentUrl, accessKey, options) => {
1444
1445
  const existing = activeAgentsRef.current.get(agentId);
@@ -1495,8 +1496,6 @@ function AgentContextProvider({ children }) {
1495
1496
  getRunner,
1496
1497
  allSessions,
1497
1498
  setAllSessions,
1498
- debugData,
1499
- setDebugData,
1500
1499
  runnersRef,
1501
1500
  listenersRef
1502
1501
  }),
@@ -1505,9 +1504,7 @@ function AgentContextProvider({ children }) {
1505
1504
  registerRunner,
1506
1505
  getRunner,
1507
1506
  allSessions,
1508
- setAllSessions,
1509
- debugData,
1510
- setDebugData
1507
+ setAllSessions
1511
1508
  ]
1512
1509
  );
1513
1510
  const toolContextValue = useMemo3(
@@ -1592,7 +1589,6 @@ function useAgentContext(agentId, agentUrl, accessKey, options) {
1592
1589
  inProgress: false,
1593
1590
  sessionId: "",
1594
1591
  sessions: [],
1595
- debugData: {},
1596
1592
  handleSend: async () => {
1597
1593
  },
1598
1594
  resumeTool: async () => {
@@ -1617,9 +1613,7 @@ function useAgentGlobalState() {
1617
1613
  }
1618
1614
  return {
1619
1615
  allSessions: context.allSessions,
1620
- setAllSessions: context.setAllSessions,
1621
- debugData: context.debugData,
1622
- setDebugData: context.setDebugData
1616
+ setAllSessions: context.setAllSessions
1623
1617
  };
1624
1618
  }
1625
1619
 
@@ -1663,11 +1657,11 @@ function ToolRenderer({ agentId, part }) {
1663
1657
  submit: part.paused ? handleSubmit : () => {
1664
1658
  },
1665
1659
  status: localStatus,
1666
- result: part.result
1660
+ result: part.result,
1661
+ error: part.error
1667
1662
  });
1668
1663
  }
1669
1664
  export {
1670
- AGENT_DEBUG_DATA_KEY,
1671
1665
  AGENT_SESSIONS_KEY,
1672
1666
  AgentContextProvider,
1673
1667
  AgentToolContext,