Skip to content

Commit 79da01e

Browse files
committed
Update sessionStore.ts
1 parent b1d1e70 commit 79da01e

1 file changed

Lines changed: 70 additions & 51 deletions

File tree

apps/twig/src/renderer/features/sessions/stores/sessionStore.ts

Lines changed: 70 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,9 @@ const subscriptions = new Map<
157157
* Called synchronously after session is created, before any prompts are sent.
158158
*/
159159
function subscribeToChannel(taskRunId: string) {
160-
if (subscriptions.has(taskRunId)) return;
160+
if (subscriptions.has(taskRunId)) {
161+
return;
162+
}
161163

162164
const eventSubscription = trpcVanilla.agent.onSessionEvent.subscribe(
163165
{ sessionId: taskRunId },
@@ -909,66 +911,78 @@ const useStore = create<SessionStore>()(
909911
} = task;
910912
const isCloud = latestRun?.environment === "cloud";
911913

912-
// Prevent duplicate connections
913-
if (connectAttempts.has(taskId)) return;
914-
if (getSessionByTaskId(taskId)?.status === "connected") return;
915-
916-
// Check auth first
917-
const auth = getAuthCredentials();
918-
if (!auth) {
919-
log.error("Missing auth credentials");
920-
const taskRunId = latestRun?.id ?? `error-${taskId}`;
921-
const session = createBaseSession(taskRunId, taskId, isCloud);
922-
session.status = "error";
923-
session.errorMessage =
924-
"Authentication required. Please sign in to continue.";
925-
addSession(session);
914+
// Prevent duplicate connections - CHECK AND ADD ATOMICALLY
915+
if (connectAttempts.has(taskId)) {
916+
return;
917+
}
918+
const existingSession = getSessionByTaskId(taskId);
919+
if (existingSession?.status === "connected") {
920+
return;
921+
}
922+
if (existingSession?.status === "connecting") {
926923
return;
927924
}
928925

929-
// For non-cloud sessions, check workspace existence (local filesystem check)
930-
// This should happen before the offline check so users see workspace errors
931-
if (!isCloud && latestRun?.id && latestRun?.log_url) {
932-
const workspaceResult = await trpcVanilla.workspace.verify.query({
933-
taskId,
934-
});
926+
// ADD TO SET IMMEDIATELY after checks - before any async work
927+
// This prevents the race condition where two calls both pass the check
928+
connectAttempts.add(taskId);
929+
930+
try {
931+
// Check auth first
932+
const auth = getAuthCredentials();
933+
if (!auth) {
934+
log.error("Missing auth credentials");
935+
const taskRunId = latestRun?.id ?? `error-${taskId}`;
936+
const session = createBaseSession(taskRunId, taskId, isCloud);
937+
session.status = "error";
938+
session.errorMessage =
939+
"Authentication required. Please sign in to continue.";
940+
addSession(session);
941+
return;
942+
}
935943

936-
if (!workspaceResult.exists) {
937-
log.warn("Workspace no longer exists, showing error state", {
944+
// For non-cloud sessions, check workspace existence (local filesystem check)
945+
// This should happen before the offline check so users see workspace errors
946+
if (!isCloud && latestRun?.id && latestRun?.log_url) {
947+
const workspaceResult = await trpcVanilla.workspace.verify.query({
938948
taskId,
939-
missingPath: workspaceResult.missingPath,
940949
});
941-
const { rawEntries } = await fetchSessionLogs(latestRun.log_url);
942-
const events = convertStoredEntriesToEvents(rawEntries);
943950

944-
const session = createBaseSession(latestRun.id, taskId, false);
945-
session.events = events;
946-
session.logUrl = latestRun.log_url;
947-
session.status = "error";
948-
session.errorMessage = workspaceResult.missingPath
949-
? `Working directory no longer exists: ${workspaceResult.missingPath}`
950-
: "The working directory for this task no longer exists. Please start a new task.";
951+
if (!workspaceResult.exists) {
952+
log.warn("Workspace no longer exists, showing error state", {
953+
taskId,
954+
missingPath: workspaceResult.missingPath,
955+
});
956+
const { rawEntries } = await fetchSessionLogs(
957+
latestRun.log_url,
958+
);
959+
const events = convertStoredEntriesToEvents(rawEntries);
960+
961+
const session = createBaseSession(latestRun.id, taskId, false);
962+
session.events = events;
963+
session.logUrl = latestRun.log_url;
964+
session.status = "error";
965+
session.errorMessage = workspaceResult.missingPath
966+
? `Working directory no longer exists: ${workspaceResult.missingPath}`
967+
: "The working directory for this task no longer exists. Please start a new task.";
968+
969+
addSession(session);
970+
return;
971+
}
972+
}
951973

974+
// Don't try to connect if offline (agent connection requires internet)
975+
if (!getIsOnline()) {
976+
log.info("Skipping connection attempt - offline", { taskId });
977+
const taskRunId = latestRun?.id ?? `offline-${taskId}`;
978+
const session = createBaseSession(taskRunId, taskId, isCloud);
979+
session.status = "disconnected";
980+
session.errorMessage =
981+
"No internet connection. Connect when you're back online.";
952982
addSession(session);
953983
return;
954984
}
955-
}
956-
957-
// Don't try to connect if offline (agent connection requires internet)
958-
if (!getIsOnline()) {
959-
log.info("Skipping connection attempt - offline", { taskId });
960-
const taskRunId = latestRun?.id ?? `offline-${taskId}`;
961-
const session = createBaseSession(taskRunId, taskId, isCloud);
962-
session.status = "disconnected";
963-
session.errorMessage =
964-
"No internet connection. Connect when you're back online.";
965-
addSession(session);
966-
return;
967-
}
968-
969-
connectAttempts.add(taskId);
970985

971-
try {
972986
if (isCloud && latestRun?.id && latestRun?.log_url) {
973987
await connectToCloudSession(
974988
taskId,
@@ -1025,7 +1039,9 @@ const useStore = create<SessionStore>()(
10251039

10261040
disconnectFromTask: async (taskId) => {
10271041
const session = getSessionByTaskId(taskId);
1028-
if (!session) return;
1042+
if (!session) {
1043+
return;
1044+
}
10291045

10301046
if (session.isCloud) {
10311047
stopCloudPolling(session.taskRunId);
@@ -1035,7 +1051,10 @@ const useStore = create<SessionStore>()(
10351051
sessionId: session.taskRunId,
10361052
});
10371053
} catch (error) {
1038-
log.error("Failed to cancel session", error);
1054+
log.error("Failed to cancel agent session", {
1055+
taskRunId: session.taskRunId,
1056+
error,
1057+
});
10391058
}
10401059
unsubscribeFromChannel(session.taskRunId);
10411060
}

0 commit comments

Comments
 (0)