| 1 | /** |
| 2 | * Optional integration check against a real `grok agent stdio` install. |
| 3 | * Enable with: T3_GROK_ACP_PROBE=1 vp test run GrokAcpCliProbe |
| 4 | * Set T3_GROK_LIVE_TURN=1 to also send a small prompt to the real model. |
| 5 | * |
| 6 | * The probe assumes either `XAI_API_KEY` is set in the environment or |
| 7 | * the user has previously run `grok login`. Without credentials the |
| 8 | * agent's `authenticate` request will fail and the test will surface |
| 9 | * the error. |
| 10 | */ |
| 11 | import * as NodeServices from "@effect/platform-node/NodeServices"; |
| 12 | import { it } from "@effect/vitest"; |
| 13 | import * as Effect from "effect/Effect"; |
| 14 | import * as Deferred from "effect/Deferred"; |
| 15 | import * as Fiber from "effect/Fiber"; |
| 16 | import * as FileSystem from "effect/FileSystem"; |
| 17 | import * as Stream from "effect/Stream"; |
| 18 | import { describe, expect } from "vite-plus/test"; |
| 19 | |
| 20 | import { makeGrokAcpRuntime } from "./acpSupport.ts"; |
| 21 | |
| 22 | const makeProbeRuntime = makeGrokAcpRuntime({ |
| 23 | grokSettings: { binaryPath: "grok" }, |
| 24 | environment: process.env, |
| 25 | cwd: process.cwd(), |
| 26 | clientInfo: { name: "t3-grok-probe", version: "0.0.0" }, |
| 27 | }); |
| 28 | |
| 29 | describe.runIf(process.env.T3_GROK_ACP_PROBE === "1")("Grok ACP CLI probe", () => { |
| 30 | it.effect("initialize and authenticate against real grok agent stdio", () => |
| 31 | Effect.gen(function* () { |
| 32 | const runtime = yield* makeProbeRuntime; |
| 33 | const started = yield* runtime.start(); |
| 34 | expect(started.initializeResult).toBeDefined(); |
| 35 | }).pipe(Effect.scoped, Effect.provide(NodeServices.layer)), |
| 36 | ); |
| 37 | |
| 38 | it.effect("completes a prompt on the agent's default model", () => |
| 39 | Effect.gen(function* () { |
| 40 | const runtime = yield* makeProbeRuntime; |
| 41 | const started = yield* runtime.start(); |
| 42 | expect(typeof started.sessionId).toBe("string"); |
| 43 | |
| 44 | const result = yield* runtime |
| 45 | .prompt({ prompt: [{ type: "text", text: "Respond with exactly: grok switch ok" }] }) |
| 46 | .pipe(Effect.timeout("60 seconds")); |
| 47 | expect(result.stopReason).toBe("end_turn"); |
| 48 | }).pipe(Effect.scoped, Effect.provide(NodeServices.layer)), |
| 49 | ); |
| 50 | it.effect("session/set_model accepts advertised reasoning effort metadata", () => |
| 51 | Effect.gen(function* () { |
| 52 | const runtime = yield* makeProbeRuntime; |
| 53 | const started = yield* runtime.start(); |
| 54 | const modelState = started.sessionSetupResult.models; |
| 55 | const currentModelId = modelState?.currentModelId.trim(); |
| 56 | expect(currentModelId).toBeDefined(); |
| 57 | if (!currentModelId) return; |
| 58 | |
| 59 | const currentModel = modelState?.availableModels.find( |
| 60 | (model) => model.modelId.trim() === currentModelId, |
| 61 | ); |
| 62 | const reasoningEffort = currentModel?._meta?.reasoningEffort; |
| 63 | expect(typeof reasoningEffort).toBe("string"); |
| 64 | if (typeof reasoningEffort !== "string") return; |
| 65 | |
| 66 | yield* runtime.setSessionModel(currentModelId, { reasoningEffort }); |
| 67 | }).pipe(Effect.scoped, Effect.provide(NodeServices.layer)), |
| 68 | ); |
| 69 | |
| 70 | it.effect.skipIf(process.env.T3_GROK_LIVE_TURN !== "1")( |
| 71 | "finishes a real Grok turn and streams its answer", |
| 72 | () => |
| 73 | Effect.gen(function* () { |
| 74 | const fileSystem = yield* FileSystem.FileSystem; |
| 75 | const cwd = yield* fileSystem.makeTempDirectoryScoped(); |
| 76 | const runtime = yield* makeGrokAcpRuntime({ |
| 77 | grokSettings: { binaryPath: "grok" }, |
| 78 | environment: process.env, |
| 79 | cwd, |
| 80 | runtimeMode: "approval-required", |
| 81 | clientInfo: { name: "t3-grok-probe", version: "0.0.0" }, |
| 82 | }); |
| 83 | yield* runtime.start(); |
| 84 | const chunks: string[] = []; |
| 85 | const events = yield* Stream.runForEach(runtime.getEvents(), (event) => { |
| 86 | if (event._tag === "EventStreamBarrier") { |
| 87 | return Deferred.succeed(event.acknowledge, undefined); |
| 88 | } |
| 89 | if (event._tag === "ContentDelta") { |
| 90 | chunks.push(event.text); |
| 91 | } |
| 92 | return Effect.void; |
| 93 | }).pipe(Effect.forkChild); |
| 94 | const result = yield* runtime.prompt({ |
| 95 | prompt: [{ type: "text", text: "Reply exactly GROK_T3_OK. Do not use any tools." }], |
| 96 | }); |
| 97 | yield* runtime.drainEvents; |
| 98 | expect(result.stopReason).toBe("end_turn"); |
| 99 | expect(chunks.join("")).toContain("GROK_T3_OK"); |
| 100 | yield* Fiber.interrupt(events); |
| 101 | }).pipe(Effect.scoped, Effect.provide(NodeServices.layer)), |
| 102 | ); |
| 103 | }); |