1200 lines · 43.6 KB · TypeScript
RawDownload
// @effect-diagnostics nodeBuiltinImport:offimport * as NodePath from "node:path";import * as NodeOS from "node:os";import * as NodeFSP from "node:fs/promises";import * as NodeURL from "node:url"; import * as NodeServices from "@effect/platform-node/NodeServices";import { assert, it } from "@effect/vitest";import * as Deferred from "effect/Deferred";import * as Effect from "effect/Effect";import * as Fiber from "effect/Fiber";import * as Layer from "effect/Layer";import * as Ref from "effect/Ref";import * as Schema from "effect/Schema";import * as Stream from "effect/Stream";import * as TestClock from "effect/testing/TestClock"; import {  ApprovalRequestId,  GrokSettings,  ProviderDriverKind,  ProviderInstanceId,  ThreadId,  TurnId,  type ProviderRuntimeEvent,} from "@t3tools/contracts"; import { ServerConfig } from "../../config.ts";import { grokPromptSettlementBelongsToContext, makeGrokAdapter } from "./GrokAdapter.ts";const decodeGrokSettings = Schema.decodeSync(GrokSettings); const __dirname = NodePath.dirname(NodeURL.fileURLToPath(import.meta.url));const mockAgentPath = NodePath.join(__dirname, "../../../scripts/acp-mock-agent.ts");const mockAgentCommand = process.execPath; async function makeMockGrokWrapper(extraEnv?: Record<string, string>) {  const dir = await NodeFSP.mkdtemp(NodePath.join(NodeOS.tmpdir(), "grok-acp-mock-"));  const wrapperPath = NodePath.join(dir, "fake-grok.sh");  const envExports = Object.entries(extraEnv ?? {})    .map(([key, value]) => `export ${key}=${JSON.stringify(value)}`)    .join("\n");  const script = `#!/bin/sh${envExports}exec ${JSON.stringify(mockAgentCommand)} ${JSON.stringify(mockAgentPath)} "$@"`;  await NodeFSP.writeFile(wrapperPath, script, "utf8");  await NodeFSP.chmod(wrapperPath, 0o755);  return wrapperPath;} function waitForFileContent(  filePath: string,  attempts = 40,  expectedContent?: string,): Effect.Effect<string> {  const readAttempt = (remainingAttempts: number): Effect.Effect<string> =>    Effect.gen(function* () {      if (remainingAttempts <= 0) {        return yield* Effect.die(new Error(`Timed out waiting for file content at ${filePath}`));      }      const raw = yield* Effect.tryPromise(() => NodeFSP.readFile(filePath, "utf8")).pipe(        Effect.orElseSucceed(() => ""),      );      if (        raw.trim().length > 0 &&        (expectedContent === undefined || raw.includes(expectedContent))      ) {        return raw;      }      yield* Effect.sleep("25 millis");      return yield* readAttempt(remainingAttempts - 1);    });  return readAttempt(attempts);} async function readJsonLines(filePath: string) {  const raw = await NodeFSP.readFile(filePath, "utf8");  return raw    .split("\n")    .map((line) => line.trim())    .filter((line) => line.length > 0)    .map((line) => JSON.parse(line) as Record<string, unknown>);} const grokAdapterTestLayer = ServerConfig.layerTest(process.cwd(), {  prefix: "t3code-grok-adapter-test-",}).pipe(Layer.provideMerge(NodeServices.layer)); const makeTestAdapter = (binaryPath: string, options?: Parameters<typeof makeGrokAdapter>[1]) =>  makeGrokAdapter(decodeGrokSettings({ binaryPath }), options).pipe(Effect.orDie); it("requires a settlement to match the live Grok turn", () => {  const staleTurnId = TurnId.make("stale-turn");  const replacementTurnId = TurnId.make("replacement-turn");   assert.isFalse(    grokPromptSettlementBelongsToContext({      liveAcpSessionId: "session-1",      expectedAcpSessionId: "session-1",      liveActiveTurnId: replacementTurnId,      liveSessionActiveTurnId: replacementTurnId,      turnId: staleTurnId,    }),  );  assert.isFalse(    grokPromptSettlementBelongsToContext({      liveAcpSessionId: "replacement-session",      expectedAcpSessionId: "stale-session",      liveActiveTurnId: staleTurnId,      liveSessionActiveTurnId: staleTurnId,      turnId: staleTurnId,    }),  );  assert.isTrue(    grokPromptSettlementBelongsToContext({      liveAcpSessionId: "session-1",      expectedAcpSessionId: "session-1",      liveActiveTurnId: staleTurnId,      liveSessionActiveTurnId: staleTurnId,      turnId: staleTurnId,    }),  );}); it.layer(grokAdapterTestLayer)("GrokAdapterLive", (it) => {  it.effect("starts a session and maps mock ACP prompt flow to runtime events", () =>    Effect.gen(function* () {      const threadId = ThreadId.make("grok-mock-thread");      const wrapperPath = yield* Effect.promise(() => makeMockGrokWrapper());      const adapter = yield* makeTestAdapter(wrapperPath);       const runtimeEvents: ProviderRuntimeEvent[] = [];      const turnCompleted = yield* Deferred.make<void>();      const runtimeEventsFiber = yield* Stream.runForEach(adapter.streamEvents, (event) =>        Effect.sync(() => {          runtimeEvents.push(event);        }).pipe(          Effect.andThen(            event.type === "turn.completed"              ? Deferred.succeed(turnCompleted, undefined)              : Effect.void,          ),        ),      ).pipe(Effect.forkChild);       const session = yield* adapter.startSession({        threadId,        provider: ProviderDriverKind.make("grok"),        cwd: process.cwd(),        runtimeMode: "full-access",        modelSelection: { instanceId: ProviderInstanceId.make("grok"), model: "grok-mock-alt" },      });       assert.equal(session.provider, "grok");      assert.equal(session.model, "grok-mock-alt");      assert.deepStrictEqual(session.resumeCursor, {        schemaVersion: 1,        sessionId: "mock-session-1",      });       yield* adapter.sendTurn({        threadId,        input: "hello grok",        attachments: [],      });       yield* Deferred.await(turnCompleted);      yield* Fiber.interrupt(runtimeEventsFiber);      const types = runtimeEvents.map((e) => e.type);       assert.includeMembers(types, [        "session.started",        "session.state.changed",        "thread.started",        "turn.started",        "item.started",        "content.delta",        "turn.completed",      ] as const);       const delta = runtimeEvents.find((e) => e.type === "content.delta");      assert.isDefined(delta);      if (delta?.type === "content.delta") {        assert.equal(delta.payload.delta, "hello from mock");      }       yield* adapter.stopSession(threadId);    }),  );   it.effect("closes the ACP child process when a session stops", () =>    Effect.gen(function* () {      const threadId = ThreadId.make("grok-stop-session-close");      const tempDir = yield* Effect.promise(() =>        NodeFSP.mkdtemp(NodePath.join(NodeOS.tmpdir(), "grok-adapter-exit-log-")),      );      const exitLogPath = NodePath.join(tempDir, "exit.log");       const wrapperPath = yield* Effect.promise(() =>        makeMockGrokWrapper({          T3_ACP_EXIT_LOG_PATH: exitLogPath,        }),      );      const adapter = yield* makeTestAdapter(wrapperPath);       yield* adapter.startSession({        threadId,        provider: ProviderDriverKind.make("grok"),        cwd: process.cwd(),        runtimeMode: "full-access",        modelSelection: { instanceId: ProviderInstanceId.make("grok"), model: "grok-build" },      });       yield* adapter.stopSession(threadId);       const exitLog = yield* waitForFileContent(exitLogPath);      assert.include(exitLog, "SIGTERM");    }),  );   it.effect("reports a Grok session running only while the prompt is in flight", () =>    Effect.gen(function* () {      const threadId = ThreadId.make("grok-session-ready-after-prompt");      const wrapperPath = yield* Effect.promise(() =>        makeMockGrokWrapper({          T3_ACP_EMIT_TOOL_CALLS: "1",        }),      );      const adapter = yield* makeTestAdapter(wrapperPath);      const requestOpened =        yield* Deferred.make<Extract<ProviderRuntimeEvent, { type: "request.opened" }>>();      const eventsFiber = yield* Stream.runForEach(adapter.streamEvents, (event) =>        event.type === "request.opened"          ? Deferred.succeed(requestOpened, event).pipe(Effect.ignore)          : Effect.void,      ).pipe(Effect.forkChild);       yield* adapter.startSession({        threadId,        provider: ProviderDriverKind.make("grok"),        cwd: process.cwd(),        runtimeMode: "approval-required",        modelSelection: { instanceId: ProviderInstanceId.make("grok"), model: "grok-build" },      });       const sendTurnFiber = yield* adapter        .sendTurn({ threadId, input: "check lifecycle", attachments: [] })        .pipe(Effect.forkChild);      const requestOpenedEvent = yield* Deferred.await(requestOpened);       const runningSessions = yield* adapter.listSessions();      const runningSession = runningSessions.find((session) => session.threadId === threadId);      assert.equal(runningSession?.status, "running");      assert.isDefined(runningSession?.activeTurnId);       yield* adapter.respondToRequest(        threadId,        ApprovalRequestId.make(String(requestOpenedEvent.requestId)),        "accept",      );      yield* Fiber.join(sendTurnFiber);       const readySessions = yield* adapter.listSessions();      const readySession = readySessions.find((session) => session.threadId === threadId);      assert.equal(readySession?.status, "ready");      assert.isUndefined(readySession?.activeTurnId);       yield* Fiber.interrupt(eventsFiber);      yield* adapter.stopSession(threadId);    }),  );   it.effect("restores ready without completing an unstarted turn when preparation fails", () =>    Effect.gen(function* () {      const threadId = ThreadId.make("grok-preparation-failure-while-connecting");      const wrapperPath = yield* Effect.promise(() => makeMockGrokWrapper());      const adapter = yield* makeTestAdapter(wrapperPath);       const runtimeEvents: ProviderRuntimeEvent[] = [];      const runtimeEventsFiber = yield* Stream.runForEach(adapter.streamEvents, (event) =>        Effect.sync(() => {          runtimeEvents.push(event);        }),      ).pipe(Effect.forkChild);       yield* adapter.startSession({        threadId,        provider: ProviderDriverKind.make("grok"),        cwd: process.cwd(),        runtimeMode: "full-access",        modelSelection: { instanceId: ProviderInstanceId.make("grok"), model: "grok-build" },      });       const error = yield* Effect.flip(        adapter.sendTurn({          threadId,          input: "prepare invalid attachment",          attachments: [            {              type: "image",              id: "missing-image",              name: "missing.png",              mimeType: "image/png",              sizeBytes: 1,            },          ],        }),      );      for (let yieldAttempt = 0; yieldAttempt < 4; yieldAttempt += 1) {        yield* Effect.yieldNow;      }       const turnCompletedEvent = runtimeEvents.find(        (event): event is Extract<ProviderRuntimeEvent, { type: "turn.completed" }> =>          event.type === "turn.completed",      );      const readySessions = yield* adapter.listSessions();      const readySession = readySessions.find((session) => session.threadId === threadId);       assert.equal(error._tag, "ProviderAdapterRequestError");      assert.isUndefined(turnCompletedEvent);      assert.equal(readySession?.status, "ready");      assert.isUndefined(readySession?.activeTurnId);       yield* Fiber.interrupt(runtimeEventsFiber);      yield* adapter.stopSession(threadId);    }),  );   it.effect("completes a Grok turn from xAI prompt completion when the prompt RPC hangs", () =>    Effect.gen(function* () {      const threadId = ThreadId.make("grok-xai-prompt-complete-fallback");      const wrapperPath = yield* Effect.promise(() =>        makeMockGrokWrapper({          T3_ACP_EMIT_XAI_PROMPT_COMPLETE_THEN_HANG: "1",          T3_ACP_EMIT_FOREIGN_SESSION_UPDATES: "1",        }),      );      const adapter = yield* makeTestAdapter(wrapperPath);       const runtimeEvents: ProviderRuntimeEvent[] = [];      const turnCompleted = yield* Deferred.make<void>();      const runtimeEventsFiber = yield* Stream.runForEach(adapter.streamEvents, (event) =>        Effect.sync(() => {          runtimeEvents.push(event);        }).pipe(          Effect.andThen(            event.type === "turn.completed"              ? Deferred.succeed(turnCompleted, undefined)              : Effect.void,          ),        ),      ).pipe(Effect.forkChild);       yield* adapter.startSession({        threadId,        provider: ProviderDriverKind.make("grok"),        cwd: process.cwd(),        runtimeMode: "full-access",        modelSelection: { instanceId: ProviderInstanceId.make("grok"), model: "grok-build" },      });       const sendTurnResult = yield* adapter.sendTurn({        threadId,        input: "exercise fallback",        attachments: [],      });       yield* Deferred.await(turnCompleted);      for (let yieldAttempt = 0; yieldAttempt < 8; yieldAttempt += 1) {        yield* Effect.yieldNow;      }      const readySessions = yield* adapter.listSessions();      const readySession = readySessions.find((session) => session.threadId === threadId);      const turnCompletedEvent = runtimeEvents.find(        (event): event is Extract<ProviderRuntimeEvent, { type: "turn.completed" }> =>          event.type === "turn.completed",      );      const eventTypes = runtimeEvents.map((event) => event.type);      const content = runtimeEvents        .filter(          (event): event is Extract<ProviderRuntimeEvent, { type: "content.delta" }> =>            event.type === "content.delta" && String(event.threadId) === String(threadId),        )        .map((event) => event.payload.delta)        .join("");      const terminalIndex = runtimeEvents.findIndex(        (event) => event.type === "turn.completed" && String(event.threadId) === String(threadId),      );      const turnOutputTypes = new Set([        "content.delta",        "item.started",        "item.updated",        "item.completed",        "turn.plan.updated",      ]);      const outputAfterTerminal = runtimeEvents        .slice(terminalIndex + 1)        .filter(          (event) => String(event.threadId) === String(threadId) && turnOutputTypes.has(event.type),        );      const toolTitles = runtimeEvents.flatMap((event) =>        event.type === "item.updated" && event.payload.title ? [event.payload.title] : [],      );       assert.equal(sendTurnResult.threadId, threadId);      assert.include(eventTypes, "turn.completed");      assert.equal(content, "hello from mock");      assert.isAtLeast(terminalIndex, 0);      assert.deepEqual(outputAfterTerminal, []);      assert.notInclude(toolTitles, "Child-only tool");      assert.equal(turnCompletedEvent?.payload.stopReason, "end_turn");      assert.equal(readySession?.status, "ready");      assert.isUndefined(readySession?.activeTurnId);       yield* Fiber.interrupt(runtimeEventsFiber);      yield* adapter.stopSession(threadId);    }),  );   it.effect("retains turn transcript when sendTurn is interrupted after prompt success", () =>    Effect.gen(function* () {      const threadId = ThreadId.make("grok-send-turn-interrupt-after-prompt");      const wrapperPath = yield* Effect.promise(() =>        makeMockGrokWrapper({          T3_ACP_EMIT_XAI_PROMPT_COMPLETE_THEN_HANG: "1",        }),      );      const adapter = yield* makeTestAdapter(wrapperPath);      const contentDelta = yield* Deferred.make<void>();      const runtimeEventsFiber = yield* Stream.runForEach(adapter.streamEvents, (event) =>        event.type === "content.delta" ? Deferred.succeed(contentDelta, undefined) : Effect.void,      ).pipe(Effect.forkChild);       yield* adapter.startSession({        threadId,        provider: ProviderDriverKind.make("grok"),        cwd: process.cwd(),        runtimeMode: "full-access",        modelSelection: { instanceId: ProviderInstanceId.make("grok"), model: "grok-build" },      });       const sendTurnFiber = yield* adapter        .sendTurn({          threadId,          input: "interrupt after prompt",          attachments: [],        })        .pipe(Effect.forkChild);       yield* Deferred.await(contentDelta);      for (let yieldAttempt = 0; yieldAttempt < 6; yieldAttempt += 1) {        yield* Effect.yieldNow;      }      yield* Fiber.interrupt(sendTurnFiber);      for (let yieldAttempt = 0; yieldAttempt < 4; yieldAttempt += 1) {        yield* Effect.yieldNow;      }       const snapshot = yield* adapter.readThread(threadId);      assert.equal(snapshot.turns.length, 1);      assert.equal(snapshot.turns[0]?.items.length, 1);       yield* Fiber.interrupt(runtimeEventsFiber);      yield* adapter.stopSession(threadId);    }),  );   it.effect("does not report a synthetic stop reason when xAI omits one", () =>    Effect.gen(function* () {      const threadId = ThreadId.make("grok-xai-prompt-complete-missing-stop-reason");      const wrapperPath = yield* Effect.promise(() =>        makeMockGrokWrapper({          T3_ACP_EMIT_XAI_PROMPT_COMPLETE_THEN_HANG: "1",          T3_ACP_OMIT_XAI_PROMPT_COMPLETE_STOP_REASON: "1",        }),      );      const adapter = yield* makeTestAdapter(wrapperPath);       const runtimeEvents: ProviderRuntimeEvent[] = [];      const turnCompleted = yield* Deferred.make<void>();      const runtimeEventsFiber = yield* Stream.runForEach(adapter.streamEvents, (event) =>        Effect.sync(() => {          runtimeEvents.push(event);        }).pipe(          Effect.andThen(            event.type === "turn.completed"              ? Deferred.succeed(turnCompleted, undefined)              : Effect.void,          ),        ),      ).pipe(Effect.forkChild);       yield* adapter.startSession({        threadId,        provider: ProviderDriverKind.make("grok"),        cwd: process.cwd(),        runtimeMode: "full-access",        modelSelection: { instanceId: ProviderInstanceId.make("grok"), model: "grok-build" },      });

Lines 1–500 of 1200.