Skip to content
Source
Sign inSign up

resume-thread.test.ts

90 lines3.1 KB

1import { EnvironmentId, MessageId, RunId, ThreadId } from "@t3tools/contracts";
2import * as Cause from "effect/Cause";
3import { AsyncResult } from "effect/reactivity";
4import { describe, expect, it } from "vite-plus/test";
5​
6import { resumeThread } from "./resume-thread";
7​
8const runId = RunId.make("run-limited");
9const failure = AsyncResult.failure(Cause.fail(new Error("not connected")));
10​
11function setup(options: { readonly startTurnFails?: boolean } = {}) {
12 const calls: Array<{ readonly command: string; readonly input: unknown }> = [];
13 const record =
14 (command: string, fails = false) =>
15 async (request: { readonly input: unknown }) => {
16 calls.push({ command, input: request.input });
17 return fails ? failure : AsyncResult.success(undefined);
18 };
19 const base = {
20 thread: {
21 environmentId: EnvironmentId.make("env"),
22 id: ThreadId.make("thread"),
23 runtimeMode: "full-access",
24 interactionMode: "default",
25 },
26 runtimeMode: "full-access",
27 interactionMode: "default",
28 modelSelection: null,
29 messageId: MessageId.make("message"),
30 createdAt: "2026-10-30T00:00:00.000Z",
31 setRuntimeMode: record("setRuntimeMode"),
32 setInteractionMode: record("setInteractionMode"),
33 startTurn: record("startTurn", options.startTurnFails),
34 resumeQueue: record("resumeQueue"),
35 } as const;
36 return { calls, base };
38​
39describe("resumeThread", () => {
40 it("continues the limited run before resuming its held queue", async () => {
41 const { calls, base } = setup();
42 const result = await resumeThread({ ...base, resumableRunId: runId, queueHeld: true });
43​
44 expect(result._tag).toBe("Success");
45 expect(calls.map((call) => call.command)).toEqual(["startTurn", "resumeQueue"]);
46 expect(calls[0]?.input).toMatchObject({
47 manualContinuationOfRunId: runId,
48 dispatchMode: "start",
49 });
50 });
51​
52 it("does not resume the queue when the continuation fails", async () => {
53 const { calls, base } = setup({ startTurnFails: true });
54 const result = await resumeThread({ ...base, resumableRunId: runId, queueHeld: true });
55​
56 expect(result).toBe(failure);
57 expect(calls.map((call) => call.command)).toEqual(["startTurn"]);
58 });
59​
60 it("only continues the run when nothing is queued", async () => {
61 const { calls, base } = setup();
62 await resumeThread({ ...base, resumableRunId: runId, queueHeld: false });
63​
64 expect(calls.map((call) => call.command)).toEqual(["startTurn"]);
65 });
66​
67 it("saves changed modes to the thread before continuing", async () => {
68 const { calls, base } = setup();
69 await resumeThread({
70 ...base,
71 runtimeMode: "approval-required",
72 interactionMode: "plan",
73 resumableRunId: runId,
74 queueHeld: false,
75 });
76​
77 expect(calls.map((call) => call.command)).toEqual([
78 "setRuntimeMode",
79 "setInteractionMode",
80 "startTurn",
81 ]);
82 });
83​
84 it("resumes a held queue directly when no run needs continuing", async () => {
85 const { calls, base } = setup();
86 await resumeThread({ ...base, resumableRunId: null, queueHeld: true });
87​
88 expect(calls.map((call) => call.command)).toEqual(["resumeQueue"]);
89 });
90});