@personaai/react 0.5.1 → 0.5.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -22,7 +22,12 @@ var index_exports = {};
22
22
  __export(index_exports, {
23
23
  PersonaProvider: () => PersonaProvider,
24
24
  VERSION: () => VERSION,
25
+ createLogger: () => import_logger2.createLogger,
26
+ createNoopLogger: () => import_logger2.createNoopLogger,
27
+ getLogLevel: () => import_logger2.getLogLevel,
28
+ isLevelEnabled: () => import_logger2.isLevelEnabled,
25
29
  openSSEStream: () => openSSEStream,
30
+ setLogLevel: () => import_logger2.setLogLevel,
26
31
  supportsStreamingFetch: () => supportsStreamingFetch,
27
32
  useAgents: () => useAgents,
28
33
  useChat: () => useChat,
@@ -37,42 +42,106 @@ module.exports = __toCommonJS(index_exports);
37
42
 
38
43
  // src/context/PersonaContext.tsx
39
44
  var import_react = require("react");
45
+ var import_logger = require("@personaai/logger");
40
46
  var import_jsx_runtime = require("react/jsx-runtime");
41
47
  var PersonaContext = (0, import_react.createContext)(null);
42
48
  function PersonaProvider({
43
49
  baseUrl,
44
50
  getAuthToken,
45
51
  defaultAgentId,
52
+ logLevel,
53
+ logger: loggerProp,
46
54
  children
47
55
  }) {
48
- const normalizedBaseUrl = (0, import_react.useMemo)(() => baseUrl.replace(/\/+$/, ""), [baseUrl]);
56
+ const normalizedBaseUrl = (0, import_react.useMemo)(
57
+ () => baseUrl.replace(/\/+$/, ""),
58
+ [baseUrl]
59
+ );
60
+ const logger = (0, import_react.useMemo)(() => {
61
+ const l = loggerProp ?? (0, import_logger.createLogger)(
62
+ "react",
63
+ logLevel !== void 0 ? { level: logLevel } : void 0
64
+ );
65
+ l.debug("PersonaProvider created", {
66
+ baseUrl: normalizedBaseUrl,
67
+ hasDefaultAgentId: !!defaultAgentId
68
+ });
69
+ l.info("PersonaProvider mounted", { baseUrl: normalizedBaseUrl });
70
+ l.trace("PersonaProvider config", {
71
+ baseUrl: normalizedBaseUrl,
72
+ hasGetAuthToken: !!getAuthToken
73
+ });
74
+ return l;
75
+ }, [loggerProp, logLevel, normalizedBaseUrl, defaultAgentId, getAuthToken]);
49
76
  const value = (0, import_react.useMemo)(() => {
50
77
  async function fetchWithAuth(path, init = {}) {
51
78
  const token = getAuthToken ? await getAuthToken() : null;
52
79
  const headers = new Headers(init.headers || {});
53
80
  if (token) {
54
81
  headers.set("Authorization", `Bearer ${token}`);
82
+ logger.trace("fetchWithAuth with token", { path });
83
+ } else {
84
+ logger.trace("fetchWithAuth without token", { path });
85
+ logger.debug("fetchWithAuth no token", { path });
55
86
  }
56
87
  const cleanPath = path.startsWith("/") ? path : `/${path}`;
57
88
  const url = `${normalizedBaseUrl}${cleanPath}`;
58
- return fetch(url, {
59
- ...init,
60
- headers
89
+ logger.debug("fetchWithAuth request", {
90
+ path: cleanPath,
91
+ url,
92
+ hasToken: !!token
93
+ });
94
+ logger.trace("fetchWithAuth details", {
95
+ url,
96
+ path: cleanPath,
97
+ hasToken: !!token
61
98
  });
99
+ try {
100
+ const res = await fetch(url, {
101
+ ...init,
102
+ headers
103
+ });
104
+ logger.debug("fetchWithAuth response", {
105
+ path: cleanPath,
106
+ status: res.status,
107
+ ok: res.ok
108
+ });
109
+ if (!res.ok) {
110
+ logger.warn("fetchWithAuth non-ok", {
111
+ path: cleanPath,
112
+ status: res.status
113
+ });
114
+ } else {
115
+ logger.info("fetchWithAuth succeeded", {
116
+ path: cleanPath,
117
+ status: res.status
118
+ });
119
+ }
120
+ return res;
121
+ } catch (err) {
122
+ logger.error("fetchWithAuth failed", {
123
+ path: cleanPath,
124
+ error: err instanceof Error ? err.message : String(err)
125
+ });
126
+ throw err;
127
+ }
62
128
  }
63
129
  return {
64
130
  baseUrl: normalizedBaseUrl,
65
131
  getAuthToken,
66
132
  defaultAgentId,
67
- fetchWithAuth
133
+ fetchWithAuth,
134
+ logger
68
135
  };
69
- }, [normalizedBaseUrl, getAuthToken, defaultAgentId]);
136
+ }, [normalizedBaseUrl, getAuthToken, defaultAgentId, logger]);
70
137
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(PersonaContext.Provider, { value, children });
71
138
  }
72
139
  function usePersonaContext() {
73
140
  const context = (0, import_react.useContext)(PersonaContext);
74
141
  if (!context) {
75
- throw new Error("usePersonaContext must be used within a <PersonaProvider>");
142
+ throw new Error(
143
+ "usePersonaContext must be used within a <PersonaProvider>"
144
+ );
76
145
  }
77
146
  return context;
78
147
  }
@@ -107,7 +176,8 @@ function xhrStream(opts) {
107
176
  return new Promise((resolveStream, rejectStream) => {
108
177
  const xhr = new XMLHttpRequest();
109
178
  xhr.open("POST", opts.url);
110
- for (const [key, val] of Object.entries(opts.headers)) xhr.setRequestHeader(key, val);
179
+ for (const [key, val] of Object.entries(opts.headers))
180
+ xhr.setRequestHeader(key, val);
111
181
  let consumed = 0;
112
182
  let finished = false;
113
183
  let failure = null;
@@ -229,7 +299,10 @@ async function openSSEStream(opts) {
229
299
  ok: false,
230
300
  errorText,
231
301
  getHeader: (name) => response.headers.get(name),
232
- reader: { read: async () => ({ done: true }), cancel: () => controller.abort() }
302
+ reader: {
303
+ read: async () => ({ done: true }),
304
+ cancel: () => controller.abort()
305
+ }
233
306
  };
234
307
  }
235
308
  if (!response.body) {
@@ -255,7 +328,8 @@ async function openSSEStream(opts) {
255
328
 
256
329
  // src/hooks/useChat.ts
257
330
  function isErrorToolContent(content) {
258
- if (typeof content !== "string" || !content.trim().startsWith("{")) return false;
331
+ if (typeof content !== "string" || !content.trim().startsWith("{"))
332
+ return false;
259
333
  try {
260
334
  return JSON.parse(content)?.status === "error";
261
335
  } catch {
@@ -268,9 +342,17 @@ function persistedTraceToActivityEntries(items) {
268
342
  if (item.type === "text") {
269
343
  if (item.text) entries.push({ kind: "text", delta: item.text });
270
344
  } else {
271
- entries.push({ kind: "tool_start", toolName: item.name, args: item.argsText });
345
+ entries.push({
346
+ kind: "tool_start",
347
+ toolName: item.name,
348
+ args: item.argsText
349
+ });
272
350
  if (item.status === "completed") {
273
- entries.push({ kind: "tool_result", toolName: item.name, result: item.resultText });
351
+ entries.push({
352
+ kind: "tool_result",
353
+ toolName: item.name,
354
+ result: item.resultText
355
+ });
274
356
  }
275
357
  }
276
358
  }
@@ -279,7 +361,8 @@ function persistedTraceToActivityEntries(items) {
279
361
  function parsePresentedFile(content) {
280
362
  try {
281
363
  const parsed = JSON.parse(content);
282
- if (parsed?.status !== "success" || typeof parsed.filePath !== "string") return null;
364
+ if (parsed?.status !== "success" || typeof parsed.filePath !== "string")
365
+ return null;
283
366
  return {
284
367
  path: parsed.filePath,
285
368
  title: typeof parsed.title === "string" ? parsed.title : parsed.filePath,
@@ -320,10 +403,27 @@ function normalizePendingInterrupt(pending) {
320
403
  return null;
321
404
  }
322
405
  function useChat(options = {}) {
323
- const { defaultAgentId, fetchWithAuth, baseUrl, getAuthToken } = usePersonaContext();
406
+ const { defaultAgentId, fetchWithAuth, baseUrl, getAuthToken, logger } = usePersonaContext();
407
+ const chatLogger = (0, import_react2.useMemo)(() => logger.child("chat"), [logger]);
324
408
  const agentId = options.agentId || defaultAgentId;
325
409
  const threadId = options.threadId;
326
- const [messages, setMessages] = (0, import_react2.useState)(options.initialMessages || []);
410
+ const didLogInitRef = (0, import_react2.useRef)(false);
411
+ if (!didLogInitRef.current) {
412
+ didLogInitRef.current = true;
413
+ chatLogger.debug("useChat init", {
414
+ agentId,
415
+ threadId,
416
+ hasInitialMessages: !!options.initialMessages?.length
417
+ });
418
+ chatLogger.trace("useChat options", {
419
+ agentId,
420
+ threadId,
421
+ initialMessageCount: options.initialMessages?.length ?? 0
422
+ });
423
+ }
424
+ const [messages, setMessages] = (0, import_react2.useState)(
425
+ options.initialMessages || []
426
+ );
327
427
  const [input, setInput] = (0, import_react2.useState)("");
328
428
  const [isStreaming, setIsStreaming] = (0, import_react2.useState)(false);
329
429
  const [isLoadingHistory, setIsLoadingHistory] = (0, import_react2.useState)(false);
@@ -336,12 +436,21 @@ function useChat(options = {}) {
336
436
  const loadedThreadIdRef = (0, import_react2.useRef)(void 0);
337
437
  const stop = (0, import_react2.useCallback)(() => {
338
438
  if (abortControllerRef.current) {
439
+ chatLogger.info("stop streaming", {});
440
+ chatLogger.debug("abort controller", {
441
+ hasController: !!abortControllerRef.current
442
+ });
339
443
  abortControllerRef.current.abort();
340
444
  abortControllerRef.current = null;
341
445
  setIsStreaming(false);
446
+ chatLogger.debug("streaming stopped");
447
+ } else {
448
+ chatLogger.trace("stop called \u2014 no active stream");
342
449
  }
343
- }, []);
450
+ }, [chatLogger]);
344
451
  const clear = (0, import_react2.useCallback)(() => {
452
+ chatLogger.info("clear chat", { messageCount: messages.length });
453
+ chatLogger.debug("clear", { messageCount: messages.length });
345
454
  stop();
346
455
  setMessages([]);
347
456
  setError(null);
@@ -349,14 +458,17 @@ function useChat(options = {}) {
349
458
  setFiles({});
350
459
  setTodos([]);
351
460
  setPresentedFile(null);
352
- }, [stop]);
461
+ }, [stop, chatLogger, messages.length]);
353
462
  const loadThreadMessages = (0, import_react2.useCallback)(
354
463
  async (id) => {
464
+ chatLogger.debug("loadThreadMessages start", { threadId: id });
465
+ chatLogger.trace("loadThreadMessages", { threadId: id });
355
466
  setIsLoadingHistory(true);
356
467
  setError(null);
357
468
  try {
358
469
  const res = await fetchWithAuth(`/threads/${id}/messages`);
359
- if (!res.ok) throw new Error(`Failed to load thread history: ${res.statusText}`);
470
+ if (!res.ok)
471
+ throw new Error(`Failed to load thread history: ${res.statusText}`);
360
472
  const body = await res.json();
361
473
  const data = body?.data ?? body;
362
474
  const raw = data?.messages ?? [];
@@ -368,42 +480,98 @@ function useChat(options = {}) {
368
480
  createdAt: /* @__PURE__ */ new Date(),
369
481
  toolCalls: m.toolCalls?.map((tc) => {
370
482
  const trace = subagentTraces[tc.toolCallId];
371
- return Array.isArray(trace) && trace.length > 0 ? { ...tc, subagentActivity: persistedTraceToActivityEntries(trace) } : tc;
483
+ return Array.isArray(trace) && trace.length > 0 ? {
484
+ ...tc,
485
+ subagentActivity: persistedTraceToActivityEntries(trace)
486
+ } : tc;
372
487
  })
373
488
  }));
374
489
  setMessages(loaded);
375
490
  setInterrupt(normalizePendingInterrupt(data?.pendingInterrupt));
376
491
  setFiles(normalizeWorkspaceFiles(data?.state?.files ?? {}));
377
492
  setTodos(data?.state?.todos ?? []);
493
+ chatLogger.info("loadThreadMessages succeeded", {
494
+ threadId: id,
495
+ messageCount: loaded.length
496
+ });
497
+ chatLogger.debug("loadThreadMessages completed", {
498
+ threadId: id,
499
+ messageCount: loaded.length
500
+ });
378
501
  return loaded;
379
502
  } catch (err) {
380
503
  const errorObj = err instanceof Error ? err : new Error(String(err));
504
+ chatLogger.warn("loadThreadMessages failed", {
505
+ threadId: id,
506
+ error: errorObj.message
507
+ });
508
+ chatLogger.error("loadThreadMessages error", {
509
+ threadId: id,
510
+ error: errorObj.message
511
+ });
381
512
  setError(errorObj);
382
513
  return [];
383
514
  } finally {
384
515
  setIsLoadingHistory(false);
516
+ chatLogger.trace("loadThreadMessages end", { threadId: id });
385
517
  }
386
518
  },
387
- [fetchWithAuth]
519
+ [fetchWithAuth, chatLogger]
388
520
  );
389
521
  (0, import_react2.useEffect)(() => {
390
- if (!threadId || isStreaming) return;
391
- if (loadedThreadIdRef.current === threadId) return;
392
- if (messages.length > 0) return;
522
+ if (!threadId || isStreaming) {
523
+ chatLogger.trace("auto-load skipped", { threadId, isStreaming });
524
+ return;
525
+ }
526
+ if (loadedThreadIdRef.current === threadId) {
527
+ chatLogger.trace("auto-load already loaded", { threadId });
528
+ return;
529
+ }
530
+ if (messages.length > 0) {
531
+ chatLogger.trace("auto-load has messages", {
532
+ threadId,
533
+ count: messages.length
534
+ });
535
+ return;
536
+ }
393
537
  loadedThreadIdRef.current = threadId;
538
+ chatLogger.info("auto-load thread history", { threadId });
539
+ chatLogger.debug("loadThreadMessages trigger", { threadId });
394
540
  void loadThreadMessages(threadId);
395
- }, [threadId, isStreaming, messages.length, loadThreadMessages]);
541
+ }, [threadId, isStreaming, messages.length, loadThreadMessages, chatLogger]);
396
542
  const sendMessage = (0, import_react2.useCallback)(
397
543
  async (contentToSend, overrideOptions) => {
398
544
  const prompt = (contentToSend ?? input).trim();
399
- if (!prompt || isStreaming) return;
545
+ if (!prompt || isStreaming) {
546
+ chatLogger.trace("sendMessage skipped", {
547
+ hasPrompt: !!prompt,
548
+ isStreaming
549
+ });
550
+ return;
551
+ }
400
552
  const targetAgentId = overrideOptions?.agentId || agentId;
401
553
  if (!targetAgentId) {
402
554
  const err = new Error("No Agent ID specified for useChat.");
555
+ chatLogger.warn("sendMessage no agentId", {});
556
+ chatLogger.error("sendMessage failed \u2014 no agent", {
557
+ error: err.message
558
+ });
403
559
  setError(err);
404
560
  options.onError?.(err);
405
561
  return;
406
562
  }
563
+ chatLogger.debug("sendMessage start", {
564
+ promptPreview: prompt.slice(0, 100),
565
+ agentId: targetAgentId,
566
+ threadId: threadId ?? overrideOptions?.threadId,
567
+ hasResume: !!overrideOptions?.resume,
568
+ messageCount: messages.length
569
+ });
570
+ chatLogger.trace("sendMessage details", {
571
+ agentId: targetAgentId,
572
+ promptPreview: prompt.slice(0, 200),
573
+ hasResume: !!overrideOptions?.resume
574
+ });
407
575
  const userMessage = {
408
576
  id: `user-${Date.now()}-${Math.random().toString(36).slice(2, 7)}`,
409
577
  role: "user",
@@ -440,7 +608,13 @@ function useChat(options = {}) {
440
608
  content: m.content
441
609
  }));
442
610
  const resolvedThreadId = await (overrideOptions?.threadId ?? options.threadId);
611
+ chatLogger.trace("resolved threadId", { threadId: resolvedThreadId });
443
612
  const token = getAuthToken ? await getAuthToken() : null;
613
+ chatLogger.debug("opening SSE stream", {
614
+ agentId: targetAgentId,
615
+ hasToken: !!token,
616
+ hasThreadId: !!resolvedThreadId
617
+ });
444
618
  const stream = await openSSEStream({
445
619
  url: `${baseUrl}/chat`,
446
620
  headers: {
@@ -456,28 +630,53 @@ function useChat(options = {}) {
456
630
  signal: controller.signal
457
631
  });
458
632
  if (!stream.ok) {
459
- throw new Error(`Chat error (${stream.status}): ${stream.errorText ?? "Stream failed"}`);
633
+ chatLogger.warn("SSE stream not ok", {
634
+ status: stream.status,
635
+ errorText: stream.errorText
636
+ });
637
+ chatLogger.error("chat stream failed", {
638
+ agentId: targetAgentId,
639
+ status: stream.status,
640
+ error: stream.errorText
641
+ });
642
+ throw new Error(
643
+ `Chat error (${stream.status}): ${stream.errorText ?? "Stream failed"}`
644
+ );
460
645
  }
646
+ chatLogger.debug("SSE stream opened", {
647
+ agentId: targetAgentId,
648
+ status: stream.status
649
+ });
650
+ chatLogger.info("chat stream started", {
651
+ agentId: targetAgentId,
652
+ threadId: resolvedThreadId
653
+ });
461
654
  const reader = stream.reader;
462
655
  let buffer = "";
463
656
  let accumulatedText = "";
464
657
  const toolCallsMap = /* @__PURE__ */ new Map();
658
+ let streamSeq = 0;
465
659
  let activeReasoningId = null;
466
660
  const reasoningById = /* @__PURE__ */ new Map();
467
661
  const patchAssistant = (patch) => {
468
662
  setMessages(
469
663
  (prev) => prev.map(
470
- (msg) => msg.id === assistantMessageId ? { ...msg, toolCalls: Array.from(toolCallsMap.values()), ...patch } : msg
664
+ (msg) => msg.id === assistantMessageId ? {
665
+ ...msg,
666
+ toolCalls: Array.from(toolCallsMap.values()),
667
+ ...patch
668
+ } : msg
471
669
  )
472
670
  );
473
671
  };
474
- const insertReasoningMessage = (id) => {
672
+ const insertReasoningMessage = (id, seq) => {
475
673
  const msg = {
476
674
  id,
477
675
  role: "reasoning",
478
676
  content: "",
479
677
  createdAt: /* @__PURE__ */ new Date(),
480
- isStreaming: true
678
+ isStreaming: true,
679
+ seq
481
680
  };
482
681
  setMessages((prev) => {
483
682
  const idx = prev.findIndex((m) => m.id === assistantMessageId);
@@ -500,11 +699,19 @@ function useChat(options = {}) {
500
699
  if (raw === "[DONE]") break;
501
700
  try {
502
701
  const event = JSON.parse(raw);
702
+ chatLogger.trace("stream event", { type: event.type, event });
503
703
  options.onEvent?.(event);
504
704
  if (event.type === "TEXT_MESSAGE_CHUNK" && event.delta) {
705
+ chatLogger.debug("text chunk", {
706
+ deltaLength: event.delta.length
707
+ });
505
708
  accumulatedText += event.delta;
506
709
  patchAssistant({ content: accumulatedText, isStreaming: true });
507
710
  } else if (event.type === "TOOL_CALL_CHUNK" && event.toolCallId) {
711
+ chatLogger.debug("tool call chunk", {
712
+ toolCallId: event.toolCallId,
713
+ toolCallName: event.toolCallName
714
+ });
508
715
  const existing = toolCallsMap.get(event.toolCallId);
509
716
  if (existing) {
510
717
  existing.args = (existing.args || "") + (event.delta || "");
@@ -512,54 +719,86 @@ function useChat(options = {}) {
512
719
  toolCallsMap.set(event.toolCallId, {
513
720
  toolCallId: event.toolCallId,
514
721
  toolName: event.toolCallName || "",
515
- args: event.delta || ""
722
+ args: event.delta || "",
723
+ seq: streamSeq++
516
724
  });
517
725
  }
518
726
  patchAssistant({});
519
727
  } else if (event.type === "TOOL_CALL_RESULT") {
728
+ chatLogger.debug("tool call result", {
729
+ toolCallId: event.toolCallId
730
+ });
520
731
  const existing = toolCallsMap.get(event.toolCallId);
521
732
  if (existing) {
522
733
  existing.result = event.content;
523
734
  existing.isError = isErrorToolContent(event.content);
735
+ if (existing.isError)
736
+ chatLogger.warn("tool call error", {
737
+ toolCallId: event.toolCallId
738
+ });
524
739
  if (existing.toolName === "present_file" && !existing.isError) {
525
740
  const presented = parsePresentedFile(event.content);
526
- if (presented) setPresentedFile(presented);
741
+ if (presented) {
742
+ chatLogger.info("present_file", { path: presented.path });
743
+ setPresentedFile(presented);
744
+ }
527
745
  }
528
746
  patchAssistant({});
529
747
  }
530
748
  } else if (event.type === "STATE_SNAPSHOT") {
749
+ chatLogger.debug("state snapshot", {
750
+ fileCount: Object.keys(event.snapshot.files ?? {}).length,
751
+ todoCount: event.snapshot.todos?.length ?? 0
752
+ });
531
753
  setFiles(normalizeWorkspaceFiles(event.snapshot.files));
532
754
  setTodos(event.snapshot.todos);
533
755
  } else if (event.type === "REASONING_MESSAGE_START" && event.messageId) {
756
+ chatLogger.debug("reasoning start", {
757
+ messageId: event.messageId
758
+ });
534
759
  activeReasoningId = event.messageId;
535
760
  reasoningById.set(event.messageId, { content: "" });
536
- insertReasoningMessage(event.messageId);
761
+ insertReasoningMessage(event.messageId, streamSeq++);
537
762
  } else if (event.type === "REASONING_MESSAGE_CONTENT") {
538
763
  let rid = event.messageId || activeReasoningId || "";
539
764
  if (!rid || !reasoningById.has(rid)) {
540
765
  rid = rid || `reasoning-${Date.now()}-${Math.random().toString(36).slice(2, 7)}`;
541
766
  activeReasoningId = rid;
542
767
  reasoningById.set(rid, { content: "" });
543
- insertReasoningMessage(rid);
768
+ insertReasoningMessage(rid, streamSeq++);
769
+ chatLogger.debug("reasoning lazy start", { messageId: rid });
544
770
  }
545
771
  const entry = reasoningById.get(rid);
546
772
  entry.content += event.delta;
773
+ chatLogger.trace("reasoning content", {
774
+ messageId: rid,
775
+ deltaLength: event.delta?.length ?? 0
776
+ });
547
777
  setMessages(
548
778
  (prev) => prev.map(
549
779
  (m) => m.id === rid ? { ...m, content: entry.content, isStreaming: true } : m
550
780
  )
551
781
  );
552
782
  } else if (event.type === "REASONING_END") {
783
+ chatLogger.debug("reasoning end", {
784
+ messageId: activeReasoningId
785
+ });
553
786
  const rid = activeReasoningId;
554
787
  activeReasoningId = null;
555
788
  if (rid) {
556
789
  setMessages(
557
- (prev) => prev.map((m) => m.id === rid ? { ...m, isStreaming: false } : m)
790
+ (prev) => prev.map(
791
+ (m) => m.id === rid ? { ...m, isStreaming: false } : m
792
+ )
558
793
  );
559
794
  }
560
795
  } else if (event.type === "CUSTOM") {
796
+ chatLogger.debug("custom event", { name: event.name });
561
797
  if (event.name === "hitl_request") {
562
798
  const value2 = event.value;
799
+ chatLogger.info("hitl interrupt", {
800
+ actionCount: value2.actionRequests?.length ?? 0
801
+ });
563
802
  setInterrupt({
564
803
  kind: "hitl",
565
804
  actionRequests: value2.actionRequests,
@@ -567,22 +806,49 @@ function useChat(options = {}) {
567
806
  });
568
807
  } else if (event.name === "clarification_request") {
569
808
  const value2 = event.value;
570
- setInterrupt({ kind: "clarification", questions: value2.questions });
809
+ chatLogger.info("clarification interrupt", {
810
+ questionCount: value2.questions?.length ?? 0
811
+ });
812
+ setInterrupt({
813
+ kind: "clarification",
814
+ questions: value2.questions
815
+ });
571
816
  } else if (event.name === "subagent_activity") {
572
817
  const { toolCallId, ...entry } = event.value;
818
+ chatLogger.trace("subagent activity", {
819
+ toolCallId,
820
+ kind: entry.kind
821
+ });
573
822
  const existing = toolCallsMap.get(toolCallId);
574
823
  if (existing) {
575
- existing.subagentActivity = [...existing.subagentActivity || [], entry];
824
+ existing.subagentActivity = [
825
+ ...existing.subagentActivity || [],
826
+ entry
827
+ ];
576
828
  patchAssistant({});
577
829
  }
578
830
  }
579
831
  } else if (event.type === "RUN_ERROR") {
832
+ chatLogger.warn("run error", {
833
+ message: event.message,
834
+ code: event.code
835
+ });
836
+ chatLogger.error("stream run error", {
837
+ code: event.code,
838
+ message: event.message
839
+ });
580
840
  throw new Error(event.message || "Stream error from agent");
841
+ } else {
842
+ chatLogger.trace("unhandled event", { type: event.type });
581
843
  }
582
844
  } catch (e) {
583
845
  if (e instanceof Error && e.message.startsWith("Stream error")) {
584
846
  throw e;
585
847
  }
848
+ chatLogger.warn("event parse error", {
849
+ raw: raw.slice(0, 200),
850
+ error: e instanceof Error ? e.message : String(e)
851
+ });
586
852
  }
587
853
  }
588
854
  }
@@ -595,11 +861,25 @@ function useChat(options = {}) {
595
861
  toolCalls: Array.from(toolCallsMap.values())
596
862
  };
597
863
  setMessages(
598
- (prev) => prev.map((msg) => msg.id === assistantMessageId ? finalMessage : msg)
864
+ (prev) => prev.map(
865
+ (msg) => msg.id === assistantMessageId ? finalMessage : msg
866
+ )
599
867
  );
868
+ chatLogger.info("sendMessage succeeded", {
869
+ agentId: targetAgentId,
870
+ textLength: accumulatedText.length,
871
+ toolCallCount: toolCallsMap.size
872
+ });
873
+ chatLogger.debug("sendMessage completed", {
874
+ agentId: targetAgentId,
875
+ textLength: accumulatedText.length,
876
+ eventCount: toolCallsMap.size + 1
877
+ });
600
878
  options.onFinish?.(finalMessage);
601
879
  } catch (err) {
602
880
  if (controller.signal.aborted) {
881
+ chatLogger.info("sendMessage aborted", { agentId: targetAgentId });
882
+ chatLogger.debug("stream aborted", { agentId: targetAgentId });
603
883
  setMessages(
604
884
  (prev) => prev.map(
605
885
  (msg) => msg.id === assistantMessageId ? { ...msg, isStreaming: false } : msg
@@ -608,6 +888,14 @@ function useChat(options = {}) {
608
888
  return;
609
889
  }
610
890
  const errorObj = err instanceof Error ? err : new Error(String(err));
891
+ chatLogger.warn("sendMessage failed", {
892
+ agentId: targetAgentId,
893
+ error: errorObj.message
894
+ });
895
+ chatLogger.error("sendMessage error", {
896
+ agentId: targetAgentId,
897
+ error: errorObj.message
898
+ });
611
899
  setError(errorObj);
612
900
  options.onError?.(errorObj);
613
901
  setMessages(
@@ -623,22 +911,48 @@ function useChat(options = {}) {
623
911
  setIsStreaming(false);
624
912
  abortControllerRef.current = null;
625
913
  finalizeReasoning();
914
+ chatLogger.debug("sendMessage finally", {
915
+ agentId: targetAgentId,
916
+ isStreaming: false
917
+ });
918
+ chatLogger.trace("sendMessage end", { agentId: targetAgentId });
626
919
  }
627
920
  },
628
- [agentId, baseUrl, getAuthToken, input, isStreaming, messages, options]
921
+ [
922
+ agentId,
923
+ baseUrl,
924
+ getAuthToken,
925
+ input,
926
+ isStreaming,
927
+ messages,
928
+ options,
929
+ chatLogger,
930
+ threadId
931
+ ]
932
+ );
933
+ const handleInputChange = (0, import_react2.useCallback)(
934
+ (e) => {
935
+ chatLogger.trace("handleInputChange", { length: e.target.value.length });
936
+ setInput(e.target.value);
937
+ },
938
+ [chatLogger]
629
939
  );
630
- const handleInputChange = (0, import_react2.useCallback)((e) => {
631
- setInput(e.target.value);
632
- }, []);
633
940
  const handleSubmit = (0, import_react2.useCallback)(
634
941
  (e) => {
635
942
  if (e) e.preventDefault();
943
+ chatLogger.debug("handleSubmit", {});
636
944
  void sendMessage();
637
945
  },
638
- [sendMessage]
946
+ [sendMessage, chatLogger]
639
947
  );
640
948
  const reload = (0, import_react2.useCallback)(() => {
641
- if (messages.length === 0 || isStreaming) return;
949
+ if (messages.length === 0 || isStreaming) {
950
+ chatLogger.trace("reload skipped", {
951
+ messageCount: messages.length,
952
+ isStreaming
953
+ });
954
+ return;
955
+ }
642
956
  let lastUserIndex = -1;
643
957
  for (let i = messages.length - 1; i >= 0; i--) {
644
958
  if (messages[i].role === "user") {
@@ -646,19 +960,42 @@ function useChat(options = {}) {
646
960
  break;
647
961
  }
648
962
  }
649
- if (lastUserIndex === -1) return;
963
+ if (lastUserIndex === -1) {
964
+ chatLogger.warn("reload no user message", {});
965
+ return;
966
+ }
650
967
  const lastUserMessage = messages[lastUserIndex];
968
+ chatLogger.info("reload", { messageId: lastUserMessage.id });
969
+ chatLogger.debug("reload last user", {
970
+ preview: lastUserMessage.content.slice(0, 100)
971
+ });
651
972
  setMessages(messages.slice(0, lastUserIndex));
652
973
  void sendMessage(lastUserMessage.content);
653
- }, [isStreaming, messages, sendMessage]);
974
+ }, [isStreaming, messages, sendMessage, chatLogger]);
654
975
  const resumeInterrupt = (0, import_react2.useCallback)(
655
- (resume, displayContent) => sendMessage(displayContent, { resume }),
656
- [sendMessage]
976
+ (resume, displayContent) => {
977
+ chatLogger.info("resumeInterrupt", {
978
+ kind: resume.decisions ? "hitl" : "clarification",
979
+ preview: displayContent.slice(0, 50)
980
+ });
981
+ return sendMessage(displayContent, { resume });
982
+ },
983
+ [sendMessage, chatLogger]
657
984
  );
658
- const dismissPresentedFile = (0, import_react2.useCallback)(() => setPresentedFile(null), []);
985
+ const dismissPresentedFile = (0, import_react2.useCallback)(() => {
986
+ chatLogger.debug("dismissPresentedFile", {});
987
+ setPresentedFile(null);
988
+ }, [chatLogger]);
659
989
  const openWorkspaceFile = (0, import_react2.useCallback)(
660
- (path) => setPresentedFile({ path, title: path.split("/").pop() || path, description: "" }),
661
- []
990
+ (path) => {
991
+ chatLogger.debug("openWorkspaceFile", { path });
992
+ setPresentedFile({
993
+ path,
994
+ title: path.split("/").pop() || path,
995
+ description: ""
996
+ });
997
+ },
998
+ [chatLogger]
662
999
  );
663
1000
  return {
664
1001
  messages,
@@ -690,7 +1027,10 @@ function useChat(options = {}) {
690
1027
  var import_react3 = require("react");
691
1028
  function useMemory(autoFetch = true) {
692
1029
  const { fetchWithAuth } = usePersonaContext();
693
- const [memory, setMemory] = (0, import_react3.useState)({ userFiles: [], agentMemories: [] });
1030
+ const [memory, setMemory] = (0, import_react3.useState)({
1031
+ userFiles: [],
1032
+ agentMemories: []
1033
+ });
694
1034
  const [isLoading, setIsLoading] = (0, import_react3.useState)(false);
695
1035
  const [error, setError] = (0, import_react3.useState)(null);
696
1036
  const fetchMemory = (0, import_react3.useCallback)(async () => {
@@ -718,7 +1058,8 @@ function useMemory(autoFetch = true) {
718
1058
  if (params.scope) query.set("scope", params.scope);
719
1059
  if (params.agentId) query.set("agentId", params.agentId);
720
1060
  const res = await fetchWithAuth(`/memory/file?${query.toString()}`);
721
- if (!res.ok) throw new Error(`Failed to get memory file: ${res.statusText}`);
1061
+ if (!res.ok)
1062
+ throw new Error(`Failed to get memory file: ${res.statusText}`);
722
1063
  return await res.json();
723
1064
  },
724
1065
  [fetchWithAuth]
@@ -730,7 +1071,8 @@ function useMemory(autoFetch = true) {
730
1071
  headers: { "Content-Type": "application/json" },
731
1072
  body: JSON.stringify(params)
732
1073
  });
733
- if (!res.ok) throw new Error(`Failed to write memory file: ${res.statusText}`);
1074
+ if (!res.ok)
1075
+ throw new Error(`Failed to write memory file: ${res.statusText}`);
734
1076
  const updated = await res.json();
735
1077
  void fetchMemory();
736
1078
  return updated;
@@ -745,7 +1087,8 @@ function useMemory(autoFetch = true) {
745
1087
  const res = await fetchWithAuth(`/memory/file?${query.toString()}`, {
746
1088
  method: "DELETE"
747
1089
  });
748
- if (!res.ok) throw new Error(`Failed to delete memory file: ${res.statusText}`);
1090
+ if (!res.ok)
1091
+ throw new Error(`Failed to delete memory file: ${res.statusText}`);
749
1092
  void fetchMemory();
750
1093
  },
751
1094
  [fetchWithAuth, fetchMemory]
@@ -799,7 +1142,8 @@ function useThreads(autoFetch = true) {
799
1142
  headers: { "Content-Type": "application/json" },
800
1143
  body: JSON.stringify({ agentId: targetAgentId })
801
1144
  });
802
- if (!res.ok) throw new Error(`Failed to create thread: ${res.statusText}`);
1145
+ if (!res.ok)
1146
+ throw new Error(`Failed to create thread: ${res.statusText}`);
803
1147
  const data = await res.json();
804
1148
  const created = data?.data ?? data;
805
1149
  void fetchThreads();
@@ -809,8 +1153,11 @@ function useThreads(autoFetch = true) {
809
1153
  );
810
1154
  const deleteThread = (0, import_react4.useCallback)(
811
1155
  async (threadId) => {
812
- const res = await fetchWithAuth(`/threads/${threadId}`, { method: "DELETE" });
813
- if (!res.ok) throw new Error(`Failed to delete thread: ${res.statusText}`);
1156
+ const res = await fetchWithAuth(`/threads/${threadId}`, {
1157
+ method: "DELETE"
1158
+ });
1159
+ if (!res.ok)
1160
+ throw new Error(`Failed to delete thread: ${res.statusText}`);
814
1161
  setThreads((prev) => prev.filter((t) => t._id !== threadId));
815
1162
  },
816
1163
  [fetchWithAuth]
@@ -822,7 +1169,8 @@ function useThreads(autoFetch = true) {
822
1169
  headers: { "Content-Type": "application/json" },
823
1170
  body: JSON.stringify({ ids: threadIds })
824
1171
  });
825
- if (!res.ok) throw new Error(`Failed to bulk-delete threads: ${res.statusText}`);
1172
+ if (!res.ok)
1173
+ throw new Error(`Failed to bulk-delete threads: ${res.statusText}`);
826
1174
  const data = await res.json();
827
1175
  const result = data?.data ?? data;
828
1176
  const deletedSet = new Set(result.deleted);
@@ -844,10 +1192,13 @@ function useThreads(autoFetch = true) {
844
1192
  headers: { "Content-Type": "application/json" },
845
1193
  body: JSON.stringify(input)
846
1194
  });
847
- if (!res.ok) throw new Error(`Failed to update thread: ${res.statusText}`);
1195
+ if (!res.ok)
1196
+ throw new Error(`Failed to update thread: ${res.statusText}`);
848
1197
  const data = await res.json();
849
1198
  const updated = data?.data ?? data;
850
- setThreads((prev) => prev.map((t) => t._id === threadId ? { ...t, ...updated } : t));
1199
+ setThreads(
1200
+ (prev) => prev.map((t) => t._id === threadId ? { ...t, ...updated } : t)
1201
+ );
851
1202
  return updated;
852
1203
  },
853
1204
  [fetchWithAuth]
@@ -959,19 +1310,17 @@ function useFiles(autoFetch = true) {
959
1310
  headers: { "Content-Type": "application/json" },
960
1311
  body: JSON.stringify({ ids: fileIds })
961
1312
  });
962
- if (!res.ok) throw new Error(`Failed to bulk-delete files: ${res.statusText}`);
1313
+ if (!res.ok)
1314
+ throw new Error(`Failed to bulk-delete files: ${res.statusText}`);
963
1315
  const idSet = new Set(fileIds);
964
1316
  setFiles((prev) => prev.filter((f) => !idSet.has(f.id)));
965
1317
  return await res.json();
966
1318
  },
967
1319
  [fetchWithAuth]
968
1320
  );
969
- const getDownloadUrl = (0, import_react5.useCallback)(
970
- (fileId) => {
971
- return `/files/${fileId}`;
972
- },
973
- []
974
- );
1321
+ const getDownloadUrl = (0, import_react5.useCallback)((fileId) => {
1322
+ return `/files/${fileId}`;
1323
+ }, []);
975
1324
  (0, import_react5.useEffect)(() => {
976
1325
  if (autoFetch) {
977
1326
  void fetchFiles();
@@ -1083,8 +1432,11 @@ function useMcpConnections(options = {}) {
1083
1432
  try {
1084
1433
  const returnTo = options.returnTo ?? (typeof window !== "undefined" ? window.location.href : void 0);
1085
1434
  const query = returnTo ? `?returnTo=${encodeURIComponent(returnTo)}` : "";
1086
- const res = await fetchWithAuth(`/agents/${agentId}/mcp-connections${query}`);
1087
- if (!res.ok) throw new Error(`Failed to load MCP connections: ${res.statusText}`);
1435
+ const res = await fetchWithAuth(
1436
+ `/agents/${agentId}/mcp-connections${query}`
1437
+ );
1438
+ if (!res.ok)
1439
+ throw new Error(`Failed to load MCP connections: ${res.statusText}`);
1088
1440
  const data = await res.json();
1089
1441
  const items = Array.isArray(data) ? data : data?.items || [];
1090
1442
  setConnections(items);
@@ -1111,12 +1463,18 @@ function useMcpConnections(options = {}) {
1111
1463
  }
1112
1464
 
1113
1465
  // src/index.ts
1114
- var VERSION = "0.4.0";
1466
+ var import_logger2 = require("@personaai/logger");
1467
+ var VERSION = "0.5.4";
1115
1468
  // Annotate the CommonJS export names for ESM import in node:
1116
1469
  0 && (module.exports = {
1117
1470
  PersonaProvider,
1118
1471
  VERSION,
1472
+ createLogger,
1473
+ createNoopLogger,
1474
+ getLogLevel,
1475
+ isLevelEnabled,
1119
1476
  openSSEStream,
1477
+ setLogLevel,
1120
1478
  supportsStreamingFetch,
1121
1479
  useAgents,
1122
1480
  useChat,