import { type GrokSettings, ProviderDriverKind } from "@t3tools/contracts";import * as Effect from "effect/Effect";import * as Layer from "effect/Layer";import * as Scope from "effect/Scope";import { ChildProcessSpawner } from "effect/unstable/process";import * as EffectAcpErrors from "effect-acp/errors";import type * as EffectAcpSchema from "effect-acp/schema";import { normalizeModelSlug } from "@t3tools/shared/model"; import { AcpSessionRuntime, type AcpSessionRuntimeOptions, type AcpSessionRuntimeShape, type AcpSpawnInput,} from "./AcpSessionRuntime.ts"; const GROK_API_KEY_ENV = "XAI_API_KEY";const GROK_OAUTH2_REFERRER_ENV = "GROK_OAUTH2_REFERRER";const T3_CODE_OAUTH_REFERRER = "t3code";const GROK_AUTH_METHOD_API_KEY = "xai.api_key";const GROK_AUTH_METHOD_CACHED_TOKEN = "cached_token";const GROK_DRIVER_KIND = ProviderDriverKind.make("grok"); type GrokAcpRuntimeGrokSettings = Pick<GrokSettings, "binaryPath">; interface GrokAcpRuntimeInput extends Omit< AcpSessionRuntimeOptions, "authMethodId" | "clientCapabilities" | "spawn"> { readonly childProcessSpawner: ChildProcessSpawner.ChildProcessSpawner["Service"]; readonly grokSettings: GrokAcpRuntimeGrokSettings | null | undefined; readonly environment?: NodeJS.ProcessEnv;} export function buildGrokAcpSpawnInput( grokSettings: GrokAcpRuntimeGrokSettings | null | undefined, cwd: string, environment?: NodeJS.ProcessEnv,): AcpSpawnInput { return { command: grokSettings?.binaryPath || "grok", args: ["agent", "stdio"], cwd, env: { ...environment, [GROK_OAUTH2_REFERRER_ENV]: T3_CODE_OAUTH_REFERRER, }, };} function resolveGrokAuthMethodId(environment: NodeJS.ProcessEnv | undefined): string { return environment?.[GROK_API_KEY_ENV]?.trim() ? GROK_AUTH_METHOD_API_KEY : GROK_AUTH_METHOD_CACHED_TOKEN;} export const makeGrokAcpRuntime = ( input: GrokAcpRuntimeInput,): Effect.Effect<AcpSessionRuntimeShape, EffectAcpErrors.AcpError, Scope.Scope> => Effect.gen(function* () { const acpContext = yield* Layer.build( AcpSessionRuntime.layer({ ...input, spawn: buildGrokAcpSpawnInput(input.grokSettings, input.cwd, input.environment), authMethodId: resolveGrokAuthMethodId(input.environment), }).pipe( Layer.provide( Layer.succeed(ChildProcessSpawner.ChildProcessSpawner, input.childProcessSpawner), ), ), ); return yield* Effect.service(AcpSessionRuntime).pipe(Effect.provide(acpContext)); }); export function resolveGrokAcpBaseModelId(model: string | null | undefined): string { const trimmed = model?.trim(); const base = trimmed && trimmed.length > 0 ? trimmed : "grok-build"; return normalizeModelSlug(base, GROK_DRIVER_KIND) ?? "grok-build";} export function currentGrokModelIdFromSessionSetup( sessionSetupResult: | EffectAcpSchema.LoadSessionResponse | EffectAcpSchema.NewSessionResponse | EffectAcpSchema.ResumeSessionResponse,): string | undefined { return sessionSetupResult.models?.currentModelId?.trim() || undefined;} export function applyGrokAcpModelSelection<E>(input: { readonly runtime: Pick<AcpSessionRuntimeShape, "setSessionModel">; readonly currentModelId: string | undefined; readonly requestedModelId: string | undefined; readonly mapError: (cause: EffectAcpErrors.AcpError) => E;}): Effect.Effect<string | undefined, E> { const shouldSwitchModel = input.requestedModelId !== undefined && input.requestedModelId !== input.currentModelId; if (!shouldSwitchModel) { return Effect.succeed(input.currentModelId); } return input.runtime .setSessionModel(input.requestedModelId) .pipe(Effect.mapError(input.mapError), Effect.as(input.requestedModelId));}
import { type GrokSettings, ProviderDriverKind } from "@t3tools/contracts";
import * as Effect from "effect/Effect";
import * as Layer from "effect/Layer";
import * as Scope from "effect/Scope";
import { ChildProcessSpawner } from "effect/unstable/process";
import * as EffectAcpErrors from "effect-acp/errors";
import type * as EffectAcpSchema from "effect-acp/schema";
import { normalizeModelSlug } from "@t3tools/shared/model";
import {
AcpSessionRuntime,
type AcpSessionRuntimeOptions,
type AcpSessionRuntimeShape,
type AcpSpawnInput,
} from "./AcpSessionRuntime.ts";
const GROK_API_KEY_ENV = "XAI_API_KEY";
const GROK_OAUTH2_REFERRER_ENV = "GROK_OAUTH2_REFERRER";
const T3_CODE_OAUTH_REFERRER = "t3code";
const GROK_AUTH_METHOD_API_KEY = "xai.api_key";
const GROK_AUTH_METHOD_CACHED_TOKEN = "cached_token";
const GROK_DRIVER_KIND = ProviderDriverKind.make("grok");
type GrokAcpRuntimeGrokSettings = Pick<GrokSettings, "binaryPath">;
interface GrokAcpRuntimeInput extends Omit<
AcpSessionRuntimeOptions,
"authMethodId" | "clientCapabilities" | "spawn"
> {
readonly childProcessSpawner: ChildProcessSpawner.ChildProcessSpawner["Service"];
readonly grokSettings: GrokAcpRuntimeGrokSettings | null | undefined;
readonly environment?: NodeJS.ProcessEnv;
}
export function buildGrokAcpSpawnInput(
grokSettings: GrokAcpRuntimeGrokSettings | null | undefined,
cwd: string,
environment?: NodeJS.ProcessEnv,
): AcpSpawnInput {
return {
command: grokSettings?.binaryPath || "grok",
args: ["agent", "stdio"],
cwd,
env: {
...environment,
[GROK_OAUTH2_REFERRER_ENV]: T3_CODE_OAUTH_REFERRER,
},
};
}
function resolveGrokAuthMethodId(environment: NodeJS.ProcessEnv | undefined): string {
return environment?.[GROK_API_KEY_ENV]?.trim()
? GROK_AUTH_METHOD_API_KEY
: GROK_AUTH_METHOD_CACHED_TOKEN;
}
export const makeGrokAcpRuntime = (
input: GrokAcpRuntimeInput,
): Effect.Effect<AcpSessionRuntimeShape, EffectAcpErrors.AcpError, Scope.Scope> =>
Effect.gen(function* () {
const acpContext = yield* Layer.build(
AcpSessionRuntime.layer({
...input,
spawn: buildGrokAcpSpawnInput(input.grokSettings, input.cwd, input.environment),
authMethodId: resolveGrokAuthMethodId(input.environment),
}).pipe(
Layer.provide(
Layer.succeed(ChildProcessSpawner.ChildProcessSpawner, input.childProcessSpawner),
),
),
);
return yield* Effect.service(AcpSessionRuntime).pipe(Effect.provide(acpContext));
});
export function resolveGrokAcpBaseModelId(model: string | null | undefined): string {
const trimmed = model?.trim();
const base = trimmed && trimmed.length > 0 ? trimmed : "grok-build";
return normalizeModelSlug(base, GROK_DRIVER_KIND) ?? "grok-build";
}
export function currentGrokModelIdFromSessionSetup(
sessionSetupResult:
| EffectAcpSchema.LoadSessionResponse
| EffectAcpSchema.NewSessionResponse
| EffectAcpSchema.ResumeSessionResponse,
): string | undefined {
return sessionSetupResult.models?.currentModelId?.trim() || undefined;
}
export function applyGrokAcpModelSelection<E>(input: {
readonly runtime: Pick<AcpSessionRuntimeShape, "setSessionModel">;
readonly currentModelId: string | undefined;
readonly requestedModelId: string | undefined;
readonly mapError: (cause: EffectAcpErrors.AcpError) => E;
}): Effect.Effect<string | undefined, E> {
const shouldSwitchModel =
input.requestedModelId !== undefined && input.requestedModelId !== input.currentModelId;
if (!shouldSwitchModel) {
return Effect.succeed(input.currentModelId);
}
return input.runtime
.setSessionModel(input.requestedModelId)
.pipe(Effect.mapError(input.mapError), Effect.as(input.requestedModelId));
}