1import { describe, expect, it } from "@effect/vitest";
2
3import * as Effect from "effect/Effect";
4import * as EffectAcpErrors from "effect-acp/errors";
5
6import { applyGrokAcpModelSelection, grokAcpSpawnArgs } from "./acpSupport.ts";
7
8describe("grokAcpSpawnArgs", () => {
9 it("inherits the Grok CLI config when no T3 runtime mode is set", () => {
10 expect(grokAcpSpawnArgs()).toEqual(["agent", "stdio"]);
11 });
12
13 it("forces Grok to ask when T3 is Supervised", () => {
14 expect(grokAcpSpawnArgs("approval-required")).toEqual([
15 "--permission-mode",
16 "default",
17 "agent",
18 "stdio",
19 ]);
20 });
21});
22
23describe("applyGrokAcpModelSelection", () => {
24 const makeRecordingRuntime = (failure?: EffectAcpErrors.AcpError) => {
25 const modelCalls: Array<{
26 modelId: string;
27 meta?: { readonly [key: string]: unknown } | null;
28 }> = [];
29 const runtime = {
30 setSessionModel: (modelId: string, meta?: { readonly [key: string]: unknown } | null) =>
31 Effect.gen(function* () {
32 modelCalls.push(meta === undefined ? { modelId } : { modelId, meta });
33 if (failure) return yield* failure;
34 return {};
35 }),
36 };
37 return { runtime, modelCalls };
38 };
39
40 it.effect("calls session/set_model when the requested model differs from current", () =>
41 Effect.gen(function* () {
42 const { runtime, modelCalls } = makeRecordingRuntime();
43 const result = yield* applyGrokAcpModelSelection({
44 runtime,
45 currentModelId: "grok-build",
46 requestedModelId: "grok-mock-alt",
47 mapError: (cause) => cause.message,
48 });
49 expect(modelCalls).toEqual([{ modelId: "grok-mock-alt" }]);
50 expect(result).toBe("grok-mock-alt");
51 }),
52 );
53
54 it.effect("applies reasoning effort through session/set_model metadata", () =>
55 Effect.gen(function* () {
56 const { runtime, modelCalls } = makeRecordingRuntime();
57 const result = yield* applyGrokAcpModelSelection({
58 runtime,
59 currentModelId: "grok-4.6",
60 currentReasoningEffort: "high",
61 requestedModelId: "grok-4.6",
62 requestedReasoningEffort: "xhigh",
63 mapError: (cause) => cause.message,
64 });
65 expect(modelCalls).toEqual([{ modelId: "grok-4.6", meta: { reasoningEffort: "xhigh" } }]);
66 expect(result).toBe("grok-4.6");
67 }),
68 );
69
70 it.effect("drops malformed effort metadata instead of sending it", () =>
71 Effect.gen(function* () {
72 const { runtime, modelCalls } = makeRecordingRuntime();
73 yield* applyGrokAcpModelSelection({
74 runtime,
75 currentModelId: "grok-4.6",
76 currentReasoningEffort: "high",
77 requestedModelId: "grok-4.6",
78 requestedReasoningEffort: "not a token",
79 mapError: (cause) => cause.message,
80 });
81 expect(modelCalls).toEqual([{ modelId: "grok-4.6" }]);
82 }),
83 );
84
85 it.effect("skips set_model when requested matches current", () =>
86 Effect.gen(function* () {
87 const { runtime, modelCalls } = makeRecordingRuntime();
88 const result = yield* applyGrokAcpModelSelection({
89 runtime,
90 currentModelId: "grok-build",
91 requestedModelId: "grok-build",
92 mapError: (cause) => cause.message,
93 });
94 expect(modelCalls).toEqual([]);
95 expect(result).toBe("grok-build");
96 }),
97 );
98
99 it.effect("keeps the session's current model when the product slug is requested", () =>
100 Effect.gen(function* () {
101 const { runtime, modelCalls } = makeRecordingRuntime();
102 const result = yield* applyGrokAcpModelSelection({
103 runtime,
104 currentModelId: "grok-4.6",
105 requestedModelId: "grok-build",
106 mapError: (cause) => cause.message,
107 });
108 expect(modelCalls).toEqual([]);
109 expect(result).toBe("grok-4.6");
110 }),
111 );
112
113 it.effect("applies reasoning to the current model when the product slug is requested", () =>
114 Effect.gen(function* () {
115 const { runtime, modelCalls } = makeRecordingRuntime();
116 const result = yield* applyGrokAcpModelSelection({
117 runtime,
118 currentModelId: "grok-4.6",
119 currentReasoningEffort: "high",
120 requestedModelId: "grok-build",
121 requestedReasoningEffort: "xhigh",
122 mapError: (cause) => cause.message,
123 });
124 expect(modelCalls).toEqual([{ modelId: "grok-4.6", meta: { reasoningEffort: "xhigh" } }]);
125 expect(result).toBe("grok-4.6");
126 }),
127 );
128});