@personaai/react 0.9.0 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -286,7 +286,7 @@ async function openSSEStream(opts) {
286
286
  };
287
287
  }
288
288
 
289
- // src/hooks/useChat.ts
289
+ // src/hooks/streamEventHelpers.ts
290
290
  function isErrorToolContent(content) {
291
291
  if (typeof content !== "string" || !content.trim().startsWith("{"))
292
292
  return false;
@@ -332,6 +332,38 @@ function parsePresentedFile(content) {
332
332
  return null;
333
333
  }
334
334
  }
335
+ function normalizeWorkspaceFiles(raw) {
336
+ const normalized = {};
337
+ for (const [path, file] of Object.entries(raw || {})) {
338
+ normalized[path] = {
339
+ content: file.content,
340
+ size: file.size,
341
+ createdAt: file.created_at,
342
+ modifiedAt: file.modified_at
343
+ };
344
+ }
345
+ return normalized;
346
+ }
347
+ function normalizePendingInterrupt(pending) {
348
+ if (!pending || typeof pending !== "object") return null;
349
+ const p = pending;
350
+ if (p.kind === "hitl") {
351
+ return {
352
+ kind: "hitl",
353
+ actionRequests: p.value?.actionRequests ?? [],
354
+ reviewConfigs: p.value?.reviewConfigs ?? []
355
+ };
356
+ }
357
+ if (p.kind === "clarification") {
358
+ return {
359
+ kind: "clarification",
360
+ questions: p.value?.questions ?? []
361
+ };
362
+ }
363
+ return null;
364
+ }
365
+
366
+ // src/hooks/useChat.ts
335
367
  function parseSandboxCommand(tc) {
336
368
  let command = tc.args ?? "";
337
369
  try {
@@ -363,36 +395,6 @@ function parseSandboxCommand(tc) {
363
395
  seq: tc.seq
364
396
  };
365
397
  }
366
- function normalizeWorkspaceFiles(raw) {
367
- const normalized = {};
368
- for (const [path, file] of Object.entries(raw || {})) {
369
- normalized[path] = {
370
- content: file.content,
371
- size: file.size,
372
- createdAt: file.created_at,
373
- modifiedAt: file.modified_at
374
- };
375
- }
376
- return normalized;
377
- }
378
- function normalizePendingInterrupt(pending) {
379
- if (!pending || typeof pending !== "object") return null;
380
- const p = pending;
381
- if (p.kind === "hitl") {
382
- return {
383
- kind: "hitl",
384
- actionRequests: p.value?.actionRequests ?? [],
385
- reviewConfigs: p.value?.reviewConfigs ?? []
386
- };
387
- }
388
- if (p.kind === "clarification") {
389
- return {
390
- kind: "clarification",
391
- questions: p.value?.questions ?? []
392
- };
393
- }
394
- return null;
395
- }
396
398
  function useChat(options = {}) {
397
399
  const { defaultAgentId, fetchWithAuth, baseUrl, getAuthToken, logger } = usePersonaContext();
398
400
  const chatLogger = useMemo2(() => logger.child("chat"), [logger]);
@@ -457,7 +459,707 @@ function useChat(options = {}) {
457
459
  chatLogger.trace("stop called \u2014 no active stream");
458
460
  }
459
461
  }, [chatLogger]);
