1import type { ProviderInteractionMode, RuntimeMode, ThreadId } from "@t3tools/contracts";
2import * as Context from "effect/Context";
3import type * as Ref from "effect/Ref";
4
5export interface DispatchModes {
6 readonly runtimeMode: RuntimeMode;
7 readonly interactionMode: ProviderInteractionMode;
8}
9
10/** A thread the orchestrator refused to touch because it ran above the limit. */
11export interface DispatchModeRefusal extends DispatchModes {
12 readonly threadId: ThreadId;
13 readonly mode: "runtime" | "interaction";
14}
15
16/**
17 * The broadest modes a command may touch, for commands an MCP caller sends.
18 * A caller checks its target's modes before dispatching, but the target's
19 * user can raise them meanwhile; the orchestrator re-checks this limit inside
20 * the thread's command lock, where nothing else can change them. Unset for
21 * the user's own commands, which have no limit.
22 *
23 * The orchestrator also records its refusal in `refused`, so the sender can
24 * report it however the code in between wrapped the dispatch error.
25 */
26export interface DispatchModeLimitValue extends DispatchModes {
27 readonly refused?: Ref.Ref<DispatchModeRefusal | undefined>;
28}
29
30export const DispatchModeLimit = Context.Reference<DispatchModeLimitValue | undefined>(
31 "t3/orchestration-v2/DispatchModeLimit",
32 { defaultValue: () => undefined },
33);
34
35const runtimeModeRank: Record<RuntimeMode, number> = {
36 "approval-required": 0,
37 "auto-accept-edits": 1,
38 auto: 2,
39 "full-access": 3,
40};
41const interactionModeRank: Record<ProviderInteractionMode, number> = { plan: 0, default: 1 };
42
43/** Which of `modes` is broader than `limit`, if either. */
44export const exceededDispatchModeLimit = (
45 limit: DispatchModes,
46 modes: DispatchModes,
47): "runtime" | "interaction" | undefined =>
48 runtimeModeRank[modes.runtimeMode] > runtimeModeRank[limit.runtimeMode]
49 ? "runtime"
50 : interactionModeRank[modes.interactionMode] > interactionModeRank[limit.interactionMode]
51 ? "interaction"
52 : undefined;