Skip to content
Source
Sign inSign up

resume-thread.ts

83 lines2.9 KB

1import type {
2 ResumeThreadQueueInput,
3 SetThreadInteractionModeInput,
4 SetThreadRuntimeModeInput,
5 StartThreadTurnInput,
6} from "@t3tools/client-runtime/operations";
7import type { AtomCommandResult } from "@t3tools/client-runtime/state/runtime";
8import type {
9 EnvironmentId,
10 MessageId,
11 ModelSelection,
12 ProviderInteractionMode,
13 RunId,
14 RuntimeMode,
15 ThreadId,
16} from "@t3tools/contracts";
17​
18type Command<Input, E> = (request: {
19 readonly environmentId: EnvironmentId;
20 readonly input: Input;
21}) => Promise<AtomCommandResult<unknown, E>>;
22​
23/** Resolves to the first failed command's result, or the last successful one. */
24export async function resumeThread<E>(input: {
25 readonly thread: {
26 readonly environmentId: EnvironmentId;
27 readonly id: ThreadId;
28 readonly runtimeMode: RuntimeMode;
29 readonly interactionMode: ProviderInteractionMode;
30 };
31 readonly resumableRunId: RunId | null;
32 readonly queueHeld: boolean;
33 readonly runtimeMode: RuntimeMode;
34 readonly interactionMode: ProviderInteractionMode;
35 readonly modelSelection: ModelSelection | null;
36 readonly messageId: MessageId;
37 readonly createdAt: string;
38 readonly setRuntimeMode: Command<SetThreadRuntimeModeInput, E>;
39 readonly setInteractionMode: Command<SetThreadInteractionModeInput, E>;
40 readonly startTurn: Command<StartThreadTurnInput, E>;
41 readonly resumeQueue: Command<ResumeThreadQueueInput, E>;
42}): Promise<AtomCommandResult<unknown, E>> {
43 const { thread, runtimeMode, interactionMode, createdAt } = input;
44 const environmentId = thread.environmentId;
45 // The server holds the queue behind a stopped or usage-limited run until that run is continued.
46 if (input.resumableRunId !== null) {
47 // A turn on an existing thread runs with the thread's saved modes, not the turn's.
48 if (runtimeMode !== thread.runtimeMode) {
49 const saved = await input.setRuntimeMode({
50 environmentId,
51 input: { threadId: thread.id, runtimeMode, createdAt },
52 });
53 if (saved._tag === "Failure") return saved;
54 }
55 if (interactionMode !== thread.interactionMode) {
56 const saved = await input.setInteractionMode({
57 environmentId,
58 input: { threadId: thread.id, interactionMode, createdAt },
59 });
60 if (saved._tag === "Failure") return saved;
61 }
62 const continued = await input.startTurn({
63 environmentId,
64 input: {
65 creationSource: "mobile",
66 threadId: thread.id,
67 manualContinuationOfRunId: input.resumableRunId,
68 ...(input.modelSelection ? { modelSelection: input.modelSelection } : {}),
69 message: {
70 messageId: input.messageId,
71 role: "user",
72 text: "Continue where you left off.",
73 attachments: [],
74 },
75 runtimeMode,
76 interactionMode,
77 dispatchMode: "start",
78 },
79 });
80 if (continued._tag === "Failure" || !input.queueHeld) return continued;
81 }
82 return input.resumeQueue({ environmentId, input: { threadId: thread.id } });