Skip to content
Source
Sign inSign up

useForceStopThread.ts

59 lines2.4 KB

1import { useAtomValue } from "@effect/atom-react";
2import type { EnvironmentId, RunId, ThreadId } from "@t3tools/contracts";
3import { useState } from "react";
4​
5import { useServerConfigs } from "../../state/entities";
6import { orchestrationEnvironment } from "../../state/orchestration";
7import {
8 isAtomCommandInterrupted,
9 squashAtomCommandFailure,
10} from "@t3tools/client-runtime/state/runtime";
11import { useAtomCommand } from "../../state/use-atom-command";
12import { toastManager } from "../ui/toast";
13​
14/** Force stop for an agent that no longer answers Stop; shared by every place that offers it. */
15export function useForceStopThread(environmentId: EnvironmentId) {
16 const forceStop = useAtomCommand(orchestrationEnvironment.forceStopThread);
17 const permitted = useAtomValue(
18 orchestrationEnvironment.forceStopThread.permissionAtom(environmentId),
19 );
20 const supported =
21 useServerConfigs().get(environmentId)?.environment.capabilities.threadForceStop === true;
22 const canForceStop = permitted && supported;
23 const [stoppingThreadId, setStoppingThreadId] = useState<ThreadId | null>(null);
24 /** Pass the run that ignored Stop, so a Force stop left open cannot hit a newer run. */
25 const forceStopThread = async (threadId: ThreadId, runId?: RunId) => {
26 if (!canForceStop || stoppingThreadId !== null) return;
27 setStoppingThreadId(threadId);
28 const result = await forceStop({
29 environmentId,
30 input: runId === undefined ? { threadId } : { threadId, runId },
31 });
32 setStoppingThreadId(null);
33 if (result._tag === "Failure") {
34 if (isAtomCommandInterrupted(result)) return;
35 const error = squashAtomCommandFailure(result);
36 toastManager.add({
37 type: "error",
38 title: "Could not force stop the agent",
39 description: error instanceof Error ? error.message : undefined,
40 });
41 return;
42 }
43 const others = result.value.sharedWithThreadIds.length;
44 if (result.value.outcome === "releasing") {
45 toastManager.add({
46 type: "info",
47 title: "Turn stopped; the agent is still shutting down",
48 });
49 }
50 if (result.value.outcome === "shared") {
51 toastManager.add({
52 type: "info",
53 title: "Turn stopped; the agent process kept running",
54 description: `It is shared with ${others === 0 ? "other" : others} working ${others === 1 ? "thread" : "threads"}. Stop those to free it.`,
55 });
56 }
57 };
58 return { canForceStop, stoppingThreadId, forceStopThread };