skydive-cli 0.1.0-beta.45 → 0.1.0-beta.49
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/js/bin.mjs
CHANGED
|
@@ -13,7 +13,7 @@ import fs from "node:fs";
|
|
|
13
13
|
import zlib from "node:zlib";
|
|
14
14
|
|
|
15
15
|
//#region package.json
|
|
16
|
-
var version$1 = "0.1.0-beta.
|
|
16
|
+
var version$1 = "0.1.0-beta.49";
|
|
17
17
|
|
|
18
18
|
//#endregion
|
|
19
19
|
//#region src/types.ts
|
|
@@ -2046,7 +2046,7 @@ const chatCommand = {
|
|
|
2046
2046
|
printError(`Unknown theme "${themeId}". Valid themes: ${themes.map((t) => t.id).join(", ")}`);
|
|
2047
2047
|
process.exit(1);
|
|
2048
2048
|
}
|
|
2049
|
-
const { runChat } = await import("./boot-
|
|
2049
|
+
const { runChat } = await import("./boot-h5qiGgfB.mjs");
|
|
2050
2050
|
await runChat({
|
|
2051
2051
|
appUrl,
|
|
2052
2052
|
sessionToken: session.value.sessionToken,
|
|
@@ -7,10 +7,11 @@ import open from "open";
|
|
|
7
7
|
import { spawn } from "node:child_process";
|
|
8
8
|
import { MarkdownRenderable, RenderableEvents, SyntaxStyle, createCliRenderer, decodePasteBytes, detectLinks } from "@opentui/core";
|
|
9
9
|
import { createRoot, extend, useKeyboard, usePaste, useRenderer, useTerminalDimensions } from "@opentui/react";
|
|
10
|
-
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
10
|
+
import { createContext, useCallback, useContext, useEffect, useMemo, useRef, useState } from "react";
|
|
11
11
|
import { create } from "zustand";
|
|
12
12
|
import { WebSocket } from "ws";
|
|
13
13
|
import os, { homedir, platform, release, tmpdir } from "node:os";
|
|
14
|
+
import { createConnection } from "node:net";
|
|
14
15
|
import { appendFile, mkdir, readFile, rm, stat, writeFile } from "node:fs/promises";
|
|
15
16
|
import { Fragment, jsx, jsxs } from "@opentui/react/jsx-runtime";
|
|
16
17
|
import { fileURLToPath } from "node:url";
|
|
@@ -65,7 +66,6 @@ const useStore = create((set, get) => ({
|
|
|
65
66
|
chatTitle: null,
|
|
66
67
|
portal: initialPortalUi,
|
|
67
68
|
portalClient: null,
|
|
68
|
-
attention: null,
|
|
69
69
|
toast: null,
|
|
70
70
|
goTo: (screen) => set({
|
|
71
71
|
screen,
|
|
@@ -122,7 +122,6 @@ const useStore = create((set, get) => ({
|
|
|
122
122
|
...state.portal,
|
|
123
123
|
prompt
|
|
124
124
|
} })),
|
|
125
|
-
setAttention: (attention) => set({ attention }),
|
|
126
125
|
showToast: (input) => set({ toast: createToast(input) }),
|
|
127
126
|
dismissToast: (id) => set((state) => state.toast?.id === id ? { toast: null } : {})
|
|
128
127
|
}));
|
|
@@ -649,19 +648,49 @@ function usePortal({ appUrl, sessionToken, shareMachine }) {
|
|
|
649
648
|
}
|
|
650
649
|
|
|
651
650
|
//#endregion
|
|
652
|
-
//#region src/chat/
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
651
|
+
//#region src/chat/agent-host/context.tsx
|
|
652
|
+
const noopAgentHost = {
|
|
653
|
+
transition() {},
|
|
654
|
+
setSession() {},
|
|
655
|
+
dispose() {}
|
|
656
|
+
};
|
|
657
|
+
const AgentHostContext = createContext(noopAgentHost);
|
|
658
|
+
function useAgentHost() {
|
|
659
|
+
return useContext(AgentHostContext);
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
//#endregion
|
|
663
|
+
//#region src/chat/agent-host/compose.ts
|
|
664
|
+
/** Fans semantic events out to every detected adapter. */
|
|
665
|
+
function composeAgentHost(adapters) {
|
|
666
|
+
let disposed = false;
|
|
667
|
+
return {
|
|
668
|
+
transition(transition) {
|
|
669
|
+
if (disposed) return;
|
|
670
|
+
for (const adapter of adapters) adapter.transition?.(transition);
|
|
671
|
+
},
|
|
672
|
+
setSession(sessionId) {
|
|
673
|
+
if (disposed) return;
|
|
674
|
+
for (const adapter of adapters) adapter.setSession?.(sessionId);
|
|
675
|
+
},
|
|
676
|
+
dispose() {
|
|
677
|
+
if (disposed) return;
|
|
678
|
+
disposed = true;
|
|
679
|
+
for (const adapter of adapters) adapter.dispose?.();
|
|
680
|
+
}
|
|
681
|
+
};
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
//#endregion
|
|
685
|
+
//#region src/chat/agent-host/adapters/terminal-notifications.ts
|
|
660
686
|
function shouldNotify({ enabled, focus }) {
|
|
661
687
|
return enabled && focus === "blurred";
|
|
662
688
|
}
|
|
663
|
-
|
|
664
|
-
|
|
689
|
+
function notificationMessage({ event, agentName, message }) {
|
|
690
|
+
if (message) return {
|
|
691
|
+
title: agentName,
|
|
692
|
+
message
|
|
693
|
+
};
|
|
665
694
|
switch (event) {
|
|
666
695
|
case "run-finished": return {
|
|
667
696
|
title: agentName,
|
|
@@ -674,12 +703,10 @@ function attentionMessage(event, agentName) {
|
|
|
674
703
|
}
|
|
675
704
|
}
|
|
676
705
|
/**
|
|
677
|
-
*
|
|
678
|
-
*
|
|
679
|
-
* focus/blur events are the source of truth for whether the terminal is in the
|
|
680
|
-
* foreground.
|
|
706
|
+
* Sends focus-gated desktop notifications through OpenTUI. OpenTUI selects
|
|
707
|
+
* OSC 9/99/777 for the detected terminal; this adapter owns that transport.
|
|
681
708
|
*/
|
|
682
|
-
function
|
|
709
|
+
function createTerminalNotificationsAdapter({ renderer, enabled }) {
|
|
683
710
|
let focus = "unknown";
|
|
684
711
|
const onFocus = () => {
|
|
685
712
|
focus = "focused";
|
|
@@ -690,12 +717,12 @@ function createAttention({ renderer, enabled }) {
|
|
|
690
717
|
renderer.on("focus", onFocus);
|
|
691
718
|
renderer.on("blur", onBlur);
|
|
692
719
|
return {
|
|
693
|
-
|
|
694
|
-
if (!shouldNotify({
|
|
720
|
+
transition({ notification }) {
|
|
721
|
+
if (!notification || !shouldNotify({
|
|
695
722
|
enabled,
|
|
696
723
|
focus
|
|
697
724
|
})) return;
|
|
698
|
-
const { title, message } =
|
|
725
|
+
const { title, message } = notificationMessage(notification);
|
|
699
726
|
try {
|
|
700
727
|
renderer.triggerNotification(message, title);
|
|
701
728
|
} catch (_error) {}
|
|
@@ -707,6 +734,181 @@ function createAttention({ renderer, enabled }) {
|
|
|
707
734
|
};
|
|
708
735
|
}
|
|
709
736
|
|
|
737
|
+
//#endregion
|
|
738
|
+
//#region src/chat/agent-host/adapters/herdr/adapter.ts
|
|
739
|
+
/** Maps one complete semantic transition to one herdr state report. */
|
|
740
|
+
function createHerdrAdapter(herdr) {
|
|
741
|
+
let lastState;
|
|
742
|
+
return {
|
|
743
|
+
transition({ state, notification }) {
|
|
744
|
+
if (state === lastState && !notification) return;
|
|
745
|
+
lastState = state;
|
|
746
|
+
const message = state === "idle" && notification?.event === "run-finished" ? notification.message : void 0;
|
|
747
|
+
herdr.report(state, message);
|
|
748
|
+
},
|
|
749
|
+
setSession: herdr.setConversation,
|
|
750
|
+
dispose: herdr.dispose
|
|
751
|
+
};
|
|
752
|
+
}
|
|
753
|
+
|
|
754
|
+
//#endregion
|
|
755
|
+
//#region src/chat/agent-host/adapters/herdr/client.ts
|
|
756
|
+
/** How we identify ourselves to herdr. The agent label is what herdr shows
|
|
757
|
+
* in its sidebar/agents pane; unknown labels pass through verbatim (herdr
|
|
758
|
+
* normalizes only its built-in agents), so no herdr-side support is needed. */
|
|
759
|
+
const SOURCE = "skydive-cli";
|
|
760
|
+
const AGENT_LABEL = "skydive";
|
|
761
|
+
/** Cap on how long a report may hold a socket open. herdr answers in
|
|
762
|
+
* microseconds when healthy; past this we drop the report on the floor. */
|
|
763
|
+
const REQUEST_TIMEOUT_MS = 500;
|
|
764
|
+
/**
|
|
765
|
+
* The herdr environment, if this process is running inside a herdr pane.
|
|
766
|
+
* All three variables are injected by herdr into every pane it spawns;
|
|
767
|
+
* anything missing means "not in herdr" and reporting stays off.
|
|
768
|
+
*/
|
|
769
|
+
function detectHerdrEnv(env = process.env) {
|
|
770
|
+
if (env.HERDR_ENV !== "1") return null;
|
|
771
|
+
const socketPath = env.HERDR_SOCKET_PATH;
|
|
772
|
+
const paneId = env.HERDR_PANE_ID;
|
|
773
|
+
if (!socketPath || !paneId) return null;
|
|
774
|
+
return {
|
|
775
|
+
socketPath,
|
|
776
|
+
paneId
|
|
777
|
+
};
|
|
778
|
+
}
|
|
779
|
+
function buildStateReport({ paneId, state, message, seq, conversationId }) {
|
|
780
|
+
return {
|
|
781
|
+
id: requestId(),
|
|
782
|
+
method: "pane.report_agent",
|
|
783
|
+
params: {
|
|
784
|
+
pane_id: paneId,
|
|
785
|
+
source: SOURCE,
|
|
786
|
+
agent: AGENT_LABEL,
|
|
787
|
+
state,
|
|
788
|
+
...message ? { message } : {},
|
|
789
|
+
seq,
|
|
790
|
+
...conversationId ? { agent_session_id: conversationId } : {}
|
|
791
|
+
}
|
|
792
|
+
};
|
|
793
|
+
}
|
|
794
|
+
function buildSessionReport({ paneId, seq, conversationId }) {
|
|
795
|
+
return {
|
|
796
|
+
id: requestId(),
|
|
797
|
+
method: "pane.report_agent_session",
|
|
798
|
+
params: {
|
|
799
|
+
pane_id: paneId,
|
|
800
|
+
source: SOURCE,
|
|
801
|
+
agent: AGENT_LABEL,
|
|
802
|
+
seq,
|
|
803
|
+
agent_session_id: conversationId
|
|
804
|
+
}
|
|
805
|
+
};
|
|
806
|
+
}
|
|
807
|
+
function buildRelease({ paneId, seq }) {
|
|
808
|
+
return {
|
|
809
|
+
id: requestId(),
|
|
810
|
+
method: "pane.release_agent",
|
|
811
|
+
params: {
|
|
812
|
+
pane_id: paneId,
|
|
813
|
+
source: SOURCE,
|
|
814
|
+
agent: AGENT_LABEL,
|
|
815
|
+
seq
|
|
816
|
+
}
|
|
817
|
+
};
|
|
818
|
+
}
|
|
819
|
+
let requestCounter = 0;
|
|
820
|
+
function requestId() {
|
|
821
|
+
requestCounter += 1;
|
|
822
|
+
return `${SOURCE}:${Date.now()}:${requestCounter}`;
|
|
823
|
+
}
|
|
824
|
+
const socketSend = (socketPath, request) => {
|
|
825
|
+
try {
|
|
826
|
+
const socket = createConnection(socketPath);
|
|
827
|
+
socket.unref();
|
|
828
|
+
let done = false;
|
|
829
|
+
const finish = () => {
|
|
830
|
+
if (done) return;
|
|
831
|
+
done = true;
|
|
832
|
+
clearTimeout(timeout);
|
|
833
|
+
socket.destroy();
|
|
834
|
+
};
|
|
835
|
+
socket.on("error", finish);
|
|
836
|
+
socket.on("data", finish);
|
|
837
|
+
socket.on("end", finish);
|
|
838
|
+
socket.on("connect", () => {
|
|
839
|
+
socket.write(`${JSON.stringify(request)}\n`);
|
|
840
|
+
});
|
|
841
|
+
const timeout = setTimeout(finish, REQUEST_TIMEOUT_MS);
|
|
842
|
+
timeout.unref?.();
|
|
843
|
+
} catch (_error) {}
|
|
844
|
+
};
|
|
845
|
+
/**
|
|
846
|
+
* The reporter, or null when not running inside herdr (the common case —
|
|
847
|
+
* callers hold `HerdrReporter | null` and optional-chain every call).
|
|
848
|
+
*/
|
|
849
|
+
function createHerdrReporter({ env, send = socketSend } = { env: detectHerdrEnv() }) {
|
|
850
|
+
if (!env) return null;
|
|
851
|
+
const { socketPath, paneId } = env;
|
|
852
|
+
let seq = Date.now() * 1e3;
|
|
853
|
+
const nextSeq = () => {
|
|
854
|
+
seq += 1;
|
|
855
|
+
return seq;
|
|
856
|
+
};
|
|
857
|
+
let lastState;
|
|
858
|
+
let lastMessage;
|
|
859
|
+
let conversationId = null;
|
|
860
|
+
let disposed = false;
|
|
861
|
+
return {
|
|
862
|
+
report(state, message) {
|
|
863
|
+
if (disposed || state === lastState && message === lastMessage) return;
|
|
864
|
+
lastState = state;
|
|
865
|
+
lastMessage = message;
|
|
866
|
+
send(socketPath, buildStateReport({
|
|
867
|
+
paneId,
|
|
868
|
+
state,
|
|
869
|
+
message,
|
|
870
|
+
seq: nextSeq(),
|
|
871
|
+
conversationId
|
|
872
|
+
}));
|
|
873
|
+
},
|
|
874
|
+
setConversation(id) {
|
|
875
|
+
if (disposed || id === conversationId) return;
|
|
876
|
+
conversationId = id;
|
|
877
|
+
if (!id) return;
|
|
878
|
+
send(socketPath, buildSessionReport({
|
|
879
|
+
paneId,
|
|
880
|
+
seq: nextSeq(),
|
|
881
|
+
conversationId: id
|
|
882
|
+
}));
|
|
883
|
+
},
|
|
884
|
+
dispose() {
|
|
885
|
+
if (disposed) return;
|
|
886
|
+
disposed = true;
|
|
887
|
+
send(socketPath, buildRelease({
|
|
888
|
+
paneId,
|
|
889
|
+
seq: nextSeq()
|
|
890
|
+
}));
|
|
891
|
+
}
|
|
892
|
+
};
|
|
893
|
+
}
|
|
894
|
+
|
|
895
|
+
//#endregion
|
|
896
|
+
//#region src/chat/agent-host/create.ts
|
|
897
|
+
/**
|
|
898
|
+
* The sole integration assembly point. Adding a host protocol means adding an
|
|
899
|
+
* adapter and registering it here; chat lifecycle and generic host code stay
|
|
900
|
+
* unchanged.
|
|
901
|
+
*/
|
|
902
|
+
function createAgentHost({ renderer, notifications }) {
|
|
903
|
+
const adapters = [createTerminalNotificationsAdapter({
|
|
904
|
+
renderer,
|
|
905
|
+
enabled: notifications
|
|
906
|
+
})];
|
|
907
|
+
const herdr = createHerdrReporter();
|
|
908
|
+
if (herdr) adapters.push(createHerdrAdapter(herdr));
|
|
909
|
+
return composeAgentHost(adapters);
|
|
910
|
+
}
|
|
911
|
+
|
|
710
912
|
//#endregion
|
|
711
913
|
//#region src/chat/clipboard.ts
|
|
712
914
|
/** Spawns a command with no stdin and collects its stdout. Resolves (never
|
|
@@ -3409,6 +3611,36 @@ function reconcileMaskedInput(previousValue, displayed) {
|
|
|
3409
3611
|
return previousValue.slice(0, kept) + displayed.slice(kept);
|
|
3410
3612
|
}
|
|
3411
3613
|
|
|
3614
|
+
//#endregion
|
|
3615
|
+
//#region src/chat/notification-preview.ts
|
|
3616
|
+
const MAX_NOTIFICATION_PREVIEW_CHARS = 240;
|
|
3617
|
+
/**
|
|
3618
|
+
* Collects assistant `text-delta` chunks for one run and turns them into a
|
|
3619
|
+
* desktop-notification-sized preview. Reasoning, tool output, cards, errors,
|
|
3620
|
+
* and old transcript items are intentionally excluded.
|
|
3621
|
+
*/
|
|
3622
|
+
function createResponsePreview() {
|
|
3623
|
+
let text = "";
|
|
3624
|
+
let lastPartId;
|
|
3625
|
+
return {
|
|
3626
|
+
addChunk(chunk) {
|
|
3627
|
+
if (chunk.type !== "text-delta") return;
|
|
3628
|
+
const delta = typeof chunk.delta === "string" ? chunk.delta : typeof chunk.text === "string" ? chunk.text : "";
|
|
3629
|
+
const partId = typeof chunk.id === "string" ? chunk.id : void 0;
|
|
3630
|
+
if (text && partId && lastPartId && partId !== lastPartId) text += " ";
|
|
3631
|
+
text += delta;
|
|
3632
|
+
lastPartId = partId ?? lastPartId;
|
|
3633
|
+
},
|
|
3634
|
+
get() {
|
|
3635
|
+
const normalized = text.replace(/\s+/g, " ").trim();
|
|
3636
|
+
if (!normalized) return void 0;
|
|
3637
|
+
const characters = Array.from(normalized);
|
|
3638
|
+
if (characters.length <= MAX_NOTIFICATION_PREVIEW_CHARS) return normalized;
|
|
3639
|
+
return `${characters.slice(0, MAX_NOTIFICATION_PREVIEW_CHARS - 1).join("")}…`;
|
|
3640
|
+
}
|
|
3641
|
+
};
|
|
3642
|
+
}
|
|
3643
|
+
|
|
3412
3644
|
//#endregion
|
|
3413
3645
|
//#region src/chat/tui/spinner-frames.ts
|
|
3414
3646
|
/** Braille dot-cycle frames — the classic smooth terminal spinner. */
|
|
@@ -4486,6 +4718,7 @@ function ChatScreen({ agent, conversation }) {
|
|
|
4486
4718
|
const grantPrompt = portal.prompt && portal.prompt.agentId === agent.id ? portal.prompt : null;
|
|
4487
4719
|
const isShared = portal.status !== "off";
|
|
4488
4720
|
const initialConversationId = isNewConversation(conversation) ? null : conversation.id;
|
|
4721
|
+
const agentHost = useAgentHost();
|
|
4489
4722
|
const [conversationId, setConversationId] = useState(initialConversationId);
|
|
4490
4723
|
const [items, setItems] = useState([]);
|
|
4491
4724
|
const [historyLoaded, setHistoryLoaded] = useState(initialConversationId === null);
|
|
@@ -4509,6 +4742,17 @@ function ChatScreen({ agent, conversation }) {
|
|
|
4509
4742
|
inputRef.current = input;
|
|
4510
4743
|
const credPromptRef = useRef(credPrompt);
|
|
4511
4744
|
credPromptRef.current = credPrompt;
|
|
4745
|
+
const hostState = grantPrompt || credPrompt ? "blocked" : run.kind === "idle" ? "idle" : "working";
|
|
4746
|
+
useEffect(() => {
|
|
4747
|
+
agentHost.transition({ state: hostState });
|
|
4748
|
+
}, [agentHost, hostState]);
|
|
4749
|
+
useEffect(() => () => {
|
|
4750
|
+
agentHost.transition({ state: "idle" });
|
|
4751
|
+
agentHost.setSession(null);
|
|
4752
|
+
}, [agentHost]);
|
|
4753
|
+
useEffect(() => {
|
|
4754
|
+
agentHost.setSession(conversationId);
|
|
4755
|
+
}, [agentHost, conversationId]);
|
|
4512
4756
|
const scrollRef = useRef(null);
|
|
4513
4757
|
const composerRef = useRef(null);
|
|
4514
4758
|
const composerBoxHeight = composerRows + 2;
|
|
@@ -4563,6 +4807,7 @@ function ChatScreen({ agent, conversation }) {
|
|
|
4563
4807
|
const attachToRun = useCallback((runId) => {
|
|
4564
4808
|
if (!rest) return;
|
|
4565
4809
|
const abort = new AbortController();
|
|
4810
|
+
const responsePreview = createResponsePreview();
|
|
4566
4811
|
setRun({
|
|
4567
4812
|
kind: "streaming",
|
|
4568
4813
|
runId,
|
|
@@ -4573,6 +4818,7 @@ function ChatScreen({ agent, conversation }) {
|
|
|
4573
4818
|
signal: abort.signal,
|
|
4574
4819
|
onEvent: (event) => {
|
|
4575
4820
|
if (event.kind === "chunk") {
|
|
4821
|
+
responsePreview.addChunk(event.chunk);
|
|
4576
4822
|
setItems((prev) => applyChunk(prev, event.chunk));
|
|
4577
4823
|
return;
|
|
4578
4824
|
}
|
|
@@ -4588,7 +4834,14 @@ function ChatScreen({ agent, conversation }) {
|
|
|
4588
4834
|
text: m.text
|
|
4589
4835
|
} : m));
|
|
4590
4836
|
setRun({ kind: "idle" });
|
|
4591
|
-
|
|
4837
|
+
agentHost.transition({
|
|
4838
|
+
state: "idle",
|
|
4839
|
+
notification: {
|
|
4840
|
+
event: "run-finished",
|
|
4841
|
+
agentName: agent.name,
|
|
4842
|
+
message: responsePreview.get()
|
|
4843
|
+
}
|
|
4844
|
+
});
|
|
4592
4845
|
}
|
|
4593
4846
|
}).catch((err) => {
|
|
4594
4847
|
if (abort.signal.aborted) return;
|
|
@@ -4599,7 +4852,11 @@ function ChatScreen({ agent, conversation }) {
|
|
|
4599
4852
|
}]);
|
|
4600
4853
|
setRun({ kind: "idle" });
|
|
4601
4854
|
});
|
|
4602
|
-
}, [
|
|
4855
|
+
}, [
|
|
4856
|
+
rest,
|
|
4857
|
+
agent.name,
|
|
4858
|
+
agentHost
|
|
4859
|
+
]);
|
|
4603
4860
|
useEffect(() => {
|
|
4604
4861
|
if (!rest || !conversationId) return;
|
|
4605
4862
|
if (initialConversationId !== null) return;
|
|
@@ -5062,7 +5319,13 @@ function ChatScreen({ agent, conversation }) {
|
|
|
5062
5319
|
agentId: agent.id,
|
|
5063
5320
|
agentName: agent.name
|
|
5064
5321
|
});
|
|
5065
|
-
|
|
5322
|
+
agentHost.transition({
|
|
5323
|
+
state: "blocked",
|
|
5324
|
+
notification: {
|
|
5325
|
+
event: "needs-input",
|
|
5326
|
+
agentName: agent.name
|
|
5327
|
+
}
|
|
5328
|
+
});
|
|
5066
5329
|
}, [
|
|
5067
5330
|
portalClient,
|
|
5068
5331
|
portal.status,
|
|
@@ -5070,7 +5333,8 @@ function ChatScreen({ agent, conversation }) {
|
|
|
5070
5333
|
portal.prompt,
|
|
5071
5334
|
agent.id,
|
|
5072
5335
|
agent.name,
|
|
5073
|
-
setPortalPrompt
|
|
5336
|
+
setPortalPrompt,
|
|
5337
|
+
agentHost
|
|
5074
5338
|
]);
|
|
5075
5339
|
useKeyboard((key) => {
|
|
5076
5340
|
if (modelPickerOpen || themePickerOpen || helpOpen) return;
|
|
@@ -5169,6 +5433,7 @@ function ChatScreen({ agent, conversation }) {
|
|
|
5169
5433
|
}
|
|
5170
5434
|
if (ctrlCArmed) {
|
|
5171
5435
|
portalClient?.dispose();
|
|
5436
|
+
agentHost.dispose();
|
|
5172
5437
|
renderer.destroy();
|
|
5173
5438
|
return;
|
|
5174
5439
|
}
|
|
@@ -5515,28 +5780,20 @@ function App({ appUrl, sessionToken, shareMachine, promptHistoryPath, notificati
|
|
|
5515
5780
|
const rest = useStore((s) => s.rest);
|
|
5516
5781
|
const goTo = useStore((s) => s.goTo);
|
|
5517
5782
|
const setClients = useStore((s) => s.setClients);
|
|
5518
|
-
const setAttention = useStore((s) => s.setAttention);
|
|
5519
5783
|
const showToast = useStore((s) => s.showToast);
|
|
5784
|
+
const [agentHost] = useState(() => createAgentHost({
|
|
5785
|
+
renderer,
|
|
5786
|
+
notifications
|
|
5787
|
+
}));
|
|
5520
5788
|
usePortal({
|
|
5521
5789
|
appUrl,
|
|
5522
5790
|
sessionToken,
|
|
5523
5791
|
shareMachine
|
|
5524
5792
|
});
|
|
5525
5793
|
useEffect(() => {
|
|
5526
|
-
|
|
5527
|
-
|
|
5528
|
-
|
|
5529
|
-
});
|
|
5530
|
-
setAttention(attention);
|
|
5531
|
-
return () => {
|
|
5532
|
-
attention.dispose();
|
|
5533
|
-
setAttention(null);
|
|
5534
|
-
};
|
|
5535
|
-
}, [
|
|
5536
|
-
renderer,
|
|
5537
|
-
notifications,
|
|
5538
|
-
setAttention
|
|
5539
|
-
]);
|
|
5794
|
+
agentHost.transition({ state: "idle" });
|
|
5795
|
+
return () => agentHost.dispose();
|
|
5796
|
+
}, [agentHost]);
|
|
5540
5797
|
useEffect(() => {
|
|
5541
5798
|
const selectionCopy = createSelectionCopy({
|
|
5542
5799
|
renderer,
|
|
@@ -5615,37 +5872,40 @@ function App({ appUrl, sessionToken, shareMachine, promptHistoryPath, notificati
|
|
|
5615
5872
|
useKeyboard((key) => {
|
|
5616
5873
|
if (key.name === "c" && key.ctrl && screen.kind !== "chat") {
|
|
5617
5874
|
useStore.getState().portalClient?.dispose();
|
|
5618
|
-
|
|
5875
|
+
agentHost.dispose();
|
|
5619
5876
|
renderer.destroy();
|
|
5620
5877
|
}
|
|
5621
5878
|
});
|
|
5622
|
-
return /* @__PURE__ */
|
|
5623
|
-
|
|
5624
|
-
|
|
5625
|
-
|
|
5626
|
-
|
|
5627
|
-
|
|
5628
|
-
|
|
5629
|
-
|
|
5630
|
-
|
|
5631
|
-
|
|
5632
|
-
|
|
5633
|
-
|
|
5634
|
-
|
|
5635
|
-
|
|
5636
|
-
|
|
5637
|
-
|
|
5638
|
-
|
|
5639
|
-
|
|
5640
|
-
|
|
5641
|
-
|
|
5642
|
-
|
|
5643
|
-
agent: screen.agent,
|
|
5644
|
-
|
|
5645
|
-
|
|
5646
|
-
|
|
5647
|
-
|
|
5648
|
-
|
|
5879
|
+
return /* @__PURE__ */ jsx(AgentHostContext.Provider, {
|
|
5880
|
+
value: agentHost,
|
|
5881
|
+
children: /* @__PURE__ */ jsxs("box", {
|
|
5882
|
+
style: {
|
|
5883
|
+
flexDirection: "column",
|
|
5884
|
+
flexGrow: 1,
|
|
5885
|
+
backgroundColor: theme.background
|
|
5886
|
+
},
|
|
5887
|
+
children: [
|
|
5888
|
+
/* @__PURE__ */ jsx(StatusBar, {}),
|
|
5889
|
+
/* @__PURE__ */ jsx(ToastView, {}),
|
|
5890
|
+
/* @__PURE__ */ jsxs("box", {
|
|
5891
|
+
style: {
|
|
5892
|
+
flexGrow: 1,
|
|
5893
|
+
padding: 1
|
|
5894
|
+
},
|
|
5895
|
+
children: [
|
|
5896
|
+
screen.kind === "splash" && /* @__PURE__ */ jsx(Splash, {}),
|
|
5897
|
+
screen.kind === "error" && /* @__PURE__ */ jsx(ErrorScreen, { message: screen.message }),
|
|
5898
|
+
screen.kind === "agent-picker" && rest && /* @__PURE__ */ jsx(AgentPickerScreen, {}),
|
|
5899
|
+
screen.kind === "agent-create" && rest && /* @__PURE__ */ jsx(AgentCreateScreen, {}),
|
|
5900
|
+
screen.kind === "conversation-picker" && rest && /* @__PURE__ */ jsx(ConversationPickerScreen, { agent: screen.agent }),
|
|
5901
|
+
screen.kind === "chat" && rest && /* @__PURE__ */ jsx(ChatScreen, {
|
|
5902
|
+
agent: screen.agent,
|
|
5903
|
+
conversation: screen.conversation
|
|
5904
|
+
})
|
|
5905
|
+
]
|
|
5906
|
+
})
|
|
5907
|
+
]
|
|
5908
|
+
})
|
|
5649
5909
|
});
|
|
5650
5910
|
}
|
|
5651
5911
|
function Splash() {
|