398 lines · 14.7 KB · TypeScript
RawDownload
import {  ANTIGRAVITY_DEFAULT_MODEL,  ProviderDriverKind,  type AntigravitySettings,  type ProviderSetupError,  type ServerProvider,  type ServerProviderModel,  type ServerProviderSlashCommand,} from "@t3tools/contracts";import { createModelCapabilities } from "@t3tools/shared/model";import * as DateTime from "effect/DateTime";import * as Effect from "effect/Effect";import * as Option from "effect/Option";import * as Predicate from "effect/Predicate";import * as Result from "effect/Result";import * as Stream from "effect/Stream";import * as SubscriptionRef from "effect/SubscriptionRef";import type * as EffectAcpErrors from "effect-acp/errors";import type * as EffectAcpSchema from "effect-acp/schema"; import type { AcpSessionRuntimeStartResult } from "../acp/AcpSessionRuntime.ts";import { makeManagedServerProvider } from "../makeManagedServerProvider.ts";import {  makeManualOnlyProviderMaintenanceCapabilities,  type ProviderMaintenanceCapabilities,} from "../providerMaintenance.ts";import {  buildServerProvider,  isCommandMissingCause,  type ServerProviderDraft,} from "../providerSnapshot.ts"; const EMPTY_MODEL_CAPABILITIES = createModelCapabilities({ optionDescriptors: [] });const MAX_WORKSPACE_SNAPSHOTS = 32;const HEALTH_CHECK_TIMEOUT = "90 seconds";const SIGN_IN_MESSAGE = "Sign in with Google to use Antigravity.";const AUTH_UNCHECKED_MESSAGE =  "Antigravity is installed. Google account access is not checked yet."; type SessionSetupResult = Pick<  AcpSessionRuntimeStartResult["sessionSetupResult"],  "configOptions" | "models">; /** Keep the native model IDs, including model-specific thinking levels. */export function buildAntigravityModelsFromSession(  setup: SessionSetupResult,): ReadonlyArray<ServerProviderModel> {  const config = setup.configOptions?.find(    (option) => option.id === "model" || option.category === "model",  );  const currentValue =    config?.type === "select" ? config.currentValue : setup.models?.currentModelId;  const entries =    config?.type === "select"      ? config.options.flatMap((entry) => ("value" in entry ? [entry] : entry.options))      : config === undefined        ? (setup.models?.availableModels.map((model) => ({            value: model.modelId,            name: model.name,          })) ?? [])        : [];  const seen = new Set<string>();  return entries.flatMap((entry): ServerProviderModel[] => {    if (!entry.value.trim() || seen.has(entry.value)) return [];    seen.add(entry.value);    return [      {        slug: entry.value,        name: entry.name.trim() ? entry.name : entry.value,        isCustom: false,        ...(entry.value === currentValue          ? { isDefault: true, aliases: [ANTIGRAVITY_DEFAULT_MODEL] }          : {}),        capabilities: EMPTY_MODEL_CAPABILITIES,      },    ];  });} function nativeCommands(  commands: ReadonlyArray<EffectAcpSchema.AvailableCommand>,): ReadonlyArray<ServerProviderSlashCommand> {  const seen = new Set<string>();  return commands.flatMap((command): ServerProviderSlashCommand[] => {    if (!command.name.trim() || seen.has(command.name)) return [];    seen.add(command.name);    const description = command.description.trim();    const hint = command.input?.hint.trim();    return [      {        name: command.name,        ...(description ? { description } : {}),        ...(hint ? { input: { hint } } : {}),      },    ];  });} function isMissingInstallation(error: EffectAcpErrors.AcpError | ProviderSetupError): boolean {  if (error._tag === "AcpSpawnError") {    return (      isCommandMissingCause(error.cause) ||      (Predicate.isObject(error.cause) && error.cause.code === "ENOENT")    );  }  return (    error._tag === "ProviderSetupError" &&    error.operation === "resolve" &&    /not installed|missing|incomplete|does not publish/i.test(error.detail)  );} interface AntigravityProviderState {  readonly draft: ServerProviderDraft;  readonly authRevision: number;} interface AntigravityProviderOptions {  readonly stampIdentity: (snapshot: ServerProviderDraft) => Effect.Effect<ServerProvider>;  readonly probe: Effect.Effect<    EffectAcpSchema.InitializeResponse,    EffectAcpErrors.AcpError | ProviderSetupError  >;  readonly supportsTextGeneration: Effect.Effect<boolean>;  readonly maintenanceCapabilities?: ProviderMaintenanceCapabilities;  /** Auth type and label published once a session authenticates. */  readonly auth?: { readonly type: string; readonly label: string };} /** Health uses initialize only. Session callbacks supply account-specific metadata. */export const makeAntigravityProvider = Effect.fn("makeAntigravityProvider")(function* (  settings: AntigravitySettings,  options: AntigravityProviderOptions,) {  const checkedAt = DateTime.formatIso(yield* DateTime.now);  const initialDraft = {    ...buildServerProvider({      presentation: { displayName: "Antigravity", showInteractionModeToggle: false },      enabled: settings.enabled,      checkedAt,      models: [],      probe: {        installed: false,        version: null,        status: "warning",        // The configured method rides along so the registry can tell a saved        // account for this method from one left by a previous configuration.        auth: { status: "unknown", ...(options.auth ? { type: options.auth.type } : {}) },        message: settings.enabled          ? "Checking Antigravity availability."          : "Antigravity is disabled in T3 Code settings.",      },    }),    setup: { canAuthenticate: true, canInstall: true },    supportsConversationRollback: false,    supportsTextGeneration: false,    workspaceSnapshots: [],  } satisfies ServerProviderDraft;  const metadata = yield* SubscriptionRef.make<AntigravityProviderState>({    draft: initialDraft,    authRevision: 0,  });  // Skills the driver discovered on disk per workspace. Session callbacks  // rewrite the workspace entry with native commands and must keep these, or  // the registry drops the suggestions and never re-reads the workspace.  const discoveredSkills = new Map<string, ServerProvider["skills"]>();  const getSnapshot = SubscriptionRef.get(metadata).pipe(    Effect.flatMap((state) => options.stampIdentity(state.draft)),  );   const checkProvider = Effect.fn("checkAntigravityProvider")(function* () {    if (!settings.enabled) return yield* getSnapshot;    const before = yield* SubscriptionRef.get(metadata);    const result = yield* options.probe.pipe(      Effect.timeoutOption(HEALTH_CHECK_TIMEOUT),      Effect.result,    );    const initialized =      Result.isSuccess(result) && Option.isSome(result.success) ? result.success.value : undefined;    const failure = Result.isFailure(result) ? result.failure : undefined;    const missingInstallation = failure !== undefined && isMissingInstallation(failure);    const errorMessage =      initialized !== undefined        ? undefined        : failure?._tag === "ProviderSetupError"          ? failure.detail.trim() || "Antigravity could not complete its local health check."          : missingInstallation            ? "Antigravity is not installed or its executable could not be found."            : failure              ? "Antigravity could not complete its local health check."              : `Antigravity did not respond to its local health check within ${HEALTH_CHECK_TIMEOUT}.`;    const supportsTextGeneration =      initialized !== undefined ? yield* options.supportsTextGeneration : false;    const updatedAt = DateTime.formatIso(yield* DateTime.now);    const next = yield* SubscriptionRef.updateAndGet(metadata, (state) => {      if (state.authRevision !== before.authRevision) return state;      const { message: _previousMessage, ...draft } = state.draft;      const authenticated = draft.auth.status === "authenticated";      const message =        errorMessage ??        (authenticated          ? undefined          : draft.auth.status === "unauthenticated"            ? SIGN_IN_MESSAGE            : AUTH_UNCHECKED_MESSAGE);      return {        ...state,        draft: {          ...draft,          installed: !missingInstallation,          version: initialized?.agentInfo?.version || draft.version,          status: errorMessage ? "error" : authenticated ? "ready" : "warning",          checkedAt: updatedAt,          ...(missingInstallation            ? {                models: [],                slashCommands: [],                skills: [],                workspaceSnapshots: [],                supportsTextGeneration: false,              }            : {}),          ...(initialized !== undefined            ? {                supportsTextGeneration:                  supportsTextGeneration && draft.auth.status !== "unauthenticated",              }            : {}),          ...(message ? { message } : {}),        },      } satisfies AntigravityProviderState;    });    return yield* options.stampIdentity(next.draft);  });   const maintenanceCapabilities =    options.maintenanceCapabilities ??    makeManualOnlyProviderMaintenanceCapabilities({      provider: ProviderDriverKind.make("antigravity"),      packageName: null,    });  const managed = yield* makeManagedServerProvider({    resolveMaintenance: () => Effect.succeed(maintenanceCapabilities),    getSettings: Effect.succeed(settings),    streamSettings: Stream.empty,    haveSettingsChanged: () => false,    initialSnapshot: () => getSnapshot,    checkProvider: checkProvider(),    enrichSnapshot: ({ publishSnapshot }) =>      SubscriptionRef.changes(metadata).pipe(        Stream.runForEach((state) =>          options.stampIdentity(state.draft).pipe(Effect.flatMap(publishSnapshot)),        ),      ),  });   const onSessionStarted = Effect.fn("AntigravityProvider.onSessionStarted")(function* (    started: AcpSessionRuntimeStartResult,    cwd?: string,  ) {    const before = yield* SubscriptionRef.get(metadata);    const supportsTextGeneration = yield* options.supportsTextGeneration;    const updatedAt = DateTime.formatIso(yield* DateTime.now);    yield* SubscriptionRef.update(metadata, (state) => {      if (        state.authRevision !== before.authRevision &&        state.draft.auth.status === "unauthenticated"      ) {        return state;      }      const { message: _previousMessage, ...draft } = state.draft;      const workspaces = draft.workspaceSnapshots ?? [];      const workspace = cwd ? workspaces.find((entry) => entry.cwd === cwd) : undefined;      return {        authRevision: state.authRevision + 1,        draft: {          ...draft,          installed: true,          status: settings.enabled ? "ready" : "disabled",          version: started.initializeResult.agentInfo?.version || draft.version,          auth: {            status: "authenticated",            type: options.auth?.type ?? "oauth-personal",            label: options.auth?.label ?? "Google account",          },          checkedAt: updatedAt,          models: buildAntigravityModelsFromSession(started.sessionSetupResult),          supportsTextGeneration,          ...(cwd            ? {                workspaceSnapshots: [                  ...workspaces.filter((entry) => entry.cwd !== cwd),                  {                    cwd,                    checkedAt: updatedAt,                    slashCommands: workspace?.slashCommands ?? draft.slashCommands,                    skills: workspace?.skills ?? discoveredSkills.get(cwd) ?? [],                  },                ].slice(-MAX_WORKSPACE_SNAPSHOTS),              }            : {}),        },      } satisfies AntigravityProviderState;    });  });   const onConfigOptionsUpdated = Effect.fn("AntigravityProvider.onConfigOptionsUpdated")(function* (    configOptions: ReadonlyArray<EffectAcpSchema.SessionConfigOption>,  ) {    const models = buildAntigravityModelsFromSession({ configOptions });    yield* SubscriptionRef.update(metadata, (state) => {      if (state.draft.auth.status !== "authenticated") return state;      return { ...state, draft: { ...state.draft, models } };    });  });   const onAvailableCommands = Effect.fn("AntigravityProvider.onAvailableCommands")(function* (    commands: ReadonlyArray<EffectAcpSchema.AvailableCommand>,    cwd?: string,  ) {    const slashCommands = nativeCommands(commands);    const updatedAt = DateTime.formatIso(yield* DateTime.now);    yield* SubscriptionRef.update(metadata, (state) => {      if (state.draft.auth.status === "unauthenticated") return state;      return {        ...state,        draft: {          ...state.draft,          slashCommands,          ...(cwd            ? {                workspaceSnapshots: [                  ...(state.draft.workspaceSnapshots ?? []).filter((entry) => entry.cwd !== cwd),                  {                    cwd,                    checkedAt: updatedAt,                    slashCommands,                    skills:                      state.draft.workspaceSnapshots?.find((entry) => entry.cwd === cwd)?.skills ??                      discoveredSkills.get(cwd) ??                      [],                  },                ].slice(-MAX_WORKSPACE_SNAPSHOTS),              }            : {}),        },      };    });  });   const clearAccountMetadata = Effect.fn("AntigravityProvider.clearAccountMetadata")(function* () {    const updatedAt = DateTime.formatIso(yield* DateTime.now);    yield* SubscriptionRef.update(      metadata,      (state) =>        ({          authRevision: state.authRevision + 1,          draft: {            ...state.draft,            auth: { status: "unauthenticated" },            status: settings.enabled ? "warning" : "disabled",            message: SIGN_IN_MESSAGE,            checkedAt: updatedAt,            models: [],            slashCommands: [],            skills: [],            workspaceSnapshots: [],            supportsTextGeneration: false,          },        }) satisfies AntigravityProviderState,    );    discoveredSkills.clear();  });   const snapshotForCwd = Effect.fn("AntigravityProvider.snapshotForCwd")(function* (    cwd: string,    skills?: ServerProvider["skills"],  ) {    if (skills) discoveredSkills.set(cwd, skills);    const snapshot = yield* getSnapshot;    const workspace = snapshot.workspaceSnapshots?.find((entry) => entry.cwd === cwd);    const resolvedSkills = skills ?? workspace?.skills ?? discoveredSkills.get(cwd) ?? [];    return workspace      ? { ...snapshot, slashCommands: workspace.slashCommands, skills: resolvedSkills }      : { ...snapshot, skills: resolvedSkills };  });   return {    snapshot: { ...managed, getSnapshot },    onSessionStarted,    onConfigOptionsUpdated,    onAvailableCommands,    onSignedOut: clearAccountMetadata(),    onAuthRequired: clearAccountMetadata(),    snapshotForCwd,  };});