@robota-sdk/agent-ui-web 3.2.1 → 3.3.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/CHANGELOG.md +18 -0
- package/dist/index.cjs +80 -37
- package/dist/index.d.cts +4 -2
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.ts +4 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +80 -37
- package/dist/index.js.map +1 -1
- package/docs/SPEC.md +5 -0
- package/package.json +6 -6
- package/src/components/AgentActivityPanel.tsx +38 -31
- package/src/components/Composer.tsx +13 -10
- package/src/components/SessionSurface.tsx +65 -38
- package/src/hooks/server-message-handling.ts +2 -0
- package/src/hooks/session-client-types.ts +7 -1
- package/src/hooks/use-app-view-requests.ts +8 -1
- package/src/hooks/use-session-directory.ts +7 -2
- package/src/hooks/useSessionClient.ts +37 -6
package/dist/index.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { isObserverMessageType } from "@robota-sdk/agent-transport";
|
|
1
2
|
import React, { createContext, createElement, forwardRef, useCallback, useContext, useEffect, useId, useImperativeHandle, useLayoutEffect, useMemo, useRef, useState } from "react";
|
|
2
3
|
import { decodeFrame, decodeServerMessage } from "@robota-sdk/agent-transport/client";
|
|
3
4
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
@@ -306,6 +307,7 @@ const SERVER_MESSAGE_HANDLING = {
|
|
|
306
307
|
background_task_control_result: "visible-notice",
|
|
307
308
|
protocol_error: "visible-notice",
|
|
308
309
|
resume_gap: "transport-control",
|
|
310
|
+
surface_role: "reducer-state",
|
|
309
311
|
settings: "reducer-state",
|
|
310
312
|
settings_error: "reducer-state"
|
|
311
313
|
};
|
|
@@ -400,6 +402,7 @@ function nextRequestId$6(prefix) {
|
|
|
400
402
|
return `${prefix}_${requestCounter$6}_${Date.now()}`;
|
|
401
403
|
}
|
|
402
404
|
const CONNECTION_CLOSED = "The connection to the session closed.";
|
|
405
|
+
const READ_ONLY = "This session is read-only.";
|
|
403
406
|
/**
|
|
404
407
|
* The key a finished call's app view is read and called by, taken from the tool row's `appView`
|
|
405
408
|
* reference; `undefined` when the row gives none. Everything outside this module treats it as an
|
|
@@ -431,7 +434,7 @@ function callAppToolMessage(requestId, viewKey, name, args) {
|
|
|
431
434
|
* keeps its own entry. A reply that lost its connection never arrives: the owner of the connection
|
|
432
435
|
* rejects every outstanding request when it drops, is replaced or goes away (`rejectPendingAppRequests`).
|
|
433
436
|
*/
|
|
434
|
-
function useAppViewRequests(send, isConnected) {
|
|
437
|
+
function useAppViewRequests(send, isConnected, isObserving) {
|
|
435
438
|
const pendingRef = useRef(/* @__PURE__ */ new Map());
|
|
436
439
|
const [requestOwner] = useState(() => nextRequestId$6("app_request"));
|
|
437
440
|
const rejectPendingAppRequests = useCallback((reason = CONNECTION_CLOSED) => {
|
|
@@ -447,6 +450,10 @@ function useAppViewRequests(send, isConnected) {
|
|
|
447
450
|
reject(/* @__PURE__ */ new Error(signal?.aborted ? "The app view closed." : CONNECTION_CLOSED));
|
|
448
451
|
return;
|
|
449
452
|
}
|
|
453
|
+
if (isObserving()) {
|
|
454
|
+
reject(/* @__PURE__ */ new Error(READ_ONLY));
|
|
455
|
+
return;
|
|
456
|
+
}
|
|
450
457
|
const requestId = nextRequestId$6(`${requestOwner}_${prefix}`);
|
|
451
458
|
const dispose = () => signal?.removeEventListener("abort", abort);
|
|
452
459
|
const abort = () => {
|
|
@@ -465,6 +472,7 @@ function useAppViewRequests(send, isConnected) {
|
|
|
465
472
|
}
|
|
466
473
|
}), [
|
|
467
474
|
isConnected,
|
|
475
|
+
isObserving,
|
|
468
476
|
requestOwner,
|
|
469
477
|
send
|
|
470
478
|
]);
|
|
@@ -1017,7 +1025,7 @@ function initialSidebarOpen() {
|
|
|
1017
1025
|
* on its primary one. After a reconnect to such a host this surface goes back to the session it was
|
|
1018
1026
|
* on; an older host has one session for everyone, so there is nothing to go back to.
|
|
1019
1027
|
*/
|
|
1020
|
-
function useSessionDirectoryState(send) {
|
|
1028
|
+
function useSessionDirectoryState(send, isObserving) {
|
|
1021
1029
|
const { storage: { browserNamespace } } = useProductIdentity();
|
|
1022
1030
|
const [sessionListing, setSessionListing] = useState(null);
|
|
1023
1031
|
const [sessionsError, setSessionsError] = useState(null);
|
|
@@ -1068,6 +1076,7 @@ function useSessionDirectoryState(send) {
|
|
|
1068
1076
|
if (target === null) return;
|
|
1069
1077
|
clearStoredRestoreId(browserNamespace);
|
|
1070
1078
|
if (target === listing.currentSessionId) return;
|
|
1079
|
+
if (isObserving()) return;
|
|
1071
1080
|
if (!keepsSessionsLive(listing)) return;
|
|
1072
1081
|
if (!listing.sessions.some((row) => row.id === target)) return;
|
|
1073
1082
|
send({
|
|
@@ -1075,7 +1084,11 @@ function useSessionDirectoryState(send) {
|
|
|
1075
1084
|
sessionId: target,
|
|
1076
1085
|
requestId: nextRequestId$1("session_change")
|
|
1077
1086
|
});
|
|
1078
|
-
}, [
|
|
1087
|
+
}, [
|
|
1088
|
+
send,
|
|
1089
|
+
browserNamespace,
|
|
1090
|
+
isObserving
|
|
1091
|
+
]);
|
|
1079
1092
|
return {
|
|
1080
1093
|
sessionListing,
|
|
1081
1094
|
sessionsError,
|
|
@@ -1370,6 +1383,9 @@ function buildConversationEntriesFromDisplaySegments(displaySegments) {
|
|
|
1370
1383
|
function useSessionClient(makeClient) {
|
|
1371
1384
|
const [status, setStatus] = useState("disconnected");
|
|
1372
1385
|
const statusRef = useRef("disconnected");
|
|
1386
|
+
const [role, setRole] = useState(null);
|
|
1387
|
+
const roleRef = useRef(null);
|
|
1388
|
+
const isObserving = useCallback(() => roleRef.current === "observe", []);
|
|
1373
1389
|
const [messages, setMessages] = useState([]);
|
|
1374
1390
|
const [activeTools, setActiveTools] = useState([]);
|
|
1375
1391
|
const [streamingText, setStreamingText] = useState("");
|
|
@@ -1437,8 +1453,9 @@ function useSessionClient(makeClient) {
|
|
|
1437
1453
|
const [executionDetailInput, setExecutionDetailInput] = useState();
|
|
1438
1454
|
const executionDetailInputRef = useRef(null);
|
|
1439
1455
|
const send = useCallback((msg) => {
|
|
1456
|
+
const refused = isObserving() && !isObserverMessageType(msg.type);
|
|
1440
1457
|
if (msg.type === "send-background-task") {
|
|
1441
|
-
if (executionDetailInputRef.current !== null) return;
|
|
1458
|
+
if (refused || executionDetailInputRef.current !== null) return;
|
|
1442
1459
|
executionDetailInputRef.current = msg.taskId;
|
|
1443
1460
|
setExecutionDetailInput({
|
|
1444
1461
|
taskId: msg.taskId,
|
|
@@ -1461,14 +1478,16 @@ function useSessionClient(makeClient) {
|
|
|
1461
1478
|
});
|
|
1462
1479
|
return;
|
|
1463
1480
|
}
|
|
1481
|
+
if (refused) return;
|
|
1464
1482
|
commandsInFlightRef.current += 1;
|
|
1465
1483
|
}
|
|
1484
|
+
if (refused) return;
|
|
1466
1485
|
if (msg.type === "switch-session" || msg.type === "new-session") {
|
|
1467
1486
|
sessionChangesInFlightRef.current += 1;
|
|
1468
1487
|
if (msg.requestId !== void 0) sessionChangeRequestIdsRef.current.add(msg.requestId);
|
|
1469
1488
|
}
|
|
1470
1489
|
clientRef.current?.send(msg);
|
|
1471
|
-
}, [appendEntry]);
|
|
1490
|
+
}, [appendEntry, isObserving]);
|
|
1472
1491
|
/** One session change this surface asked for has been answered. */
|
|
1473
1492
|
const settleSessionChange = useCallback((requestId) => {
|
|
1474
1493
|
sessionChangesInFlightRef.current = Math.max(0, sessionChangesInFlightRef.current - 1);
|
|
@@ -1504,8 +1523,8 @@ function useSessionClient(makeClient) {
|
|
|
1504
1523
|
const { handleExecutionDetailMessage, handleExecutionWorkspace, closeExecutionDetail, ...executionDetailState } = useExecutionDetailState(send);
|
|
1505
1524
|
const { handleModelListMessage, ...modelListState } = useModelListState(send);
|
|
1506
1525
|
const { handleProjectMessage, ...projectPanelState } = useProjectPanelState(send);
|
|
1507
|
-
const { handleAppViewMessage, rejectPendingAppRequests, readAppView, callAppTool } = useAppViewRequests(send, useCallback(() => statusRef.current === "connected", []));
|
|
1508
|
-
const { handleSessionsMessage, canListSessions, markCurrent, armRestore, ...sessionDirectoryState } = useSessionDirectoryState(send);
|
|
1526
|
+
const { handleAppViewMessage, rejectPendingAppRequests, readAppView, callAppTool } = useAppViewRequests(send, useCallback(() => statusRef.current === "connected", []), isObserving);
|
|
1527
|
+
const { handleSessionsMessage, canListSessions, markCurrent, armRestore, ...sessionDirectoryState } = useSessionDirectoryState(send, isObserving);
|
|
1509
1528
|
const { requestSessions, setSessionSidebarOpen } = sessionDirectoryState;
|
|
1510
1529
|
const { handleSettingsMessage, openSettings, refreshSettings, ...settingsState } = useSettingsState(send);
|
|
1511
1530
|
const settingsOpenRef = useRef(false);
|
|
@@ -1527,6 +1546,10 @@ function useSessionClient(makeClient) {
|
|
|
1527
1546
|
if (handleAgentDefinitionsMessage(msg)) return;
|
|
1528
1547
|
if (handleSchedulesMessage(msg)) return;
|
|
1529
1548
|
switch (msg.type) {
|
|
1549
|
+
case "surface_role":
|
|
1550
|
+
roleRef.current = msg.role;
|
|
1551
|
+
setRole(msg.role);
|
|
1552
|
+
break;
|
|
1530
1553
|
case "messages": {
|
|
1531
1554
|
const reconstructed = msg.display ? buildConversationEntriesFromDisplaySegments(msg.display) : msg.messages.flatMap((m) => {
|
|
1532
1555
|
if (m.role !== "user" && m.role !== "assistant") return [];
|
|
@@ -1898,6 +1921,10 @@ function useSessionClient(makeClient) {
|
|
|
1898
1921
|
const onStatusChange = (next) => {
|
|
1899
1922
|
statusRef.current = next;
|
|
1900
1923
|
setStatus(next);
|
|
1924
|
+
if (next !== "connected") {
|
|
1925
|
+
roleRef.current = null;
|
|
1926
|
+
setRole(null);
|
|
1927
|
+
}
|
|
1901
1928
|
if (next !== "connected") {
|
|
1902
1929
|
rejectPendingAppRequests();
|
|
1903
1930
|
clearCompactionNotices();
|
|
@@ -1916,6 +1943,7 @@ function useSessionClient(makeClient) {
|
|
|
1916
1943
|
sessionChangesInFlightRef.current = 0;
|
|
1917
1944
|
sessionChangeRequestIdsRef.current.clear();
|
|
1918
1945
|
pendingIntentRef.current = null;
|
|
1946
|
+
client.send({ type: "get-surface-role" });
|
|
1919
1947
|
client.send({ type: "get-commands" });
|
|
1920
1948
|
client.send({ type: "get-status" });
|
|
1921
1949
|
client.send({ type: "get-pending" });
|
|
@@ -1924,10 +1952,18 @@ function useSessionClient(makeClient) {
|
|
|
1924
1952
|
requestSchedules();
|
|
1925
1953
|
}
|
|
1926
1954
|
};
|
|
1927
|
-
const
|
|
1955
|
+
const inner = makeClient({
|
|
1928
1956
|
onMessage: handleMessage,
|
|
1929
1957
|
onStatusChange
|
|
1930
1958
|
});
|
|
1959
|
+
const client = {
|
|
1960
|
+
connect: () => inner.connect(),
|
|
1961
|
+
disconnect: () => inner.disconnect(),
|
|
1962
|
+
send: (msg) => {
|
|
1963
|
+
if (roleRef.current === "observe" && !isObserverMessageType(msg.type)) return;
|
|
1964
|
+
inner.send(msg);
|
|
1965
|
+
}
|
|
1966
|
+
};
|
|
1931
1967
|
clientRef.current = client;
|
|
1932
1968
|
client.connect();
|
|
1933
1969
|
return () => {
|
|
@@ -1956,6 +1992,7 @@ function useSessionClient(makeClient) {
|
|
|
1956
1992
|
commandCatalog,
|
|
1957
1993
|
sessionStatus,
|
|
1958
1994
|
ownDriverId,
|
|
1995
|
+
role,
|
|
1959
1996
|
send,
|
|
1960
1997
|
sendCommandSilently,
|
|
1961
1998
|
pendingPrompts,
|
|
@@ -3569,7 +3606,7 @@ function AgentActivityPanel({ tasks, schedules = [], goal = null, onPauseSchedul
|
|
|
3569
3606
|
task,
|
|
3570
3607
|
onPause: onPauseSchedule,
|
|
3571
3608
|
onResume: onResumeSchedule,
|
|
3572
|
-
onRequestDelete: () => setPendingDeleteId(task.id)
|
|
3609
|
+
onRequestDelete: onDeleteSchedule ? () => setPendingDeleteId(task.id) : void 0
|
|
3573
3610
|
}, task.id))
|
|
3574
3611
|
})] }),
|
|
3575
3612
|
goal && /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("p", {
|
|
@@ -3670,33 +3707,33 @@ function ScheduleCard({ task, onPause, onResume, onRequestDelete }) {
|
|
|
3670
3707
|
describeScheduleStatus(task)
|
|
3671
3708
|
]
|
|
3672
3709
|
}),
|
|
3673
|
-
/* @__PURE__ */ jsxs("div", {
|
|
3710
|
+
onResume || onPause || onRequestDelete ? /* @__PURE__ */ jsxs("div", {
|
|
3674
3711
|
className: "mt-2 flex items-center gap-3",
|
|
3675
|
-
children: [isPaused ? /* @__PURE__ */ jsxs("button", {
|
|
3712
|
+
children: [isPaused ? onResume && /* @__PURE__ */ jsxs("button", {
|
|
3676
3713
|
type: "button",
|
|
3677
|
-
onClick: () => onResume
|
|
3714
|
+
onClick: () => onResume(task.id),
|
|
3678
3715
|
className: "flex items-center gap-1.5 rounded-lg px-2 py-1 text-[13px] text-muted-foreground hover:bg-hover hover:text-foreground",
|
|
3679
3716
|
children: [/* @__PURE__ */ jsx(Play, {
|
|
3680
3717
|
size: 11,
|
|
3681
3718
|
fill: "currentColor",
|
|
3682
3719
|
"aria-hidden": "true"
|
|
3683
3720
|
}), "Resume"]
|
|
3684
|
-
}) : /* @__PURE__ */ jsxs("button", {
|
|
3721
|
+
}) : onPause && /* @__PURE__ */ jsxs("button", {
|
|
3685
3722
|
type: "button",
|
|
3686
|
-
onClick: () => onPause
|
|
3723
|
+
onClick: () => onPause(task.id),
|
|
3687
3724
|
className: "flex items-center gap-1.5 rounded-lg px-2 py-1 text-[13px] text-muted-foreground hover:bg-hover hover:text-foreground",
|
|
3688
3725
|
children: [/* @__PURE__ */ jsx(Pause, {
|
|
3689
3726
|
size: 11,
|
|
3690
3727
|
fill: "currentColor",
|
|
3691
3728
|
"aria-hidden": "true"
|
|
3692
3729
|
}), "Pause"]
|
|
3693
|
-
}), /* @__PURE__ */ jsx("button", {
|
|
3730
|
+
}), onRequestDelete && /* @__PURE__ */ jsx("button", {
|
|
3694
3731
|
type: "button",
|
|
3695
3732
|
onClick: onRequestDelete,
|
|
3696
3733
|
className: "flex items-center gap-1.5 rounded-lg px-2 py-1 text-[13px] text-destructive hover:bg-destructive/10",
|
|
3697
3734
|
children: "Delete…"
|
|
3698
3735
|
})]
|
|
3699
|
-
})
|
|
3736
|
+
}) : null
|
|
3700
3737
|
]
|
|
3701
3738
|
});
|
|
3702
3739
|
}
|
|
@@ -3720,7 +3757,7 @@ function GoalCard({ goal, onCancel }) {
|
|
|
3720
3757
|
className: "mt-1.5 pl-[26px] text-[13px] text-muted-foreground",
|
|
3721
3758
|
children: describeGoalStatus(goal)
|
|
3722
3759
|
}),
|
|
3723
|
-
goal.status === "active" && /* @__PURE__ */ jsx("div", {
|
|
3760
|
+
goal.status === "active" && onCancel && /* @__PURE__ */ jsx("div", {
|
|
3724
3761
|
className: "mt-2 pl-[26px]",
|
|
3725
3762
|
children: /* @__PURE__ */ jsxs("button", {
|
|
3726
3763
|
type: "button",
|
|
@@ -6516,7 +6553,7 @@ function GoalBar({ status, onStop }) {
|
|
|
6516
6553
|
goal.maxIterations
|
|
6517
6554
|
]
|
|
6518
6555
|
}),
|
|
6519
|
-
/* @__PURE__ */ jsxs("button", {
|
|
6556
|
+
onStop && /* @__PURE__ */ jsxs("button", {
|
|
6520
6557
|
type: "button",
|
|
6521
6558
|
"aria-label": "Stop goal",
|
|
6522
6559
|
onClick: onStop,
|
|
@@ -8421,7 +8458,8 @@ function SetupPanel({ onSetUp, disabled }) {
|
|
|
8421
8458
|
* The full desktop layout over an `IWsSessionState`. `surface` is an optional label shown next to the
|
|
8422
8459
|
* mark (e.g. "app").
|
|
8423
8460
|
*/
|
|
8424
|
-
function SessionSurface({ state, surface, personalUsageEnabled = false, draftMode = "persistent", onReconnect, pickFiles, getPathForFile, onOpenMemoryInEditor, appViewSandboxUrl }) {
|
|
8461
|
+
function SessionSurface({ state, surface, personalUsageEnabled: personalUsageRequested = false, draftMode = "persistent", onReconnect, pickFiles, getPathForFile, onOpenMemoryInEditor, appViewSandboxUrl }) {
|
|
8462
|
+
const readOnly = state.role === "observe";
|
|
8425
8463
|
const [view, setView] = useState("chat");
|
|
8426
8464
|
const { identity } = useProductIdentity();
|
|
8427
8465
|
const appViewHost = useMemo(() => ({
|
|
@@ -8440,6 +8478,7 @@ function SessionSurface({ state, surface, personalUsageEnabled = false, draftMod
|
|
|
8440
8478
|
identity.displayName,
|
|
8441
8479
|
surface
|
|
8442
8480
|
]);
|
|
8481
|
+
const personalUsageEnabled = personalUsageRequested && !readOnly;
|
|
8443
8482
|
const composerRef = useRef(null);
|
|
8444
8483
|
const tasks = state.executionWorkspace?.entries ?? [];
|
|
8445
8484
|
const hasTasks = tasks.some((entry) => entry.kind !== "main_thread");
|
|
@@ -8459,7 +8498,7 @@ function SessionSurface({ state, surface, personalUsageEnabled = false, draftMod
|
|
|
8459
8498
|
const hasWorkInProgress = hasTasks || state.scheduledTasks.length > 0 || currentGoal !== null;
|
|
8460
8499
|
const isEmpty = state.messages.length === 0 && !state.streamingText && !state.isThinking && state.activeTools.length === 0;
|
|
8461
8500
|
const setupRequired = state.sessionStatus?.setupRequired === true;
|
|
8462
|
-
const hasSessionList = (state.sessionListing ?? null) !== null || state.sessionsError?.code === "list_failed";
|
|
8501
|
+
const hasSessionList = !readOnly && ((state.sessionListing ?? null) !== null || state.sessionsError?.code === "list_failed");
|
|
8463
8502
|
const sidebarOpen = hasSessionList && state.sessionSidebarOpen;
|
|
8464
8503
|
const usage = personalUsageEnabled && view === "usage";
|
|
8465
8504
|
const project = view === "project";
|
|
@@ -8529,7 +8568,7 @@ function SessionSurface({ state, surface, personalUsageEnabled = false, draftMod
|
|
|
8529
8568
|
connectionLost: state.connectionLost ?? false
|
|
8530
8569
|
}), usage ? /* @__PURE__ */ jsxs("div", {
|
|
8531
8570
|
className: "min-h-0 flex-1",
|
|
8532
|
-
children: [/* @__PURE__ */ jsx(PersonalUsageDashboard, { state }), /* @__PURE__ */ jsx(PermissionPrompt, {
|
|
8571
|
+
children: [/* @__PURE__ */ jsx(PersonalUsageDashboard, { state }), readOnly ? null : /* @__PURE__ */ jsx(PermissionPrompt, {
|
|
8533
8572
|
layout: "modal",
|
|
8534
8573
|
prompts: state.pendingPrompts,
|
|
8535
8574
|
onAnswerPermission: state.answerPermission,
|
|
@@ -8541,7 +8580,7 @@ function SessionSurface({ state, surface, personalUsageEnabled = false, draftMod
|
|
|
8541
8580
|
children: [/* @__PURE__ */ jsx(ProjectPanel, {
|
|
8542
8581
|
state,
|
|
8543
8582
|
onOpenMemoryInEditor
|
|
8544
|
-
}), /* @__PURE__ */ jsx(PermissionPrompt, {
|
|
8583
|
+
}), readOnly ? null : /* @__PURE__ */ jsx(PermissionPrompt, {
|
|
8545
8584
|
layout: "modal",
|
|
8546
8585
|
prompts: state.pendingPrompts,
|
|
8547
8586
|
onAnswerPermission: state.answerPermission,
|
|
@@ -8561,7 +8600,7 @@ function SessionSurface({ state, surface, personalUsageEnabled = false, draftMod
|
|
|
8561
8600
|
}),
|
|
8562
8601
|
/* @__PURE__ */ jsx("div", {
|
|
8563
8602
|
className: "min-h-0 flex-1 overflow-hidden",
|
|
8564
|
-
children: setupRequired ? /* @__PURE__ */ jsx(SetupPanel, {
|
|
8603
|
+
children: setupRequired && !readOnly ? /* @__PURE__ */ jsx(SetupPanel, {
|
|
8565
8604
|
onSetUp: () => state.send({
|
|
8566
8605
|
type: "command",
|
|
8567
8606
|
name: "provider",
|
|
@@ -8569,7 +8608,7 @@ function SessionSurface({ state, surface, personalUsageEnabled = false, draftMod
|
|
|
8569
8608
|
}),
|
|
8570
8609
|
disabled: state.status !== "connected"
|
|
8571
8610
|
}) : isEmpty ? /* @__PURE__ */ jsx(EmptyState, {}) : /* @__PURE__ */ jsx(AppViewHostContext.Provider, {
|
|
8572
|
-
value: appViewHost,
|
|
8611
|
+
value: readOnly ? null : appViewHost,
|
|
8573
8612
|
children: /* @__PURE__ */ jsx(ConversationView, {
|
|
8574
8613
|
messages: state.messages,
|
|
8575
8614
|
activeTools: state.activeTools,
|
|
@@ -8584,13 +8623,13 @@ function SessionSurface({ state, surface, personalUsageEnabled = false, draftMod
|
|
|
8584
8623
|
children: [
|
|
8585
8624
|
/* @__PURE__ */ jsx(GoalBar, {
|
|
8586
8625
|
status: state.sessionStatus ?? null,
|
|
8587
|
-
onStop: () => state.send({
|
|
8626
|
+
onStop: readOnly ? void 0 : () => state.send({
|
|
8588
8627
|
type: "command",
|
|
8589
8628
|
name: "goal",
|
|
8590
8629
|
args: "cancel"
|
|
8591
8630
|
})
|
|
8592
8631
|
}),
|
|
8593
|
-
/* @__PURE__ */ jsx(PermissionPrompt, {
|
|
8632
|
+
readOnly ? null : /* @__PURE__ */ jsx(PermissionPrompt, {
|
|
8594
8633
|
layout: "dock",
|
|
8595
8634
|
prompts: state.pendingPrompts,
|
|
8596
8635
|
onAnswerPermission: state.answerPermission,
|
|
@@ -8598,7 +8637,11 @@ function SessionSurface({ state, surface, personalUsageEnabled = false, draftMod
|
|
|
8598
8637
|
ownDriverId: state.ownDriverId,
|
|
8599
8638
|
onFocusReturn: () => composerRef.current?.focus()
|
|
8600
8639
|
}),
|
|
8601
|
-
|
|
8640
|
+
readOnly ? /* @__PURE__ */ jsx("p", {
|
|
8641
|
+
role: "status",
|
|
8642
|
+
className: "rounded-2xl bg-card px-4 py-3 text-center text-[14px] text-muted-foreground",
|
|
8643
|
+
children: "Read-only: you are watching this session."
|
|
8644
|
+
}) : setupRequired ? null : /* @__PURE__ */ jsx(Composer, {
|
|
8602
8645
|
ref: composerRef,
|
|
8603
8646
|
draftMode,
|
|
8604
8647
|
catalog: state.commandCatalog ?? null,
|
|
@@ -8653,13 +8696,13 @@ function SessionSurface({ state, surface, personalUsageEnabled = false, draftMod
|
|
|
8653
8696
|
selectedEntryId: state.openEntryId ?? void 0,
|
|
8654
8697
|
onSelect: (entry) => state.openExecutionDetail(entry.id),
|
|
8655
8698
|
onReturnToConversation: () => state.closeExecutionDetail(),
|
|
8656
|
-
onStop: stopExecutionEntry,
|
|
8699
|
+
onStop: readOnly ? void 0 : stopExecutionEntry,
|
|
8657
8700
|
schedules: state.scheduledTasks,
|
|
8658
8701
|
goal: currentGoal,
|
|
8659
|
-
onPauseSchedule: state.pauseSchedule,
|
|
8660
|
-
onResumeSchedule: state.resumeSchedule,
|
|
8661
|
-
onDeleteSchedule: state.deleteSchedule,
|
|
8662
|
-
onCancelGoal: () => state.send({
|
|
8702
|
+
onPauseSchedule: readOnly ? void 0 : state.pauseSchedule,
|
|
8703
|
+
onResumeSchedule: readOnly ? void 0 : state.resumeSchedule,
|
|
8704
|
+
onDeleteSchedule: readOnly ? void 0 : state.deleteSchedule,
|
|
8705
|
+
onCancelGoal: readOnly ? void 0 : () => state.send({
|
|
8663
8706
|
type: "command",
|
|
8664
8707
|
name: "goal",
|
|
8665
8708
|
args: "cancel"
|
|
@@ -8674,18 +8717,18 @@ function SessionSurface({ state, surface, personalUsageEnabled = false, draftMod
|
|
|
8674
8717
|
complete: state.executionDetailComplete,
|
|
8675
8718
|
onClose: () => state.closeExecutionDetail(),
|
|
8676
8719
|
onLoadMore: () => state.loadMoreExecutionDetail(),
|
|
8677
|
-
onStop: openEntry ? () => stopExecutionEntry(openEntry) : void 0,
|
|
8720
|
+
onStop: openEntry && !readOnly ? () => stopExecutionEntry(openEntry) : void 0,
|
|
8678
8721
|
inputState: state.executionDetailInput,
|
|
8679
8722
|
mode: state.executionDetailMode,
|
|
8680
8723
|
unreadable: state.executionDetailUnreadable,
|
|
8681
8724
|
onShowEarlier: state.showEarlierExecutionDetail,
|
|
8682
8725
|
onShowLive: state.showLiveExecutionDetail,
|
|
8683
|
-
onSend: openEntry ? (prompt) => state.send({
|
|
8726
|
+
onSend: openEntry && !readOnly ? (prompt) => state.send({
|
|
8684
8727
|
type: "send-background-task",
|
|
8685
8728
|
taskId: openEntry.sourceId,
|
|
8686
8729
|
input: { prompt }
|
|
8687
8730
|
}) : void 0,
|
|
8688
|
-
onContinue: openEntry?.resumeSessionId ? () => {
|
|
8731
|
+
onContinue: openEntry?.resumeSessionId && !readOnly ? () => {
|
|
8689
8732
|
if (openEntry.resumeSessionId) state.switchSession(openEntry.resumeSessionId);
|
|
8690
8733
|
} : void 0
|
|
8691
8734
|
})
|
|
@@ -8693,8 +8736,8 @@ function SessionSurface({ state, surface, personalUsageEnabled = false, draftMod
|
|
|
8693
8736
|
})]
|
|
8694
8737
|
}),
|
|
8695
8738
|
/* @__PURE__ */ jsx(SessionNotices, { state }),
|
|
8696
|
-
/* @__PURE__ */ jsx(SettingsScreen, { state }),
|
|
8697
|
-
/* @__PURE__ */ jsx(AgentSwitcherSheet, { state }),
|
|
8739
|
+
readOnly ? null : /* @__PURE__ */ jsx(SettingsScreen, { state }),
|
|
8740
|
+
readOnly ? null : /* @__PURE__ */ jsx(AgentSwitcherSheet, { state }),
|
|
8698
8741
|
/* @__PURE__ */ jsx(HelpSheet, {
|
|
8699
8742
|
open: state.helpOpen,
|
|
8700
8743
|
onClose: () => state.closeHelp(),
|