460
- const clear = useCallback(() => {
462
+ const clear = useCallback(() => {
463
+ chatLogger.info("clear chat", { messageCount: messages.length });
464
+ chatLogger.debug("clear", { messageCount: messages.length });
465
+ stop();
466
+ setMessages([]);
467
+ setError(null);
468
+ setInterrupt(null);
469
+ setFiles({});
470
+ setTodos([]);
471
+ setPresentedFile(null);
472
+ loadedThreadIdRef.current = void 0;
473
+ }, [stop, chatLogger, messages.length]);
474
+ const startNewChat = useCallback(() => {
475
+ chatLogger.info("startNewChat \u2014 entering ephemeral mode");
476
+ stop();
477
+ setMessages([]);
478
+ setError(null);
479
+ setInterrupt(null);
480
+ setFiles({});
481
+ setTodos([]);
482
+ setPresentedFile(null);
483
+ setInput("");
484
+ loadedThreadIdRef.current = void 0;
485
+ voiceThreadRef.current = void 0;
486
+ voicePrevLenRef.current = 0;
487
+ voiceStreamingIdRef.current = null;
488
+ voiceUserPartialIdRef.current = null;
489
+ setInternalThreadId(void 0);
490
+ }, [stop, chatLogger]);
491
+ const loadThreadMessages = useCallback(
492
+ async (id) => {
493
+ chatLogger.debug("loadThreadMessages start", { threadId: id });
494
+ chatLogger.trace("loadThreadMessages", { threadId: id });
495
+ setIsLoadingHistory(true);
496
+ setError(null);
497
+ try {
498
+ const res = await fetchWithAuth(`/threads/${id}/messages`);
499
+ if (!res.ok)
500
+ throw new Error(`Failed to load thread history: ${res.statusText}`);
501
+ const body = await res.json();
502
+ const data = body?.data ?? body;
503
+ const raw = data?.messages ?? [];
504
+ const subagentTraces = data?.subagentTraces ?? {};
505
+ const loaded = raw.map((m, i) => ({
506
+ id: m.id || `history-${id}-${i}`,
507
+ role: m.role,
508
+ content: m.content,
509
+ createdAt: /* @__PURE__ */ new Date(),
510
+ toolCalls: m.toolCalls?.map((tc) => {
511
+ const trace = subagentTraces[tc.toolCallId];
512
+ return Array.isArray(trace) && trace.length > 0 ? {
513
+ ...tc,
514
+ subagentActivity: persistedTraceToActivityEntries(trace)
515
+ } : tc;
516
+ })
517
+ }));
518
+ setMessages(loaded);
519
+ setInterrupt(normalizePendingInterrupt(data?.pendingInterrupt));
520
+ setFiles(normalizeWorkspaceFiles(data?.state?.files ?? {}));
521
+ setTodos(data?.state?.todos ?? []);
522
+ loadedThreadIdRef.current = id;
523
+ chatLogger.info("loadThreadMessages succeeded", {
524
+ threadId: id,
525
+ messageCount: loaded.length
526
+ });
527
+ chatLogger.debug("loadThreadMessages completed", {
528
+ threadId: id,
529
+ messageCount: loaded.length
530
+ });
531
+ return loaded;
532
+ } catch (err) {
533
+ const errorObj = err instanceof Error ? err : new Error(String(err));
534
+ chatLogger.warn("loadThreadMessages failed", {
535
+ threadId: id,
536
+ error: errorObj.message
537
+ });
538
+ chatLogger.error("loadThreadMessages error", {
539
+ threadId: id,
540
+ error: errorObj.message
541
+ });
542
+ setError(errorObj);
543
+ if (loadedThreadIdRef.current === id) loadedThreadIdRef.current = void 0;
544
+ return [];
545
+ } finally {
546
+ setIsLoadingHistory(false);
547
+ chatLogger.trace("loadThreadMessages end", { threadId: id });
548
+ }
549
+ },
550
+ [fetchWithAuth, chatLogger]
551
+ );
552
+ useEffect(() => {
553
+ if (!effectiveThreadId || isStreaming) {
554
+ chatLogger.trace("auto-load skipped", { threadId: effectiveThreadId, isStreaming });
555
+ return;
556
+ }
557
+ if (loadedThreadIdRef.current === effectiveThreadId) {
558
+ chatLogger.trace("auto-load already loaded", { threadId: effectiveThreadId });
559
+ return;
560
+ }
561
+ if (messages.length > 0) {
562
+ chatLogger.trace("auto-load has messages", {
563
+ threadId: effectiveThreadId,
564
+ count: messages.length
565
+ });
566
+ return;
567
+ }
568
+ chatLogger.info("auto-load thread history", { threadId: effectiveThreadId });
569
+ chatLogger.debug("loadThreadMessages trigger", { threadId: effectiveThreadId });
570
+ void loadThreadMessages(effectiveThreadId);
571
+ }, [effectiveThreadId, isStreaming, messages.length, loadThreadMessages, chatLogger]);
572
+ const voice = options.voice;
573
+ useEffect(() => {
574
+ if (!voice) return;
575
+ if (voiceThreadRef.current !== effectiveThreadId) {
576
+ voiceThreadRef.current = effectiveThreadId;
577
+ voicePrevLenRef.current = voice.transcript.length;
578
+ voiceStreamingIdRef.current = null;
579
+ voiceUserPartialIdRef.current = null;
580
+ return;
581
+ }
582
+ const isVoiceActive = voice.state !== "idle" && voice.state !== "ended" && voice.state !== "error";
583
+ const curLen = voice.transcript.length;
584
+ if (curLen < voicePrevLenRef.current) {
585
+ voicePrevLenRef.current = 0;
586
+ voiceStreamingIdRef.current = null;
587
+ voiceUserPartialIdRef.current = null;
588
+ }
589
+ if (!isVoiceActive) {
590
+ if (curLen > voicePrevLenRef.current) {
591
+ const pendingLines = voice.transcript.slice(voicePrevLenRef.current);
592
+ voicePrevLenRef.current = curLen;
593
+ for (const line of pendingLines) {
594
+ const text = (line.text || "").trim();
595
+ if (!text) continue;
596
+ const role = line.speaker === "user" ? "user" : "assistant";
597
+ const voiceId = `voice-${line.id}`;
598
+ setMessages((prev) => {
599
+ if (prev.some((m) => m.id === voiceId)) return prev;
600
+ if (prev.some((m) => !m.id.startsWith("voice-") && m.role === role && m.content.trim() === text)) return prev;
601
+ const last = prev[prev.length - 1];
602
+ if (last?.id.startsWith("voice-") && last.role === "assistant" && role === "assistant") {
603
+ const merged = text.startsWith(last.content) ? text : `${last.content} ${text}`.trim();
604
+ return [...prev.slice(0, -1), { ...last, content: merged, isStreaming: false }];
605
+ }
606
+ return [...prev, { id: voiceId, role, content: text, createdAt: /* @__PURE__ */ new Date() }];
607
+ });
608
+ }
609
+ } else {
610
+ voicePrevLenRef.current = voice.transcript.length;
611
+ }
612
+ if (voiceStreamingIdRef.current) {
613
+ const doneId = voiceStreamingIdRef.current;
614
+ voiceStreamingIdRef.current = null;
615
+ setMessages((prev) => prev.map((m) => m.id === doneId ? { ...m, isStreaming: false } : m));
616
+ }
617
+ if (voiceUserPartialIdRef.current) {
618
+ const doneId = voiceUserPartialIdRef.current;
619
+ voiceUserPartialIdRef.current = null;
620
+ setMessages((prev) => prev.map((m) => m.id === doneId ? { ...m, isStreaming: false } : m));
621
+ }
622
+ return;
623
+ }
624
+ if (curLen > voicePrevLenRef.current) {
625
+ const newLines = voice.transcript.slice(voicePrevLenRef.current);
626
+ voicePrevLenRef.current = curLen;
627
+ for (const line of newLines) {
628
+ const text = (line.text || "").trim();
629
+ if (!text) continue;
630
+ const role = line.speaker === "user" ? "user" : "assistant";
631
+ const voiceId = `voice-${line.id}`;
632
+ setMessages((prev) => {
633
+ if (prev.some((m) => m.id === voiceId)) return prev;
634
+ if (prev.some(
635
+ (m) => !m.id.startsWith("voice-") && m.role === role && m.content.trim() === text
636
+ ))
637
+ return prev;
638
+ const last = prev[prev.length - 1];
639
+ if (last?.id.startsWith("voice-") && last.role === "assistant" && role === "assistant") {
640
+ const merged = text.startsWith(last.content) ? text : `${last.content} ${text}`.trim();
641
+ return [...prev.slice(0, -1), { ...last, content: merged, isStreaming: false }];
642
+ }
643
+ return [...prev, { id: voiceId, role, content: text, createdAt: /* @__PURE__ */ new Date() }];
644
+ });
645
+ }
646
+ }
647
+ const agentPartialText = voice.partial?.speaker === "agent" ? voice.partial.text.trim() : "";
648
+ const userPartialText = voice.partial?.speaker === "user" ? voice.partial.text.trim() : "";
649
+ if (agentPartialText) {
650
+ if (voiceUserPartialIdRef.current) {
651
+ const doneId = voiceUserPartialIdRef.current;
652
+ voiceUserPartialIdRef.current = null;
653
+ setMessages((prev) => prev.map((m) => m.id === doneId ? { ...m, isStreaming: false } : m));
654
+ }
655
+ setMessages((prev) => {
656
+ const last = prev[prev.length - 1];
657
+ if (last?.id.startsWith("voice-") && last.role === "assistant") {
658
+ voiceStreamingIdRef.current = last.id;
659
+ return [...prev.slice(0, -1), { ...last, content: agentPartialText, isStreaming: true }];
660
+ }
661
+ const id = voiceStreamingIdRef.current || `voice-partial-${Date.now()}`;
662
+ voiceStreamingIdRef.current = id;
663
+ return [...prev, { id, role: "assistant", content: agentPartialText, isStreaming: true, createdAt: /* @__PURE__ */ new Date() }];
664
+ });
665
+ } else if (userPartialText) {
666
+ if (voiceStreamingIdRef.current) {
667
+ const doneId = voiceStreamingIdRef.current;
668
+ voiceStreamingIdRef.current = null;
669
+ setMessages((prev) => prev.map((m) => m.id === doneId ? { ...m, isStreaming: false } : m));
670
+ }
671
+ setMessages((prev) => {
672
+ const last = prev[prev.length - 1];
673
+ if (last?.id.startsWith("voice-") && last.role === "user" && last.isStreaming) {
674
+ voiceUserPartialIdRef.current = last.id;
675
+ return [...prev.slice(0, -1), { ...last, content: userPartialText, isStreaming: true }];
676
+ }
677
+ const id = voiceUserPartialIdRef.current || `voice-partial-user-${Date.now()}`;
678
+ voiceUserPartialIdRef.current = id;
679
+ return [...prev, { id, role: "user", content: userPartialText, isStreaming: true, createdAt: /* @__PURE__ */ new Date() }];
680
+ });
681
+ } else {
682
+ if (voiceStreamingIdRef.current && voice.state !== "speaking") {
683
+ const doneId = voiceStreamingIdRef.current;
684
+ voiceStreamingIdRef.current = null;
685
+ setMessages((prev) => prev.map((m) => m.id === doneId ? { ...m, isStreaming: false } : m));
686
+ }
687
+ if (voiceUserPartialIdRef.current) {
688
+ const doneId = voiceUserPartialIdRef.current;
689
+ voiceUserPartialIdRef.current = null;
690
+ setMessages((prev) => prev.map((m) => m.id === doneId ? { ...m, isStreaming: false } : m));
691
+ }
692
+ }
693
+ }, [voice?.transcript, voice?.partial, voice?.state, effectiveThreadId]);
694
+ const doSend = useCallback(
695
+ async (prompt, baseMessages, overrideOptions) => {
696
+ const targetAgentId = overrideOptions?.agentId || agentId;
697
+ if (!targetAgentId) {
698
+ const err = new Error("No Agent ID specified for useChat.");
699
+ chatLogger.warn("sendMessage no agentId", {});
700
+ chatLogger.error("sendMessage failed \u2014 no agent", { error: err.message });
701
+ setError(err);
702
+ options.onError?.(err);
703
+ return false;
704
+ }
705
+ chatLogger.debug("sendMessage start", {
706
+ promptPreview: prompt.slice(0, 100),
707
+ agentId: targetAgentId,
708
+ threadId: effectiveThreadId ?? overrideOptions?.threadId,
709
+ hasResume: !!overrideOptions?.resume,
710
+ hasContextOverride: !!overrideOptions?.contextOverride,
711
+ messageCount: baseMessages.length
712
+ });
713
+ chatLogger.trace("sendMessage details", {
714
+ agentId: targetAgentId,
715
+ promptPreview: prompt.slice(0, 200),
716
+ hasResume: !!overrideOptions?.resume,
717
+ hasContextOverride: !!overrideOptions?.contextOverride
718
+ });
719
+ const userMessage = {
720
+ id: `user-${Date.now()}-${Math.random().toString(36).slice(2, 7)}`,
721
+ role: "user",
722
+ content: prompt,
723
+ createdAt: /* @__PURE__ */ new Date()
724
+ };
725
+ const assistantMessageId = `assistant-${Date.now()}-${Math.random().toString(36).slice(2, 7)}`;
726
+ const placeholderAssistant = {
727
+ id: assistantMessageId,
728
+ role: "assistant",
729
+ content: "",
730
+ createdAt: /* @__PURE__ */ new Date(),
731
+ isStreaming: true,
732
+ toolCalls: []
733
+ };
734
+ const nextMessages = [...baseMessages, userMessage];
735
+ setMessages([...nextMessages, placeholderAssistant]);
736
+ setInput("");
737
+ setIsStreaming(true);
738
+ setError(null);
739
+ setInterrupt(null);
740
+ const controller = new AbortController();
741
+ abortControllerRef.current = controller;
742
+ const finalizeReasoning = () => {
743
+ setMessages(
744
+ (prev) => prev.map((m) => m.role === "reasoning" && m.isStreaming ? { ...m, isStreaming: false } : m)
745
+ );
746
+ };
747
+ try {
748
+ const payloadMessages = nextMessages.filter((m) => m.role !== "reasoning").map((m) => ({
749
+ role: m.role === "assistant" ? "assistant" : "user",
750
+ content: m.content
751
+ }));
752
+ let resolvedThreadId = await overrideOptions?.threadId ?? effectiveThreadId;
753
+ if (!resolvedThreadId) {
754
+ chatLogger.info("minting real thread for ephemeral chat", { agentId: targetAgentId });
755
+ const createRes = await fetchWithAuth("/threads", {
756
+ method: "POST",
757
+ headers: { "Content-Type": "application/json" },
758
+ body: JSON.stringify({ agentId: targetAgentId })
759
+ });
760
+ if (!createRes.ok) throw new Error(`Failed to create thread: ${createRes.statusText}`);
761
+ const createBody = await createRes.json();
762
+ const created = createBody?.data ?? createBody;
763
+ resolvedThreadId = created._id ?? created.id;
764
+ if (!resolvedThreadId) throw new Error("Thread creation returned no id");
765
+ setInternalThreadId(resolvedThreadId);
766
+ loadedThreadIdRef.current = resolvedThreadId;
767
+ options.onThreadCreated?.(resolvedThreadId);
768
+ chatLogger.info("ephemeral chat minted", { threadId: resolvedThreadId });
769
+ }
770
+ chatLogger.trace("resolved threadId", { threadId: resolvedThreadId });
771
+ const token = getAuthToken ? await getAuthToken() : null;
772
+ const resolvedHookContext = typeof options.context === "function" ? options.context() : options.context;
773
+ const mergedContext = { ...resolvedHookContext, ...overrideOptions?.context };
774
+ const hasContext = Object.keys(mergedContext).length > 0;
775
+ chatLogger.debug("opening SSE stream", {
776
+ agentId: targetAgentId,
777
+ hasToken: !!token,
778
+ hasThreadId: !!resolvedThreadId,
779
+ hasContext
780
+ });
781
+ const stream = await openSSEStream({
782
+ url: `${baseUrl}/chat`,
783
+ headers: {
784
+ "Content-Type": "application/json",
785
+ ...token ? { Authorization: `Bearer ${token}` } : {}
786
+ },
787
+ body: JSON.stringify({
788
+ agentId: targetAgentId,
789
+ messages: payloadMessages,
790
+ threadId: resolvedThreadId,
791
+ resume: overrideOptions?.resume,
792
+ contextOverride: overrideOptions?.contextOverride,
793
+ ...hasContext ? { context: mergedContext } : {}
794
+ }),
795
+ signal: controller.signal
796
+ });
797
+ if (!stream.ok) {
798
+ chatLogger.warn("SSE stream not ok", { status: stream.status, errorText: stream.errorText });
799
+ chatLogger.error("chat stream failed", { agentId: targetAgentId, status: stream.status, error: stream.errorText });
800
+ throw new Error(`Chat error (${stream.status}): ${stream.errorText ?? "Stream failed"}`);
801
+ }
802
+ chatLogger.debug("SSE stream opened", { agentId: targetAgentId, status: stream.status });
803
+ chatLogger.info("chat stream started", { agentId: targetAgentId, threadId: resolvedThreadId });
804
+ const reader = stream.reader;
805
+ let buffer = "";
806
+ let accumulatedText = "";
807
+ const toolCallsMap = /* @__PURE__ */ new Map();
808
+ let streamSeq = 0;
809
+ let activeReasoningId = null;
810
+ const reasoningById = /* @__PURE__ */ new Map();
811
+ const patchAssistant = (patch) => {
812
+ setMessages(
813
+ (prev) => prev.map(
814
+ (msg) => msg.id === assistantMessageId ? { ...msg, toolCalls: Array.from(toolCallsMap.values()), ...patch } : msg
815
+ )
816
+ );
817
+ };
818
+ const insertReasoningMessage = (id, seq) => {
819
+ const msg = { id, role: "reasoning", content: "", createdAt: /* @__PURE__ */ new Date(), isStreaming: true, seq };
820
+ setMessages((prev) => {
821
+ const idx = prev.findIndex((m) => m.id === assistantMessageId);
822
+ if (idx === -1) return [...prev, msg];
823
+ const next = [...prev];
824
+ next.splice(idx, 0, msg);
825
+ return next;
826
+ });
827
+ };
828
+ while (true) {
829
+ const { done, value } = await reader.read();
830
+ if (done) break;
831
+ buffer += value ?? "";
832
+ const lines = buffer.split("\n");
833
+ buffer = lines.pop() ?? "";
834
+ for (const line of lines) {
835
+ const trimmed = line.trim();
836
+ if (!trimmed || !trimmed.startsWith("data:")) continue;
837
+ const raw = trimmed.replace(/^data:\s*/, "");
838
+ if (raw === "[DONE]") break;
839
+ try {
840
+ const event = JSON.parse(raw);
841
+ chatLogger.trace("stream event", { type: event.type, event });
842
+ options.onEvent?.(event);
843
+ if (event.type === "TEXT_MESSAGE_CHUNK" && event.delta) {
844
+ chatLogger.debug("text chunk", { deltaLength: event.delta.length });
845
+ accumulatedText += event.delta;
846
+ patchAssistant({ content: accumulatedText, isStreaming: true });
847
+ } else if (event.type === "TOOL_CALL_CHUNK" && event.toolCallId) {
848
+ chatLogger.debug("tool call chunk", { toolCallId: event.toolCallId, toolCallName: event.toolCallName });
849
+ const existing = toolCallsMap.get(event.toolCallId);
850
+ if (existing) {
851
+ existing.args = (existing.args || "") + (event.delta || "");
852
+ } else {
853
+ toolCallsMap.set(event.toolCallId, {
854
+ toolCallId: event.toolCallId,
855
+ toolName: event.toolCallName || "",
856
+ args: event.delta || "",
857
+ seq: streamSeq++
858
+ });
859
+ }
860
+ patchAssistant({});
861
+ } else if (event.type === "TOOL_CALL_RESULT") {
862
+ chatLogger.debug("tool call result", { toolCallId: event.toolCallId });
863
+ const existing = toolCallsMap.get(event.toolCallId);
864
+ if (existing) {
865
+ existing.result = event.content;
866
+ existing.isError = isErrorToolContent(event.content);
867
+ if (existing.isError) chatLogger.warn("tool call error", { toolCallId: event.toolCallId });
868
+ if (existing.toolName === "present_file" && !existing.isError) {
869
+ const presented = parsePresentedFile(event.content);
870
+ if (presented) {
871
+ chatLogger.info("present_file", { path: presented.path });
872
+ setPresentedFile(presented);
873
+ }
874
+ }
875
+ patchAssistant({});
876
+ }
877
+ } else if (event.type === "STATE_SNAPSHOT") {
878
+ chatLogger.debug("state snapshot", {
879
+ fileCount: Object.keys(event.snapshot.files ?? {}).length,
880
+ todoCount: event.snapshot.todos?.length ?? 0
881
+ });
882
+ setFiles(normalizeWorkspaceFiles(event.snapshot.files ?? {}));
883
+ setTodos(event.snapshot.todos ?? []);
884
+ } else if (event.type === "REASONING_MESSAGE_START" && event.messageId) {
885
+ chatLogger.debug("reasoning start", { messageId: event.messageId });
886
+ activeReasoningId = event.messageId;
887
+ reasoningById.set(event.messageId, { content: "" });
888
+ insertReasoningMessage(event.messageId, streamSeq++);
889
+ } else if (event.type === "REASONING_MESSAGE_CONTENT") {
890
+ let rid = event.messageId || activeReasoningId || "";
891
+ if (!rid || !reasoningById.has(rid)) {
892
+ rid = rid || `reasoning-${Date.now()}-${Math.random().toString(36).slice(2, 7)}`;
893
+ activeReasoningId = rid;
894
+ reasoningById.set(rid, { content: "" });
895
+ insertReasoningMessage(rid, streamSeq++);
896
+ chatLogger.debug("reasoning lazy start", { messageId: rid });
897
+ }
898
+ const entry = reasoningById.get(rid);
899
+ entry.content += event.delta;
900
+ chatLogger.trace("reasoning content", { messageId: rid, deltaLength: event.delta?.length ?? 0 });
901
+ setMessages((prev) => prev.map((m) => m.id === rid ? { ...m, content: entry.content, isStreaming: true } : m));
902
+ } else if (event.type === "REASONING_END") {
903
+ chatLogger.debug("reasoning end", { messageId: activeReasoningId });
904
+ const rid = activeReasoningId;
905
+ activeReasoningId = null;
906
+ if (rid) {
907
+ setMessages((prev) => prev.map((m) => m.id === rid ? { ...m, isStreaming: false } : m));
908
+ }
909
+ } else if (event.type === "CUSTOM") {
910
+ chatLogger.debug("custom event", { name: event.name });
911
+ if (event.name === "hitl_request") {
912
+ const value2 = event.value;
913
+ chatLogger.info("hitl interrupt", { actionCount: value2.actionRequests?.length ?? 0 });
914
+ setInterrupt({ kind: "hitl", actionRequests: value2.actionRequests, reviewConfigs: value2.reviewConfigs });
915
+ } else if (event.name === "clarification_request") {
916
+ const value2 = event.value;
917
+ chatLogger.info("clarification interrupt", { questionCount: value2.questions?.length ?? 0 });
918
+ setInterrupt({ kind: "clarification", questions: value2.questions });
919
+ } else if (event.name === "subagent_activity") {
920
+ const { toolCallId, ...entry } = event.value;
921
+ chatLogger.trace("subagent activity", { toolCallId, kind: entry.kind });
922
+ const existing = toolCallsMap.get(toolCallId);
923
+ if (existing) {
924
+ existing.subagentActivity = [...existing.subagentActivity || [], entry];
925
+ patchAssistant({});
926
+ }
927
+ } else if (event.name === "mcp_app") {
928
+ const val = event.value;
929
+ if (val?.toolCallId && val?.resourceUri && val?.mcpId) {
930
+ const existing = toolCallsMap.get(val.toolCallId);
931
+ if (existing) {
932
+ existing.mcpApp = { resourceUri: val.resourceUri, mcpId: val.mcpId };
933
+ patchAssistant({});
934
+ }
935
+ }
936
+ }
937
+ } else if (event.type === "title") {
938
+ const title = event.title;
939
+ if (typeof title === "string" && title.trim()) {
940
+ chatLogger.info("auto title", { title });
941
+ options.onTitle?.(title);
942
+ }
943
+ } else if (event.type === "RUN_ERROR") {
944
+ chatLogger.warn("run error", { message: event.message, code: event.code });
945
+ chatLogger.error("stream run error", { code: event.code, message: event.message });
946
+ throw new Error(event.message || "Stream error from agent");
947
+ } else {
948
+ chatLogger.trace("unhandled event", { type: event.type });
949
+ }
950
+ } catch (e) {
951
+ if (e instanceof Error && e.message.startsWith("Stream error")) throw e;
952
+ chatLogger.warn("event parse error", { raw: raw.slice(0, 200), error: e instanceof Error ? e.message : String(e) });
953
+ }
954
+ }
955
+ }
956
+ const finalMessage = {
957
+ id: assistantMessageId,
958
+ role: "assistant",
959
+ content: accumulatedText,
960
+ createdAt: /* @__PURE__ */ new Date(),
961
+ isStreaming: false,
962
+ toolCalls: Array.from(toolCallsMap.values())
963
+ };
964
+ setMessages((prev) => prev.map((msg) => msg.id === assistantMessageId ? finalMessage : msg));
965
+ chatLogger.info("sendMessage succeeded", { agentId: targetAgentId, textLength: accumulatedText.length, toolCallCount: toolCallsMap.size });
966
+ chatLogger.debug("sendMessage completed", { agentId: targetAgentId, textLength: accumulatedText.length, eventCount: toolCallsMap.size + 1 });
967
+ options.onFinish?.(finalMessage);
968
+ return true;
969
+ } catch (err) {
970
+ if (controller.signal.aborted) {
971
+ chatLogger.info("sendMessage aborted", { agentId: targetAgentId });
972
+ chatLogger.debug("stream aborted", { agentId: targetAgentId });
973
+ setMessages((prev) => prev.map((msg) => msg.id === assistantMessageId ? { ...msg, isStreaming: false } : msg));
974
+ return false;
975
+ }
976
+ const errorObj = err instanceof Error ? err : new Error(String(err));
977
+ chatLogger.warn("sendMessage failed", { agentId: targetAgentId, error: errorObj.message });
978
+ chatLogger.error("sendMessage error", { agentId: targetAgentId, error: errorObj.message });
979
+ setError(errorObj);
980
+ options.onError?.(errorObj);
981
+ setMessages(
982
+ (prev) => prev.map(
983
+ (msg) => msg.id === assistantMessageId ? { ...msg, content: msg.content || `\u26A0\uFE0F Error: ${errorObj.message || "Failed to get response."}`, isStreaming: false } : msg
984
+ )
985
+ );
986
+ return false;
987
+ } finally {
988
+ setIsStreaming(false);
989
+ abortControllerRef.current = null;
990
+ finalizeReasoning();
991
+ chatLogger.debug("sendMessage finally", { agentId: targetAgentId, isStreaming: false });
992
+ chatLogger.trace("sendMessage end", { agentId: targetAgentId });
993
+ }
994
+ },
995
+ [agentId, baseUrl, getAuthToken, fetchWithAuth, options, chatLogger, effectiveThreadId]
996
+ );
997
+ const sendMessage = useCallback(
998
+ async (contentToSend, overrideOptions) => {
999
+ const prompt = (contentToSend ?? input).trim();
1000
+ if (!prompt || isStreaming) {
1001
+ chatLogger.trace("sendMessage skipped", {
1002
+ hasPrompt: !!prompt,
1003
+ isStreaming
1004
+ });
1005
+ if (isStreaming) {
1006
+ chatLogger.warn("sendMessage dropped while streaming \u2014 caller should queue or disable send", {});
1007
+ }
1008
+ return false;
1009
+ }
1010
+ return doSend(prompt, messages, overrideOptions);
1011
+ },
1012
+ [input, isStreaming, messages, doSend, chatLogger]
1013
+ );
1014
+ const handleInputChange = useCallback(
1015
+ (e) => {
1016
+ chatLogger.trace("handleInputChange", { length: e.target.value.length });
1017
+ setInput(e.target.value);
1018
+ },
1019
+ [chatLogger]
1020
+ );
1021
+ const handleSubmit = useCallback(
1022
+ (e) => {
1023
+ if (e) e.preventDefault();
1024
+ chatLogger.debug("handleSubmit", {});
1025
+ void sendMessage();
1026
+ },
1027
+ [sendMessage, chatLogger]
1028
+ );
1029
+ const reload = useCallback(async () => {
1030
+ if (messages.length === 0 || isStreaming) {
1031
+ chatLogger.trace("reload skipped", {
1032
+ messageCount: messages.length,
1033
+ isStreaming
1034
+ });
1035
+ return false;
1036
+ }
1037
+ let lastUserIndex = -1;
1038
+ for (let i = messages.length - 1; i >= 0; i--) {
1039
+ if (messages[i].role === "user") {
1040
+ lastUserIndex = i;
1041
+ break;
1042
+ }
1043
+ }
1044
+ if (lastUserIndex === -1) {
1045
+ chatLogger.warn("reload no user message", {});
1046
+ return false;
1047
+ }
1048
+ const lastUserMessage = messages[lastUserIndex];
1049
+ const truncated = messages.slice(0, lastUserIndex);
1050
+ chatLogger.info("reload", { messageId: lastUserMessage.id });
1051
+ chatLogger.debug("reload last user", {
1052
+ preview: lastUserMessage.content.slice(0, 100)
1053
+ });
1054
+ return doSend(lastUserMessage.content, truncated);
1055
+ }, [isStreaming, messages, doSend, chatLogger]);
1056
+ const resumeInterrupt = useCallback(
1057
+ (resume, displayContent) => {
1058
+ chatLogger.info("resumeInterrupt", {
1059
+ kind: resume.decisions ? "hitl" : "clarification",
1060
+ preview: displayContent.slice(0, 50)
1061
+ });
1062
+ return sendMessage(displayContent, { resume });
1063
+ },
1064
+ [sendMessage, chatLogger]
1065
+ );
1066
+ const dismissPresentedFile = useCallback(() => {
1067
+ chatLogger.debug("dismissPresentedFile", {});
1068
+ setPresentedFile(null);
1069
+ }, [chatLogger]);
1070
+ const openWorkspaceFile = useCallback(
1071
+ (path) => {
1072
+ chatLogger.debug("openWorkspaceFile", { path });
1073
+ setPresentedFile({
1074
+ path,
1075
+ title: path.split("/").pop() || path,
1076
+ description: ""
1077
+ });
1078
+ },
1079
+ [chatLogger]
1080
+ );
1081
+ return {
1082
+ messages,
1083
+ input,
1084
+ setInput,
1085
+ handleInputChange,
1086
+ handleSubmit,
1087
+ sendMessage,
1088
+ isStreaming,
1089
+ isLoading: isStreaming,
1090
+ isLoadingHistory,
1091
+ error,
1092
+ interrupt,
1093
+ resumeInterrupt,
1094
+ files,
1095
+ todos,
1096
+ presentedFile,
1097
+ dismissPresentedFile,
1098
+ openWorkspaceFile,
1099
+ sandboxCommands,
1100
+ stop,
1101
+ reload,
1102
+ clear,
1103
+ startNewChat,
1104
+ currentThreadId: effectiveThreadId,
1105
+ isEphemeral: !effectiveThreadId,
1106
+ setMessages,
1107
+ loadThreadMessages
1108
+ };
1109
+ }
1110
+
1111
+ // src/hooks/useArchitectChat.ts
1112
+ import { useCallback as useCallback2, useEffect as useEffect2, useMemo as useMemo3, useRef as useRef2, useState as useState2 } from "react";
1113
+ var ARCHITECT_AGENT_ID = "000000000000000000000002";
1114
+ function useArchitectChat(options = {}) {
1115
+ const { fetchWithAuth, baseUrl, getAuthToken, logger } = usePersonaContext();
1116
+ const chatLogger = useMemo3(() => logger.child("architect"), [logger]);
1117
+ const threadId = options.threadId;
1118
+ const [internalThreadId, setInternalThreadId] = useState2(void 0);
1119
+ const effectiveThreadId = threadId ?? internalThreadId;
1120
+ useEffect2(() => {
1121
+ if (threadId !== void 0) setInternalThreadId(threadId);
1122
+ }, [threadId]);
1123
+ const didLogInitRef = useRef2(false);
1124
+ if (!didLogInitRef.current) {
1125
+ didLogInitRef.current = true;
1126
+ chatLogger.debug("useArchitectChat init", {
1127
+ threadId,
1128
+ hasInitialMessages: !!options.initialMessages?.length
1129
+ });
1130
+ chatLogger.trace("useArchitectChat options", {
1131
+ threadId,
1132
+ initialMessageCount: options.initialMessages?.length ?? 0
1133
+ });
1134
+ }
1135
+ const [messages, setMessages] = useState2(
1136
+ options.initialMessages || []
1137
+ );
1138
+ const [input, setInput] = useState2("");
1139
+ const [isStreaming, setIsStreaming] = useState2(false);
1140
+ const [isLoadingHistory, setIsLoadingHistory] = useState2(false);
1141
+ const [error, setError] = useState2(null);
1142
+ const [interrupt, setInterrupt] = useState2(null);
1143
+ const [files, setFiles] = useState2({});
1144
+ const [todos, setTodos] = useState2([]);
1145
+ const [presentedFile, setPresentedFile] = useState2(null);
1146
+ const abortControllerRef = useRef2(null);
1147
+ const loadedThreadIdRef = useRef2(void 0);
1148
+ const stop = useCallback2(() => {
1149
+ if (abortControllerRef.current) {
1150
+ chatLogger.info("stop streaming", {});
1151
+ chatLogger.debug("abort controller", {
1152
+ hasController: !!abortControllerRef.current
1153
+ });
1154
+ abortControllerRef.current.abort();
1155
+ abortControllerRef.current = null;
1156
+ setIsStreaming(false);
1157
+ chatLogger.debug("streaming stopped");
1158
+ } else {
1159
+ chatLogger.trace("stop called \u2014 no active stream");
1160
+ }
1161
+ }, [chatLogger]);
1162
+ const clear = useCallback2(() => {
461
1163
  chatLogger.info("clear chat", { messageCount: messages.length });
462
1164
  chatLogger.debug("clear", { messageCount: messages.length });
463
1165
  stop();
@@ -469,7 +1171,7 @@ function useChat(options = {}) {
469
1171
  setPresentedFile(null);
470
1172
  loadedThreadIdRef.current = void 0;
471
1173
  }, [stop, chatLogger, messages.length]);
472
- const startNewChat = useCallback(() => {
1174
+ const startNewChat = useCallback2(() => {
473
1175
  chatLogger.info("startNewChat \u2014 entering ephemeral mode");
474
1176
  stop();
475
1177
  setMessages([]);
@@ -480,13 +1182,9 @@ function useChat(options = {}) {
480
1182
  setPresentedFile(null);
481
1183
  setInput("");
482
1184
  loadedThreadIdRef.current = void 0;
483
- voiceThreadRef.current = void 0;
484
- voicePrevLenRef.current = 0;
485
- voiceStreamingIdRef.current = null;
486
- voiceUserPartialIdRef.current = null;
487
1185
  setInternalThreadId(void 0);
488
1186
  }, [stop, chatLogger]);
489
- const loadThreadMessages = useCallback(
1187
+ const loadThreadMessages = useCallback2(
490
1188
  async (id) => {
491
1189
  chatLogger.debug("loadThreadMessages start", { threadId: id });
492
1190
  chatLogger.trace("loadThreadMessages", { threadId: id });
@@ -547,7 +1245,7 @@ function useChat(options = {}) {
547
1245
  },
548
1246
  [fetchWithAuth, chatLogger]
549
1247
  );
550
- useEffect(() => {
1248
+ useEffect2(() => {
551
1249
  if (!effectiveThreadId || isStreaming) {
552
1250
  chatLogger.trace("auto-load skipped", { threadId: effectiveThreadId, isStreaming });
553
1251
  return;
@@ -567,152 +1265,17 @@ function useChat(options = {}) {
567
1265
  chatLogger.debug("loadThreadMessages trigger", { threadId: effectiveThreadId });
568
1266
  void loadThreadMessages(effectiveThreadId);
569
1267
  }, [effectiveThreadId, isStreaming, messages.length, loadThreadMessages, chatLogger]);
570
- const voice = options.voice;
571
- useEffect(() => {
572
- if (!voice) return;
573
- if (voiceThreadRef.current !== effectiveThreadId) {
574
- voiceThreadRef.current = effectiveThreadId;
575
- voicePrevLenRef.current = voice.transcript.length;
576
- voiceStreamingIdRef.current = null;
577
- voiceUserPartialIdRef.current = null;
578
- return;
579
- }
580
- const isVoiceActive = voice.state !== "idle" && voice.state !== "ended" && voice.state !== "error";
581
- const curLen = voice.transcript.length;
582
- if (curLen < voicePrevLenRef.current) {
583
- voicePrevLenRef.current = 0;
584
- voiceStreamingIdRef.current = null;
585
- voiceUserPartialIdRef.current = null;
586
- }
587
- if (!isVoiceActive) {
588
- if (curLen > voicePrevLenRef.current) {
589
- const pendingLines = voice.transcript.slice(voicePrevLenRef.current);
590
- voicePrevLenRef.current = curLen;
591
- for (const line of pendingLines) {
592
- const text = (line.text || "").trim();
593
- if (!text) continue;
594
- const role = line.speaker === "user" ? "user" : "assistant";
595
- const voiceId = `voice-${line.id}`;
596
- setMessages((prev) => {
597
- if (prev.some((m) => m.id === voiceId)) return prev;
598
- if (prev.some((m) => !m.id.startsWith("voice-") && m.role === role && m.content.trim() === text)) return prev;
599
- const last = prev[prev.length - 1];
600
- if (last?.id.startsWith("voice-") && last.role === "assistant" && role === "assistant") {
601
- const merged = text.startsWith(last.content) ? text : `${last.content} ${text}`.trim();
602
- return [...prev.slice(0, -1), { ...last, content: merged, isStreaming: false }];
603
- }
604
- return [...prev, { id: voiceId, role, content: text, createdAt: /* @__PURE__ */ new Date() }];
605
- });
606
- }
607
- } else {
608
- voicePrevLenRef.current = voice.transcript.length;
609
- }
610
- if (voiceStreamingIdRef.current) {
611
- const doneId = voiceStreamingIdRef.current;
612
- voiceStreamingIdRef.current = null;
613
- setMessages((prev) => prev.map((m) => m.id === doneId ? { ...m, isStreaming: false } : m));
614
- }
615
- if (voiceUserPartialIdRef.current) {
616
- const doneId = voiceUserPartialIdRef.current;
617
- voiceUserPartialIdRef.current = null;
618
- setMessages((prev) => prev.map((m) => m.id === doneId ? { ...m, isStreaming: false } : m));
619
- }
620
- return;
621
- }
622
- if (curLen > voicePrevLenRef.current) {
623
- const newLines = voice.transcript.slice(voicePrevLenRef.current);
624
- voicePrevLenRef.current = curLen;
625
- for (const line of newLines) {
626
- const text = (line.text || "").trim();
627
- if (!text) continue;
628
- const role = line.speaker === "user" ? "user" : "assistant";
629
- const voiceId = `voice-${line.id}`;
630
- setMessages((prev) => {
631
- if (prev.some((m) => m.id === voiceId)) return prev;
632
- if (prev.some(
633
- (m) => !m.id.startsWith("voice-") && m.role === role && m.content.trim() === text
634
- ))
635
- return prev;
636
- const last = prev[prev.length - 1];
637
- if (last?.id.startsWith("voice-") && last.role === "assistant" && role === "assistant") {
638
- const merged = text.startsWith(last.content) ? text : `${last.content} ${text}`.trim();
639
- return [...prev.slice(0, -1), { ...last, content: merged, isStreaming: false }];
640
- }
641
- return [...prev, { id: voiceId, role, content: text, createdAt: /* @__PURE__ */ new Date() }];
642
- });
643
- }
644
- }
645
- const agentPartialText = voice.partial?.speaker === "agent" ? voice.partial.text.trim() : "";
646
- const userPartialText = voice.partial?.speaker === "user" ? voice.partial.text.trim() : "";
647
- if (agentPartialText) {
648
- if (voiceUserPartialIdRef.current) {
649
- const doneId = voiceUserPartialIdRef.current;
650
- voiceUserPartialIdRef.current = null;
651
- setMessages((prev) => prev.map((m) => m.id === doneId ? { ...m, isStreaming: false } : m));
652
- }
653
- setMessages((prev) => {
654
- const last = prev[prev.length - 1];
655
- if (last?.id.startsWith("voice-") && last.role === "assistant") {
656
- voiceStreamingIdRef.current = last.id;
657
- return [...prev.slice(0, -1), { ...last, content: agentPartialText, isStreaming: true }];
658
- }
659
- const id = voiceStreamingIdRef.current || `voice-partial-${Date.now()}`;
660
- voiceStreamingIdRef.current = id;
661
- return [...prev, { id, role: "assistant", content: agentPartialText, isStreaming: true, createdAt: /* @__PURE__ */ new Date() }];
662
- });
663
- } else if (userPartialText) {
664
- if (voiceStreamingIdRef.current) {
665
- const doneId = voiceStreamingIdRef.current;
666
- voiceStreamingIdRef.current = null;
667
- setMessages((prev) => prev.map((m) => m.id === doneId ? { ...m, isStreaming: false } : m));
668
- }
669
- setMessages((prev) => {
670
- const last = prev[prev.length - 1];
671
- if (last?.id.startsWith("voice-") && last.role === "user" && last.isStreaming) {
672
- voiceUserPartialIdRef.current = last.id;
673
- return [...prev.slice(0, -1), { ...last, content: userPartialText, isStreaming: true }];
674
- }
675
- const id = voiceUserPartialIdRef.current || `voice-partial-user-${Date.now()}`;
676
- voiceUserPartialIdRef.current = id;
677
- return [...prev, { id, role: "user", content: userPartialText, isStreaming: true, createdAt: /* @__PURE__ */ new Date() }];
678
- });
679
- } else {
680
- if (voiceStreamingIdRef.current && voice.state !== "speaking") {
681
- const doneId = voiceStreamingIdRef.current;
682
- voiceStreamingIdRef.current = null;
683
- setMessages((prev) => prev.map((m) => m.id === doneId ? { ...m, isStreaming: false } : m));
684
- }
685
- if (voiceUserPartialIdRef.current) {
686
- const doneId = voiceUserPartialIdRef.current;
687
- voiceUserPartialIdRef.current = null;
688
- setMessages((prev) => prev.map((m) => m.id === doneId ? { ...m, isStreaming: false } : m));
689
- }
690
- }
691
- }, [voice?.transcript, voice?.partial, voice?.state, effectiveThreadId]);
692
- const doSend = useCallback(
1268
+ const doSend = useCallback2(
693
1269
  async (prompt, baseMessages, overrideOptions) => {
694
- const targetAgentId = overrideOptions?.agentId || agentId;
695
- if (!targetAgentId) {
696
- const err = new Error("No Agent ID specified for useChat.");
697
- chatLogger.warn("sendMessage no agentId", {});
698
- chatLogger.error("sendMessage failed \u2014 no agent", { error: err.message });
699
- setError(err);
700
- options.onError?.(err);
701
- return false;
702
- }
703
1270
  chatLogger.debug("sendMessage start", {
704
1271
  promptPreview: prompt.slice(0, 100),
705
- agentId: targetAgentId,
706
1272
  threadId: effectiveThreadId ?? overrideOptions?.threadId,
707
1273
  hasResume: !!overrideOptions?.resume,
708
- hasContextOverride: !!overrideOptions?.contextOverride,
709
1274
  messageCount: baseMessages.length
710
1275
  });
711
1276
  chatLogger.trace("sendMessage details", {
712
- agentId: targetAgentId,
713
1277
  promptPreview: prompt.slice(0, 200),
714
- hasResume: !!overrideOptions?.resume,
715
- hasContextOverride: !!overrideOptions?.contextOverride
1278
+ hasResume: !!overrideOptions?.resume
716
1279
  });
717
1280
  const userMessage = {
718
1281
  id: `user-${Date.now()}-${Math.random().toString(36).slice(2, 7)}`,
@@ -749,11 +1312,11 @@ function useChat(options = {}) {
749
1312
  }));
750
1313
  let resolvedThreadId = await overrideOptions?.threadId ?? effectiveThreadId;
751
1314
  if (!resolvedThreadId) {
752
- chatLogger.info("minting real thread for ephemeral chat", { agentId: targetAgentId });
1315
+ chatLogger.info("minting real thread for ephemeral architect chat", {});
753
1316
  const createRes = await fetchWithAuth("/threads", {
754
1317
  method: "POST",
755
1318
  headers: { "Content-Type": "application/json" },
756
- body: JSON.stringify({ agentId: targetAgentId })
1319
+ body: JSON.stringify({ agentId: ARCHITECT_AGENT_ID })
757
1320
  });
758
1321
  if (!createRes.ok) throw new Error(`Failed to create thread: ${createRes.statusText}`);
759
1322
  const createBody = await createRes.json();
@@ -763,42 +1326,34 @@ function useChat(options = {}) {
763
1326
  setInternalThreadId(resolvedThreadId);
764
1327
  loadedThreadIdRef.current = resolvedThreadId;
765
1328
  options.onThreadCreated?.(resolvedThreadId);
766
- chatLogger.info("ephemeral chat minted", { threadId: resolvedThreadId });
1329
+ chatLogger.info("ephemeral architect chat minted", { threadId: resolvedThreadId });
767
1330
  }
768
1331
  chatLogger.trace("resolved threadId", { threadId: resolvedThreadId });
769
1332
  const token = getAuthToken ? await getAuthToken() : null;
770
- const resolvedHookContext = typeof options.context === "function" ? options.context() : options.context;
771
- const mergedContext = { ...resolvedHookContext, ...overrideOptions?.context };
772
- const hasContext = Object.keys(mergedContext).length > 0;
773
1333
  chatLogger.debug("opening SSE stream", {
774
- agentId: targetAgentId,
775
1334
  hasToken: !!token,
776
- hasThreadId: !!resolvedThreadId,
777
- hasContext
1335
+ hasThreadId: !!resolvedThreadId
778
1336
  });
779
1337
  const stream = await openSSEStream({
780
- url: `${baseUrl}/chat`,
1338
+ url: `${baseUrl}/architect`,
781
1339
  headers: {
782
1340
  "Content-Type": "application/json",
783
1341
  ...token ? { Authorization: `Bearer ${token}` } : {}
784
1342
  },
785
1343
  body: JSON.stringify({
786
- agentId: targetAgentId,
787
1344
  messages: payloadMessages,
788
1345
  threadId: resolvedThreadId,
789
- resume: overrideOptions?.resume,
790
- contextOverride: overrideOptions?.contextOverride,
791
- ...hasContext ? { context: mergedContext } : {}
1346
+ resume: overrideOptions?.resume
792
1347
  }),
793
1348
  signal: controller.signal
794
1349
  });
795
1350
  if (!stream.ok) {
796
1351
  chatLogger.warn("SSE stream not ok", { status: stream.status, errorText: stream.errorText });
797
- chatLogger.error("chat stream failed", { agentId: targetAgentId, status: stream.status, error: stream.errorText });
798
- throw new Error(`Chat error (${stream.status}): ${stream.errorText ?? "Stream failed"}`);
1352
+ chatLogger.error("architect stream failed", { status: stream.status, error: stream.errorText });
1353
+ throw new Error(`Architect error (${stream.status}): ${stream.errorText ?? "Stream failed"}`);
799
1354
  }
800
- chatLogger.debug("SSE stream opened", { agentId: targetAgentId, status: stream.status });
801
- chatLogger.info("chat stream started", { agentId: targetAgentId, threadId: resolvedThreadId });
1355
+ chatLogger.debug("SSE stream opened", { status: stream.status });
1356
+ chatLogger.info("architect stream started", { threadId: resolvedThreadId });
802
1357
  const reader = stream.reader;
803
1358
  let buffer = "";
804
1359
  let accumulatedText = "";
@@ -960,20 +1515,20 @@ function useChat(options = {}) {
960
1515
  toolCalls: Array.from(toolCallsMap.values())
961
1516
  };
962
1517
  setMessages((prev) => prev.map((msg) => msg.id === assistantMessageId ? finalMessage : msg));
963
- chatLogger.info("sendMessage succeeded", { agentId: targetAgentId, textLength: accumulatedText.length, toolCallCount: toolCallsMap.size });
964
- chatLogger.debug("sendMessage completed", { agentId: targetAgentId, textLength: accumulatedText.length, eventCount: toolCallsMap.size + 1 });
1518
+ chatLogger.info("sendMessage succeeded", { textLength: accumulatedText.length, toolCallCount: toolCallsMap.size });
1519
+ chatLogger.debug("sendMessage completed", { textLength: accumulatedText.length, eventCount: toolCallsMap.size + 1 });
965
1520
  options.onFinish?.(finalMessage);
966
1521
  return true;
967
1522
  } catch (err) {
968
1523
  if (controller.signal.aborted) {
969
- chatLogger.info("sendMessage aborted", { agentId: targetAgentId });
970
- chatLogger.debug("stream aborted", { agentId: targetAgentId });
1524
+ chatLogger.info("sendMessage aborted", {});
1525
+ chatLogger.debug("stream aborted", {});
971
1526
  setMessages((prev) => prev.map((msg) => msg.id === assistantMessageId ? { ...msg, isStreaming: false } : msg));
972
1527
  return false;
973
1528
  }
974
1529
  const errorObj = err instanceof Error ? err : new Error(String(err));
975
- chatLogger.warn("sendMessage failed", { agentId: targetAgentId, error: errorObj.message });
976
- chatLogger.error("sendMessage error", { agentId: targetAgentId, error: errorObj.message });
1530
+ chatLogger.warn("sendMessage failed", { error: errorObj.message });
1531
+ chatLogger.error("sendMessage error", { error: errorObj.message });
977
1532
  setError(errorObj);
978
1533
  options.onError?.(errorObj);
979
1534
  setMessages(
@@ -986,13 +1541,13 @@ function useChat(options = {}) {
986
1541
  setIsStreaming(false);
987
1542
  abortControllerRef.current = null;
988
1543
  finalizeReasoning();
989
- chatLogger.debug("sendMessage finally", { agentId: targetAgentId, isStreaming: false });
990
- chatLogger.trace("sendMessage end", { agentId: targetAgentId });
1544
+ chatLogger.debug("sendMessage finally", { isStreaming: false });
1545
+ chatLogger.trace("sendMessage end", {});
991
1546
  }
992
1547
  },
993
- [agentId, baseUrl, getAuthToken, fetchWithAuth, options, chatLogger, effectiveThreadId]
1548
+ [baseUrl, getAuthToken, fetchWithAuth, options, chatLogger, effectiveThreadId]
994
1549
  );
995
- const sendMessage = useCallback(
1550
+ const sendMessage = useCallback2(
996
1551
  async (contentToSend, overrideOptions) => {
997
1552
  const prompt = (contentToSend ?? input).trim();
998
1553
  if (!prompt || isStreaming) {
@@ -1009,14 +1564,14 @@ function useChat(options = {}) {
1009
1564
  },
1010
1565
  [input, isStreaming, messages, doSend, chatLogger]
1011
1566
  );
1012
- const handleInputChange = useCallback(
1567
+ const handleInputChange = useCallback2(
1013
1568
  (e) => {
1014
1569
  chatLogger.trace("handleInputChange", { length: e.target.value.length });
1015
1570
  setInput(e.target.value);
1016
1571
  },
1017
1572
  [chatLogger]
1018
1573
  );
1019
- const handleSubmit = useCallback(
1574
+ const handleSubmit = useCallback2(
1020
1575
  (e) => {
1021
1576
  if (e) e.preventDefault();
1022
1577
  chatLogger.debug("handleSubmit", {});
@@ -1024,7 +1579,7 @@ function useChat(options = {}) {
1024
1579
  },
1025
1580
  [sendMessage, chatLogger]
1026
1581
  );
1027
- const reload = useCallback(async () => {
1582
+ const reload = useCallback2(async () => {
1028
1583
  if (messages.length === 0 || isStreaming) {
1029
1584
  chatLogger.trace("reload skipped", {
1030
1585
  messageCount: messages.length,
@@ -1051,7 +1606,7 @@ function useChat(options = {}) {
1051
1606
  });
1052
1607
  return doSend(lastUserMessage.content, truncated);
1053
1608
  }, [isStreaming, messages, doSend, chatLogger]);
1054
- const resumeInterrupt = useCallback(
1609
+ const resumeInterrupt = useCallback2(
1055
1610
  (resume, displayContent) => {
1056
1611
  chatLogger.info("resumeInterrupt", {
1057
1612
  kind: resume.decisions ? "hitl" : "clarification",
@@ -1061,11 +1616,11 @@ function useChat(options = {}) {
1061
1616
  },
1062
1617
  [sendMessage, chatLogger]
1063
1618
  );
1064
- const dismissPresentedFile = useCallback(() => {
1619
+ const dismissPresentedFile = useCallback2(() => {
1065
1620
  chatLogger.debug("dismissPresentedFile", {});
1066
1621
  setPresentedFile(null);
1067
1622
  }, [chatLogger]);
1068
- const openWorkspaceFile = useCallback(
1623
+ const openWorkspaceFile = useCallback2(
1069
1624
  (path) => {
1070
1625
  chatLogger.debug("openWorkspaceFile", { path });
1071
1626
  setPresentedFile({
@@ -1094,7 +1649,6 @@ function useChat(options = {}) {
1094
1649
  presentedFile,
1095
1650
  dismissPresentedFile,
1096
1651
  openWorkspaceFile,
1097
- sandboxCommands,
1098
1652
  stop,
1099
1653
  reload,
1100
1654
  clear,
@@ -1107,16 +1661,16 @@ function useChat(options = {}) {
1107
1661
  }
1108
1662
 
1109
1663
  // src/hooks/useMemory.ts
1110
- import { useCallback as useCallback2, useEffect as useEffect2, useState as useState2 } from "react";
1664
+ import { useCallback as useCallback3, useEffect as useEffect3, useState as useState3 } from "react";
1111
1665
  function useMemory(autoFetch = true) {
1112
1666
  const { fetchWithAuth } = usePersonaContext();
1113
- const [memory, setMemory] = useState2({
1667
+ const [memory, setMemory] = useState3({
1114
1668
  userFiles: [],
1115
1669
  agentMemories: []
1116
1670
  });
1117
- const [isLoading, setIsLoading] = useState2(false);
1118
- const [error, setError] = useState2(null);
1119
- const fetchMemory = useCallback2(async () => {
1671
+ const [isLoading, setIsLoading] = useState3(false);
1672
+ const [error, setError] = useState3(null);
1673
+ const fetchMemory = useCallback3(async () => {
1120
1674
  setIsLoading(true);
1121
1675
  setError(null);
1122
1676
  try {
@@ -1135,7 +1689,7 @@ function useMemory(autoFetch = true) {
1135
1689
  setIsLoading(false);
1136
1690
  }
1137
1691
  }, [fetchWithAuth]);
1138
- const getFile = useCallback2(
1692
+ const getFile = useCallback3(
1139
1693
  async (params) => {
1140
1694
  const query = new URLSearchParams({ path: params.path });
1141
1695
  if (params.scope) query.set("scope", params.scope);
@@ -1147,7 +1701,7 @@ function useMemory(autoFetch = true) {
1147
1701
  },
1148
1702
  [fetchWithAuth]
1149
1703
  );
1150
- const writeFile = useCallback2(
1704
+ const writeFile = useCallback3(
1151
1705
  async (params) => {
1152
1706
  const res = await fetchWithAuth("/memory/file", {
1153
1707
  method: "PUT",
@@ -1162,7 +1716,7 @@ function useMemory(autoFetch = true) {
1162
1716
  },
1163
1717
  [fetchWithAuth, fetchMemory]
1164
1718
  );
1165
- const deleteFile = useCallback2(
1719
+ const deleteFile = useCallback3(
1166
1720
  async (params) => {
1167
1721
  const query = new URLSearchParams({ path: params.path });
1168
1722
  if (params.scope) query.set("scope", params.scope);
@@ -1176,7 +1730,7 @@ function useMemory(autoFetch = true) {
1176
1730
  },
1177
1731
  [fetchWithAuth, fetchMemory]
1178
1732
  );
1179
- useEffect2(() => {
1733
+ useEffect3(() => {
1180
1734
  if (autoFetch) {
1181
1735
  void fetchMemory();
1182
1736
  }
@@ -1193,13 +1747,13 @@ function useMemory(autoFetch = true) {
1193
1747
  }
1194
1748
 
1195
1749
  // src/hooks/useThreads.ts
1196
- import { useCallback as useCallback3, useEffect as useEffect3, useState as useState3 } from "react";
1750
+ import { useCallback as useCallback4, useEffect as useEffect4, useState as useState4 } from "react";
1197
1751
  function useThreads(autoFetch = true) {
1198
1752
  const { fetchWithAuth, defaultAgentId } = usePersonaContext();
1199
- const [threads, setThreads] = useState3([]);
1200
- const [isLoading, setIsLoading] = useState3(false);
1201
- const [error, setError] = useState3(null);
1202
- const fetchThreads = useCallback3(async () => {
1753
+ const [threads, setThreads] = useState4([]);
1754
+ const [isLoading, setIsLoading] = useState4(false);
1755
+ const [error, setError] = useState4(null);
1756
+ const fetchThreads = useCallback4(async () => {
1203
1757
  setIsLoading(true);
1204
1758
  setError(null);
1205
1759
  try {
@@ -1217,7 +1771,7 @@ function useThreads(autoFetch = true) {
1217
1771
  setIsLoading(false);
1218
1772
  }
1219
1773
  }, [fetchWithAuth]);
1220
- const createThread = useCallback3(
1774
+ const createThread = useCallback4(
1221
1775
  async (agentId) => {
1222
1776
  const targetAgentId = agentId || defaultAgentId;
1223
1777
  const res = await fetchWithAuth("/threads", {
@@ -1234,7 +1788,7 @@ function useThreads(autoFetch = true) {
1234
1788
  },
1235
1789
  [fetchWithAuth, defaultAgentId, fetchThreads]
1236
1790
  );
1237
- const deleteThread = useCallback3(
1791
+ const deleteThread = useCallback4(
1238
1792
  async (threadId) => {
1239
1793
  const res = await fetchWithAuth(`/threads/${threadId}`, {
1240
1794
  method: "DELETE"
@@ -1245,7 +1799,7 @@ function useThreads(autoFetch = true) {
1245
1799
  },
1246
1800
  [fetchWithAuth]
1247
1801
  );
1248
- const bulkDeleteThreads = useCallback3(
1802
+ const bulkDeleteThreads = useCallback4(
1249
1803
  async (threadIds) => {
1250
1804
  const res = await fetchWithAuth("/threads/bulk-delete", {
1251
1805
  method: "POST",
@@ -1262,13 +1816,13 @@ function useThreads(autoFetch = true) {
1262
1816
  },
1263
1817
  [fetchWithAuth]
1264
1818
  );
1265
- const deleteAllThreads = useCallback3(async () => {
1819
+ const deleteAllThreads = useCallback4(async () => {
1266
1820
  const ids = threads.map((t) => t._id);
1267
1821
  for (let i = 0; i < ids.length; i += 100) {
1268
1822
  await bulkDeleteThreads(ids.slice(i, i + 100));
1269
1823
  }
1270
1824
  }, [threads, bulkDeleteThreads]);
1271
- const updateThread = useCallback3(
1825
+ const updateThread = useCallback4(
1272
1826
  async (threadId, input) => {
1273
1827
  const res = await fetchWithAuth(`/threads/${threadId}`, {
1274
1828
  method: "PATCH",
@@ -1286,11 +1840,11 @@ function useThreads(autoFetch = true) {
1286
1840
  },
1287
1841
  [fetchWithAuth]
1288
1842
  );
1289
- const renameThread = useCallback3(
1843
+ const renameThread = useCallback4(
1290
1844
  (threadId, title) => updateThread(threadId, { title }),
1291
1845
  [updateThread]
1292
1846
  );
1293
- const resetThread = useCallback3(
1847
+ const resetThread = useCallback4(
1294
1848
  async (threadId) => {
1295
1849
  const res = await fetchWithAuth(`/threads/${threadId}/reset`, {
1296
1850
  method: "POST"
@@ -1305,7 +1859,7 @@ function useThreads(autoFetch = true) {
1305
1859
  },
1306
1860
  [fetchWithAuth]
1307
1861
  );
1308
- const getThread = useCallback3(
1862
+ const getThread = useCallback4(
1309
1863
  async (threadId) => {
1310
1864
  const res = await fetchWithAuth(`/threads/${threadId}`);
1311
1865
  if (!res.ok) throw new Error(`Failed to fetch thread: ${res.statusText}`);
@@ -1314,7 +1868,7 @@ function useThreads(autoFetch = true) {
1314
1868
  },
1315
1869
  [fetchWithAuth]
1316
1870
  );
1317
- useEffect3(() => {
1871
+ useEffect4(() => {
1318
1872
  if (autoFetch) {
1319
1873
  void fetchThreads();
1320
1874
  }
@@ -1336,7 +1890,7 @@ function useThreads(autoFetch = true) {
1336
1890
  }
1337
1891
 
1338
1892
  // src/hooks/useVoice.ts
1339
- import { useCallback as useCallback4, useEffect as useEffect4, useMemo as useMemo3, useRef as useRef2, useState as useState4 } from "react";
1893
+ import { useCallback as useCallback5, useEffect as useEffect5, useMemo as useMemo4, useRef as useRef3, useState as useState5 } from "react";
1340
1894
 
1341
1895
  // src/hooks/voiceWorklets.ts
1342
1896
  var RECORDER_WORKLET_SOURCE = `
@@ -1439,42 +1993,42 @@ function mergeTranscriptText(prev, next) {
1439
1993
  }
1440
1994
  function useVoice(options = {}) {
1441
1995
  const { defaultAgentId, fetchWithAuth, logger } = usePersonaContext();
1442
- const voiceLogger = useMemo3(() => logger.child("voice"), [logger]);
1996
+ const voiceLogger = useMemo4(() => logger.child("voice"), [logger]);
1443
1997
  const agentId = options.agentId || defaultAgentId;
1444
1998
  const threadId = options.threadId;
1445
1999
  const contextOverride = options.contextOverride;
1446
2000
  const context = options.context;
1447
- const [state, setState] = useState4("idle");
1448
- const [isMuted, setIsMuted] = useState4(false);
1449
- const [transcript, setTranscript] = useState4(
2001
+ const [state, setState] = useState5("idle");
2002
+ const [isMuted, setIsMuted] = useState5(false);
2003
+ const [transcript, setTranscript] = useState5(
1450
2004
  []
1451
2005
  );
1452
- const [partial, setPartial] = useState4(
2006
+ const [partial, setPartial] = useState5(
1453
2007
  null
1454
2008
  );
1455
- const [toolCalls, setToolCalls] = useState4([]);
1456
- const [error, setError] = useState4(null);
1457
- const [endReason, setEndReason] = useState4(
2009
+ const [toolCalls, setToolCalls] = useState5([]);
2010
+ const [error, setError] = useState5(null);
2011
+ const [endReason, setEndReason] = useState5(
1458
2012
  null
1459
2013
  );
1460
- const wsRef = useRef2(null);
1461
- const streamRef = useRef2(null);
1462
- const inputCtxRef = useRef2(null);
1463
- const outputCtxRef = useRef2(null);
1464
- const recorderNodeRef = useRef2(null);
1465
- const playerNodeRef = useRef2(null);
1466
- const acceptedTurnSeqRef = useRef2(0);
1467
- const mountedRef = useRef2(true);
1468
- const lastFinalTurnRef = useRef2(
2014
+ const wsRef = useRef3(null);
2015
+ const streamRef = useRef3(null);
2016
+ const inputCtxRef = useRef3(null);
2017
+ const outputCtxRef = useRef3(null);
2018
+ const recorderNodeRef = useRef3(null);
2019
+ const playerNodeRef = useRef3(null);
2020
+ const acceptedTurnSeqRef = useRef3(0);
2021
+ const mountedRef = useRef3(true);
2022
+ const lastFinalTurnRef = useRef3(
1469
2023
  null
1470
2024
  );
1471
- useEffect4(() => {
2025
+ useEffect5(() => {
1472
2026
  mountedRef.current = true;
1473
2027
  return () => {
1474
2028
  mountedRef.current = false;
1475
2029
  };
1476
2030
  }, []);
1477
- const teardownAudio = useCallback4(() => {
2031
+ const teardownAudio = useCallback5(() => {
1478
2032
  try {
1479
2033
  streamRef.current?.getTracks().forEach((track) => track.stop());
1480
2034
  } catch {
@@ -1501,7 +2055,7 @@ function useVoice(options = {}) {
1501
2055
  }
1502
2056
  outputCtxRef.current = null;
1503
2057
  }, []);
1504
- const stop = useCallback4(() => {
2058
+ const stop = useCallback5(() => {
1505
2059
  voiceLogger.debug("stop() called");
1506
2060
  try {
1507
2061
  wsRef.current?.close(1e3, "client_stop");
@@ -1511,8 +2065,8 @@ function useVoice(options = {}) {
1511
2065
  teardownAudio();
1512
2066
  if (mountedRef.current) setState("idle");
1513
2067
  }, [teardownAudio, voiceLogger]);
1514
- useEffect4(() => stop, [stop]);
1515
- const startCapture = useCallback4(async (inputSampleRate) => {
2068
+ useEffect5(() => stop, [stop]);
2069
+ const startCapture = useCallback5(async (inputSampleRate) => {
1516
2070
  const stream = await navigator.mediaDevices.getUserMedia({
1517
2071
  audio: {
1518
2072
  echoCancellation: true,
@@ -1538,7 +2092,7 @@ function useVoice(options = {}) {
1538
2092
  recorderNodeRef.current = recorderNode;
1539
2093
  source.connect(recorderNode);
1540
2094
  }, []);
1541
- const setupPlayback = useCallback4(async (outputSampleRate) => {
2095
+ const setupPlayback = useCallback5(async (outputSampleRate) => {
1542
2096
  const outputCtx = new AudioContext({ sampleRate: outputSampleRate });
1543
2097
  outputCtxRef.current = outputCtx;
1544
2098
  await outputCtx.audioWorklet.addModule(playerWorkletUrl());
@@ -1546,7 +2100,7 @@ function useVoice(options = {}) {
1546
2100
  playerNode.connect(outputCtx.destination);
1547
2101
  playerNodeRef.current = playerNode;
1548
2102
  }, []);
1549
- const upsertToolCall = useCallback4(
2103
+ const upsertToolCall = useCallback5(
1550
2104
  (id, patch) => {
1551
2105
  setToolCalls((prev) => {
1552
2106
  const idx = prev.findIndex((t) => t.id === id);
@@ -1558,7 +2112,7 @@ function useVoice(options = {}) {
1558
2112
  },
1559
2113
  []
1560
2114
  );
1561
- const handleTranscript = useCallback4((value) => {
2115
+ const handleTranscript = useCallback5((value) => {
1562
2116
  const { speaker, text, isFinal, turnSeq } = value;
1563
2117
  if (!isFinal) {
1564
2118
  setPartial({ id: "partial", speaker, text });
@@ -1581,7 +2135,7 @@ function useVoice(options = {}) {
1581
2135
  });
1582
2136
  lastFinalTurnRef.current = { speaker, turnSeq };
1583
2137
  }, []);
1584
- const handleCustomEvent = useCallback4(
2138
+ const handleCustomEvent = useCallback5(
1585
2139
  (name, value) => {
1586
2140
  switch (name) {
1587
2141
  case "voice_session_ready":
@@ -1639,7 +2193,7 @@ function useVoice(options = {}) {
1639
2193
  },
1640
2194
  [handleTranscript, setupPlayback, startCapture, teardownAudio, voiceLogger]
1641
2195
  );
1642
- const handleMessage = useCallback4(
2196
+ const handleMessage = useCallback5(
1643
2197
  (event) => {
1644
2198
  if (typeof event.data !== "string") {
1645
2199
  const buf = event.data;
@@ -1697,7 +2251,7 @@ function useVoice(options = {}) {
1697
2251
  },
1698
2252
  [handleCustomEvent, upsertToolCall, voiceLogger]
1699
2253
  );
1700
- const start = useCallback4(async () => {
2254
+ const start = useCallback5(async () => {
1701
2255
  if (!agentId) {
1702
2256
  const err = new Error(
1703
2257
  "useVoice: no agentId provided and no defaultAgentId set on PersonaProvider"
@@ -1764,17 +2318,17 @@ function useVoice(options = {}) {
1764
2318
  teardownAudio();
1765
2319
  }
1766
2320
  }, [agentId, threadId, contextOverride, context, fetchWithAuth, handleMessage, teardownAudio, voiceLogger]);
1767
- const mute = useCallback4((muted) => {
2321
+ const mute = useCallback5((muted) => {
1768
2322
  setIsMuted(muted);
1769
2323
  streamRef.current?.getAudioTracks().forEach((track) => {
1770
2324
  track.enabled = !muted;
1771
2325
  });
1772
2326
  }, []);
1773
- const sendText = useCallback4((text) => {
2327
+ const sendText = useCallback5((text) => {
1774
2328
  if (!text?.trim() || wsRef.current?.readyState !== WebSocket.OPEN) return;
1775
2329
  wsRef.current.send(JSON.stringify({ type: "voice.text", text }));
1776
2330
  }, []);
1777
- const updateContext = useCallback4((newContext) => {
2331
+ const updateContext = useCallback5((newContext) => {
1778
2332
  if (wsRef.current?.readyState !== WebSocket.OPEN) return;
1779
2333
  wsRef.current.send(JSON.stringify({ type: "voice.context", context: newContext }));
1780
2334
  }, []);
@@ -1795,14 +2349,14 @@ function useVoice(options = {}) {
1795
2349
  }
1796
2350
 
1797
2351
  // src/hooks/useFiles.ts
1798
- import { useCallback as useCallback5, useEffect as useEffect5, useState as useState5 } from "react";
2352
+ import { useCallback as useCallback6, useEffect as useEffect6, useState as useState6 } from "react";
1799
2353
  function useFiles(autoFetch = true) {
1800
2354
  const { fetchWithAuth } = usePersonaContext();
1801
- const [files, setFiles] = useState5([]);
1802
- const [isLoading, setIsLoading] = useState5(false);
1803
- const [isUploading, setIsUploading] = useState5(false);
1804
- const [error, setError] = useState5(null);
1805
- const fetchFiles = useCallback5(async () => {
2355
+ const [files, setFiles] = useState6([]);
2356
+ const [isLoading, setIsLoading] = useState6(false);
2357
+ const [isUploading, setIsUploading] = useState6(false);
2358
+ const [error, setError] = useState6(null);
2359
+ const fetchFiles = useCallback6(async () => {
1806
2360
  setIsLoading(true);
1807
2361
  setError(null);
1808
2362
  try {
@@ -1820,7 +2374,7 @@ function useFiles(autoFetch = true) {
1820
2374
  setIsLoading(false);
1821
2375
  }
1822
2376
  }, [fetchWithAuth]);
1823
- const uploadFile = useCallback5(
2377
+ const uploadFile = useCallback6(
1824
2378
  async (fileOrFormData) => {
1825
2379
  setIsUploading(true);
1826
2380
  setError(null);
@@ -1853,7 +2407,7 @@ function useFiles(autoFetch = true) {
1853
2407
  },
1854
2408
  [fetchWithAuth, fetchFiles]
1855
2409
  );
1856
- const deleteFile = useCallback5(
2410
+ const deleteFile = useCallback6(
1857
2411
  async (fileId) => {
1858
2412
  const res = await fetchWithAuth(`/files/${fileId}`, { method: "DELETE" });
1859
2413
  if (!res.ok) throw new Error(`Failed to delete file: ${res.statusText}`);
@@ -1861,7 +2415,7 @@ function useFiles(autoFetch = true) {
1861
2415
  },
1862
2416
  [fetchWithAuth]
1863
2417
  );
1864
- const bulkDeleteFiles = useCallback5(
2418
+ const bulkDeleteFiles = useCallback6(
1865
2419
  async (fileIds) => {
1866
2420
  const res = await fetchWithAuth("/files/bulk-delete", {
1867
2421
  method: "POST",
@@ -1876,10 +2430,10 @@ function useFiles(autoFetch = true) {
1876
2430
  },
1877
2431
  [fetchWithAuth]
1878
2432
  );
1879
- const getDownloadUrl = useCallback5((fileId) => {
2433
+ const getDownloadUrl = useCallback6((fileId) => {
1880
2434
  return `/files/${fileId}`;
1881
2435
  }, []);
1882
- useEffect5(() => {
2436
+ useEffect6(() => {
1883
2437
  if (autoFetch) {
1884
2438
  void fetchFiles();
1885
2439
  }
@@ -1898,13 +2452,13 @@ function useFiles(autoFetch = true) {
1898
2452
  }
1899
2453
 
1900
2454
  // src/hooks/useAgents.ts
1901
- import { useCallback as useCallback6, useEffect as useEffect6, useState as useState6 } from "react";
2455
+ import { useCallback as useCallback7, useEffect as useEffect7, useState as useState7 } from "react";
1902
2456
  function useAgents(autoFetch = true) {
1903
2457
  const { fetchWithAuth } = usePersonaContext();
1904
- const [agents, setAgents] = useState6([]);
1905
- const [isLoading, setIsLoading] = useState6(false);
1906
- const [error, setError] = useState6(null);
1907
- const fetchAgents = useCallback6(async () => {
2458
+ const [agents, setAgents] = useState7([]);
2459
+ const [isLoading, setIsLoading] = useState7(false);
2460
+ const [error, setError] = useState7(null);
2461
+ const fetchAgents = useCallback7(async () => {
1908
2462
  setIsLoading(true);
1909
2463
  setError(null);
1910
2464
  try {
@@ -1922,7 +2476,7 @@ function useAgents(autoFetch = true) {
1922
2476
  setIsLoading(false);
1923
2477
  }
1924
2478
  }, [fetchWithAuth]);
1925
- useEffect6(() => {
2479
+ useEffect7(() => {
1926
2480
  if (autoFetch) {
1927
2481
  void fetchAgents();
1928
2482
  }
@@ -1936,13 +2490,13 @@ function useAgents(autoFetch = true) {
1936
2490
  }
1937
2491
 
1938
2492
  // src/hooks/useConnection.ts
1939
- import { useCallback as useCallback7, useEffect as useEffect7, useState as useState7 } from "react";
2493
+ import { useCallback as useCallback8, useEffect as useEffect8, useState as useState8 } from "react";
1940
2494
  function useConnection(autoCheck = true) {
1941
2495
  const { fetchWithAuth } = usePersonaContext();
1942
- const [health, setHealth] = useState7(null);
1943
- const [isConnected, setIsConnected] = useState7(false);
1944
- const [isLoading, setIsLoading] = useState7(false);
1945
- const checkHealth = useCallback7(async () => {
2496
+ const [health, setHealth] = useState8(null);
2497
+ const [isConnected, setIsConnected] = useState8(false);
2498
+ const [isLoading, setIsLoading] = useState8(false);
2499
+ const checkHealth = useCallback8(async () => {
1946
2500
  setIsLoading(true);
1947
2501
  try {
1948
2502
  const res = await fetchWithAuth("/health");
@@ -1961,7 +2515,7 @@ function useConnection(autoCheck = true) {
1961
2515
  setIsLoading(false);
1962
2516
  }
1963
2517
  }, [fetchWithAuth]);
1964
- useEffect7(() => {
2518
+ useEffect8(() => {
1965
2519
  if (autoCheck) {
1966
2520
  void checkHealth();
1967
2521
  }
@@ -1975,15 +2529,15 @@ function useConnection(autoCheck = true) {
1975
2529
  }
1976
2530
 
1977
2531
  // src/hooks/useMcpConnections.ts
1978
- import { useCallback as useCallback8, useEffect as useEffect8, useState as useState8 } from "react";
2532
+ import { useCallback as useCallback9, useEffect as useEffect9, useState as useState9 } from "react";
1979
2533
  function useMcpConnections(options = {}) {
1980
2534
  const { defaultAgentId, fetchWithAuth } = usePersonaContext();
1981
2535
  const agentId = options.agentId ?? defaultAgentId;
1982
2536
  const autoFetch = options.autoFetch ?? true;
1983
- const [connections, setConnections] = useState8([]);
1984
- const [isLoading, setIsLoading] = useState8(false);
1985
- const [error, setError] = useState8(null);
1986
- const fetchConnections = useCallback8(async () => {
2537
+ const [connections, setConnections] = useState9([]);
2538
+ const [isLoading, setIsLoading] = useState9(false);
2539
+ const [error, setError] = useState9(null);
2540
+ const fetchConnections = useCallback9(async () => {
1987
2541
  if (!agentId) return [];
1988
2542
  setIsLoading(true);
1989
2543
  setError(null);
@@ -2007,7 +2561,7 @@ function useMcpConnections(options = {}) {
2007
2561
  setIsLoading(false);
2008
2562
  }
2009
2563
  }, [agentId, fetchWithAuth, options.returnTo]);
2010
- useEffect8(() => {
2564
+ useEffect9(() => {
2011
2565
  if (autoFetch) void fetchConnections();
2012
2566
  }, [autoFetch, fetchConnections]);
2013
2567
  return {
@@ -2021,11 +2575,11 @@ function useMcpConnections(options = {}) {
2021
2575
  }
2022
2576
 
2023
2577
  // src/hooks/useMcp.ts
2024
- import { useCallback as useCallback9 } from "react";
2578
+ import { useCallback as useCallback10 } from "react";
2025
2579
  function useMcp(options = {}) {
2026
2580
  const { fetchWithAuth } = usePersonaContext();
2027
2581
  const defaultMcpId = options.mcpId;
2028
- const readResource = useCallback9(
2582
+ const readResource = useCallback10(
2029
2583
  async (uri, mcpId) => {
2030
2584
  const id = mcpId ?? defaultMcpId;
2031
2585
  if (!id) throw new Error("MCP server ID is required to read resource");
@@ -2039,7 +2593,7 @@ function useMcp(options = {}) {
2039
2593
  },
2040
2594
  [fetchWithAuth, defaultMcpId]
2041
2595
  );
2042
- const callTool = useCallback9(
2596
+ const callTool = useCallback10(
2043
2597
  async (name, args, mcpId) => {
2044
2598
  const id = mcpId ?? defaultMcpId;
2045
2599
  if (!id) throw new Error("MCP server ID is required to call tool");
@@ -2062,21 +2616,21 @@ function useMcp(options = {}) {
2062
2616
  }
2063
2617
 
2064
2618
  // src/hooks/useWorkflows.ts
2065
- import { useCallback as useCallback10, useEffect as useEffect9, useState as useState9 } from "react";
2619
+ import { useCallback as useCallback11, useEffect as useEffect10, useState as useState10 } from "react";
2066
2620
  function useWorkflows(options) {
2067
2621
  const opts = typeof options === "boolean" ? { autoFetch: options } : options ?? {};
2068
2622
  const { autoFetch = true, search, status, page, limit } = opts;
2069
2623
  const { fetchWithAuth } = usePersonaContext();
2070
- const [workflows, setWorkflows] = useState9([]);
2071
- const [pagination, setPagination] = useState9({
2624
+ const [workflows, setWorkflows] = useState10([]);
2625
+ const [pagination, setPagination] = useState10({
2072
2626
  page: page ?? 1,
2073
2627
  limit: limit ?? 20,
2074
2628
  total: 0,
2075
2629
  totalPages: 0
2076
2630
  });
2077
- const [isLoading, setIsLoading] = useState9(false);
2078
- const [error, setError] = useState9(null);
2079
- const fetchWorkflows = useCallback10(async () => {
2631
+ const [isLoading, setIsLoading] = useState10(false);
2632
+ const [error, setError] = useState10(null);
2633
+ const fetchWorkflows = useCallback11(async () => {
2080
2634
  setIsLoading(true);
2081
2635
  setError(null);
2082
2636
  try {
@@ -2117,7 +2671,7 @@ function useWorkflows(options) {
2117
2671
  setIsLoading(false);
2118
2672
  }
2119
2673
  }, [fetchWithAuth, search, status, page, limit]);
2120
- const createWorkflow = useCallback10(
2674
+ const createWorkflow = useCallback11(
2121
2675
  async (input) => {
2122
2676
  setError(null);
2123
2677
  try {
@@ -2141,7 +2695,7 @@ function useWorkflows(options) {
2141
2695
  },
2142
2696
  [fetchWithAuth]
2143
2697
  );
2144
- useEffect9(() => {
2698
+ useEffect10(() => {
2145
2699
  if (autoFetch) {
2146
2700
  void fetchWorkflows();
2147
2701
  }
@@ -2157,17 +2711,17 @@ function useWorkflows(options) {
2157
2711
  }
2158
2712
 
2159
2713
  // src/hooks/useWorkflow.ts
2160
- import { useCallback as useCallback11, useEffect as useEffect10, useState as useState10 } from "react";
2714
+ import { useCallback as useCallback12, useEffect as useEffect11, useState as useState11 } from "react";
2161
2715
  function useWorkflow(workflowId, options) {
2162
2716
  const opts = typeof options === "boolean" ? { autoFetch: options } : options ?? {};
2163
2717
  const { autoFetch = true } = opts;
2164
2718
  const { fetchWithAuth } = usePersonaContext();
2165
- const [workflow, setWorkflow] = useState10(null);
2166
- const [versions, setVersions] = useState10([]);
2167
- const [mermaid, setMermaid] = useState10(null);
2168
- const [isLoading, setIsLoading] = useState10(false);
2169
- const [error, setError] = useState10(null);
2170
- const fetchWorkflow = useCallback11(async () => {
2719
+ const [workflow, setWorkflow] = useState11(null);
2720
+ const [versions, setVersions] = useState11([]);
2721
+ const [mermaid, setMermaid] = useState11(null);
2722
+ const [isLoading, setIsLoading] = useState11(false);
2723
+ const [error, setError] = useState11(null);
2724
+ const fetchWorkflow = useCallback12(async () => {
2171
2725
  if (!workflowId) return null;
2172
2726
  setIsLoading(true);
2173
2727
  setError(null);
@@ -2187,7 +2741,7 @@ function useWorkflow(workflowId, options) {
2187
2741
  setIsLoading(false);
2188
2742
  }
2189
2743
  }, [fetchWithAuth, workflowId]);
2190
- const fetchVersions = useCallback11(async () => {
2744
+ const fetchVersions = useCallback12(async () => {
2191
2745
  if (!workflowId) return [];
2192
2746
  try {
2193
2747
  const res = await fetchWithAuth(`/workflows/${workflowId}/versions`);
@@ -2200,7 +2754,7 @@ function useWorkflow(workflowId, options) {
2200
2754
  return [];
2201
2755
  }
2202
2756
  }, [fetchWithAuth, workflowId]);
2203
- const fetchMermaid = useCallback11(async () => {
2757
+ const fetchMermaid = useCallback12(async () => {
2204
2758
  if (!workflowId) return "";
2205
2759
  try {
2206
2760
  const res = await fetchWithAuth(`/workflows/${workflowId}/mermaid`);
@@ -2213,7 +2767,7 @@ function useWorkflow(workflowId, options) {
2213
2767
  return "";
2214
2768
  }
2215
2769
  }, [fetchWithAuth, workflowId]);
2216
- const saveDraft = useCallback11(
2770
+ const saveDraft = useCallback12(
2217
2771
  async (draft) => {
2218
2772
  if (!workflowId) throw new Error("Workflow ID is required");
2219
2773
  setError(null);
@@ -2232,7 +2786,7 @@ function useWorkflow(workflowId, options) {
2232
2786
  },
2233
2787
  [fetchWithAuth, workflowId]
2234
2788
  );
2235
- const publish = useCallback11(
2789
+ const publish = useCallback12(
2236
2790
  async (summary) => {
2237
2791
  if (!workflowId) throw new Error("Workflow ID is required");
2238
2792
  setError(null);
@@ -2252,7 +2806,7 @@ function useWorkflow(workflowId, options) {
2252
2806
  },
2253
2807
  [fetchWithAuth, workflowId, fetchWorkflow, fetchVersions]
2254
2808
  );
2255
- const deleteWorkflow = useCallback11(async () => {
2809
+ const deleteWorkflow = useCallback12(async () => {
2256
2810
  if (!workflowId) throw new Error("Workflow ID is required");
2257
2811
  setError(null);
2258
2812
  const res = await fetchWithAuth(`/workflows/${workflowId}`, {
@@ -2263,7 +2817,7 @@ function useWorkflow(workflowId, options) {
2263
2817
  }
2264
2818
  setWorkflow(null);
2265
2819
  }, [fetchWithAuth, workflowId]);
2266
- useEffect10(() => {
2820
+ useEffect11(() => {
2267
2821
  if (autoFetch && workflowId) {
2268
2822
  void fetchWorkflow();
2269
2823
  }
@@ -2284,25 +2838,25 @@ function useWorkflow(workflowId, options) {
2284
2838
  }
2285
2839
 
2286
2840
  // src/hooks/useWorkflowStream.ts
2287
- import { useCallback as useCallback12, useEffect as useEffect11, useRef as useRef3, useState as useState11 } from "react";
2841
+ import { useCallback as useCallback13, useEffect as useEffect12, useRef as useRef4, useState as useState12 } from "react";
2288
2842
  function useWorkflowStream(workflowId, options) {
2289
2843
  const { baseUrl, getAuthToken, fetchWithAuth, logger } = usePersonaContext();
2290
- const [status, setStatus] = useState11("idle");
2291
- const [runId, setRunId] = useState11(null);
2292
- const [activeNodeId, setActiveNodeId] = useState11(null);
2293
- const [nodeRuns, setNodeRuns] = useState11(
2844
+ const [status, setStatus] = useState12("idle");
2845
+ const [runId, setRunId] = useState12(null);
2846
+ const [activeNodeId, setActiveNodeId] = useState12(null);
2847
+ const [nodeRuns, setNodeRuns] = useState12(
2294
2848
  {}
2295
2849
  );
2296
- const [text, setText] = useState11("");
2297
- const [output, setOutput] = useState11(null);
2298
- const [error, setError] = useState11(null);
2299
- const [events, setEvents] = useState11([]);
2300
- const abortControllerRef = useRef3(null);
2301
- const currentRunIdRef = useRef3(null);
2850
+ const [text, setText] = useState12("");
2851
+ const [output, setOutput] = useState12(null);
2852
+ const [error, setError] = useState12(null);
2853
+ const [events, setEvents] = useState12([]);
2854
+ const abortControllerRef = useRef4(null);
2855
+ const currentRunIdRef = useRef4(null);
2302
2856
  currentRunIdRef.current = runId;
2303
- const optionsRef = useRef3(options);
2857
+ const optionsRef = useRef4(options);
2304
2858
  optionsRef.current = options;
2305
- const cancel = useCallback12(async () => {
2859
+ const cancel = useCallback13(async () => {
2306
2860
  if (abortControllerRef.current) {
2307
2861
  abortControllerRef.current.abort();
2308
2862
  abortControllerRef.current = null;
@@ -2323,7 +2877,7 @@ function useWorkflowStream(workflowId, options) {
2323
2877
  setStatus("cancelled");
2324
2878
  setActiveNodeId(null);
2325
2879
  }, [fetchWithAuth, logger]);
2326
- const reset = useCallback12(() => {
2880
+ const reset = useCallback13(() => {
2327
2881
  if (abortControllerRef.current) {
2328
2882
  abortControllerRef.current.abort();
2329
2883
  abortControllerRef.current = null;
@@ -2337,7 +2891,7 @@ function useWorkflowStream(workflowId, options) {
2337
2891
  setError(null);
2338
2892
  setEvents([]);
2339
2893
  }, []);
2340
- const processStream = useCallback12(
2894
+ const processStream = useCallback13(
2341
2895
  async (url, method, body, targetRunId) => {
2342
2896
  if (abortControllerRef.current) {
2343
2897
  abortControllerRef.current.abort();
@@ -2502,7 +3056,7 @@ function useWorkflowStream(workflowId, options) {
2502
3056
  },
2503
3057
  [getAuthToken]
2504
3058
  );
2505
- const start = useCallback12(
3059
+ const start = useCallback13(
2506
3060
  async (input, opts) => {
2507
3061
  const targetWfId = opts?.workflowId || workflowId;
2508
3062
  if (!targetWfId) {
@@ -2523,7 +3077,7 @@ function useWorkflowStream(workflowId, options) {
2523
3077
  },
2524
3078
  [workflowId, baseUrl, processStream]
2525
3079
  );
2526
- const resume = useCallback12(
3080
+ const resume = useCallback13(
2527
3081
  async (targetRunId, sinceSeq) => {
2528
3082
  if (!targetRunId) {
2529
3083
  throw new Error("Run ID is required to resume stream");
@@ -2536,7 +3090,7 @@ function useWorkflowStream(workflowId, options) {
2536
3090
  },
2537
3091
  [baseUrl, processStream]
2538
3092
  );
2539
- useEffect11(() => {
3093
+ useEffect12(() => {
2540
3094
  return () => {
2541
3095
  if (abortControllerRef.current) {
2542
3096
  abortControllerRef.current.abort();
@@ -2561,21 +3115,21 @@ function useWorkflowStream(workflowId, options) {
2561
3115
  }
2562
3116
 
2563
3117
  // src/hooks/useWorkflowRuns.ts
2564
- import { useCallback as useCallback13, useEffect as useEffect12, useState as useState12 } from "react";
3118
+ import { useCallback as useCallback14, useEffect as useEffect13, useState as useState13 } from "react";
2565
3119
  function useWorkflowRuns(workflowId, options) {
2566
3120
  const opts = typeof options === "boolean" ? { autoFetch: options } : options ?? {};
2567
3121
  const { autoFetch = true, page = 1, limit = 20 } = opts;
2568
3122
  const { fetchWithAuth } = usePersonaContext();
2569
- const [runs, setRuns] = useState12([]);
2570
- const [pagination, setPagination] = useState12({
3123
+ const [runs, setRuns] = useState13([]);
3124
+ const [pagination, setPagination] = useState13({
2571
3125
  page,
2572
3126
  limit,
2573
3127
  total: 0,
2574
3128
  totalPages: 0
2575
3129
  });
2576
- const [isLoading, setIsLoading] = useState12(false);
2577
- const [error, setError] = useState12(null);
2578
- const fetchRuns = useCallback13(async () => {
3130
+ const [isLoading, setIsLoading] = useState13(false);
3131
+ const [error, setError] = useState13(null);
3132
+ const fetchRuns = useCallback14(async () => {
2579
3133
  if (!workflowId) return [];
2580
3134
  setIsLoading(true);
2581
3135
  setError(null);
@@ -2605,7 +3159,7 @@ function useWorkflowRuns(workflowId, options) {
2605
3159
  setIsLoading(false);
2606
3160
  }
2607
3161
  }, [fetchWithAuth, workflowId, page, limit]);
2608
- const getRun = useCallback13(
3162
+ const getRun = useCallback14(
2609
3163
  async (runId) => {
2610
3164
  if (!runId) throw new Error("Run ID is required");
2611
3165
  const res = await fetchWithAuth(`/workflows/runs/${runId}`);
@@ -2616,7 +3170,7 @@ function useWorkflowRuns(workflowId, options) {
2616
3170
  },
2617
3171
  [fetchWithAuth]
2618
3172
  );
2619
- const cancelRun = useCallback13(
3173
+ const cancelRun = useCallback14(
2620
3174
  async (runId) => {
2621
3175
  if (!runId) throw new Error("Run ID is required");
2622
3176
  const res = await fetchWithAuth(`/workflows/runs/${runId}/cancel`, {
@@ -2631,7 +3185,7 @@ function useWorkflowRuns(workflowId, options) {
2631
3185
  },
2632
3186
  [fetchWithAuth]
2633
3187
  );
2634
- useEffect12(() => {
3188
+ useEffect13(() => {
2635
3189
  if (autoFetch && workflowId) {
2636
3190
  void fetchRuns();
2637
3191
  }
@@ -2655,8 +3209,9 @@ import {
2655
3209
  getLogLevel,
2656
3210
  isLevelEnabled
2657
3211
  } from "@personaai/logger";
2658
- var VERSION = "0.9.0";
3212
+ var VERSION = "0.10.0";
2659
3213
  export {
3214
+ ARCHITECT_AGENT_ID,
2660
3215
  PersonaProvider,
2661
3216
  VERSION,
2662
3217
  createLogger2 as createLogger,
@@ -2667,6 +3222,7 @@ export {
2667
3222
  setLogLevel,
2668
3223
  supportsStreamingFetch,
2669
3224
  useAgents,
3225
+ useArchitectChat,
2670
3226
  useChat,
2671
3227
  useConnection,
2672
3228
  useFiles,