1import {
2 type ModelSelection,
3 OrchestratorMcpFailure,
4 type OrchestratorMcpDelegateTaskInput,
5 type OrchestratorMcpInteractionMode,
6 type OrchestratorMcpRuntimeMode,
7 type ProviderInteractionMode,
8 type RuntimeMode,
9} from "@t3tools/contracts";
10import * as Effect from "effect/Effect";
11
12/** How much a runtime mode allows, narrowest first. */
13export function runtimeModeRank(mode: RuntimeMode): number {
14 switch (mode) {
15 case "approval-required":
16 return 0;
17 case "auto-accept-edits":
18 return 1;
19 case "auto":
20 return 2;
21 case "full-access":
22 return 3;
23 }
24}
25
26/** How much an interaction mode allows: plan, then default. */
27export function interactionModeRank(mode: ProviderInteractionMode): number {
28 return mode === "plan" ? 0 : 1;
29}
30
31/**
32 * The mode a child runs at: the one asked for, never broader than its parent's.
33 * An inherited mode the target provider does not offer steps down to the
34 * broadest one it does; an explicitly requested one is refused instead.
35 */
36export function resolveRuntimeMode(
37 parentMode: RuntimeMode,
38 requested: OrchestratorMcpRuntimeMode | undefined,
39 target?: {
40 readonly modelSelection: ModelSelection;
41 readonly supportedRuntimeModes: ReadonlyArray<RuntimeMode> | undefined;
42 },
43): Effect.Effect<RuntimeMode, OrchestratorMcpFailure> {
44 const inherited = requested === undefined || requested === "inherit";
45 const resolved = inherited ? parentMode : requested;
46 if (runtimeModeRank(resolved) > runtimeModeRank(parentMode)) {
47 return Effect.fail(
48 new OrchestratorMcpFailure({
49 code: "runtime_mode_escalation_denied",
50 message: `Child runtime mode ${resolved} is broader than parent mode ${parentMode}.`,
51 }),
52 );
53 }
54 const supported = target?.supportedRuntimeModes;
55 if (supported === undefined || supported.length === 0 || supported.includes(resolved)) {
56 return Effect.succeed(resolved);
57 }
58 if (!inherited) {
59 return Effect.fail(
60 new OrchestratorMcpFailure({
61 code: "invalid_request",
62 message: `Provider ${target?.modelSelection.instanceId} does not offer runtime mode ${resolved}, so it would run as approval-required. Use one of: ${supported.join(", ")}.`,
63 }),
64 );
65 }
66 return Effect.succeed(
67 supported
68 .filter((mode) => runtimeModeRank(mode) <= runtimeModeRank(resolved))
69 .toSorted((left, right) => runtimeModeRank(right) - runtimeModeRank(left))[0] ??
70 "approval-required",
71 );
72}
73
74/** The same, for interaction modes. */
75export function resolveInteractionMode(
76 parentMode: ProviderInteractionMode,
77 requested: OrchestratorMcpInteractionMode | undefined,
78): Effect.Effect<ProviderInteractionMode, OrchestratorMcpFailure> {
79 const resolved = requested === undefined || requested === "inherit" ? parentMode : requested;
80 return interactionModeRank(resolved) > interactionModeRank(parentMode)
81 ? Effect.fail(
82 new OrchestratorMcpFailure({
83 code: "interaction_mode_escalation_denied",
84 message: `Child interaction mode ${resolved} is broader than parent mode ${parentMode}.`,
85 }),
86 )
87 : Effect.succeed(resolved);
88}
89
90/** The task as its child receives it, with the role the caller asked for. */
91export function taskPrompt(input: OrchestratorMcpDelegateTaskInput): string {
92 return input.role === undefined || input.role === "general"
93 ? input.task
94 : `Act as the ${input.role} sub-agent for this task.\n\n${input.task}`;
95}