import { createServerFn } from "@tanstack/react-start";
import { z } from "zod";
import { requireViewer, viewerMiddleware } from "./middleware";
import { limitHeavy } from "~/server/limits";
import { assertVerifiedForWrites } from "~/server/verified-writes";
import { requireRepoAccess } from "~/server/repos";
import { compareBranches } from "~/server/git/compare";
import { badRequest, forbidden } from "~/server/errors";
import { loadRepoSettings } from "~/server/mergefix/store";
import { suggestPullDescription as suggest } from "~/server/pull-describe/service";
import { repoRef } from "~/lib/validation";
/** Billed to the viewer (their plan or their own key), never the repository owner: any reader can open a pull request. */
export const suggestPullDescription = createServerFn({ method: "POST" })
.middleware([viewerMiddleware])
.validator(repoRef.extend({ base: z.string().min(1), head: z.string().min(1) }))
.handler(async ({ data, context }) => {
const viewer = requireViewer(context.viewer);
assertVerifiedForWrites(viewer);
await limitHeavy(viewer);
const { repo } = await requireRepoAccess(data.owner, data.repo, viewer, "read");
// Private code only goes to a model when the repository opted in (the same switch as merge fixes).
if (repo.visibility !== "public" && !(await loadRepoSettings(repo.id)).allowPrivate)
throw forbidden("AI features are off for this private repository");
const compared = await compareBranches(repo, data.base, data.head, viewer);
const headRepo = compared.headRepo;
if (
headRepo.id !== repo.id &&
headRepo.visibility !== "public" &&
!(await loadRepoSettings(headRepo.id)).allowPrivate
)
throw forbidden("AI features are off for the private head repository");
if (compared.comparison.commits.length === 0) throw badRequest("There are no commits to describe");
return suggest(
{ accountId: viewer.id, repoId: repo.id },
{ base: compared.base.name, head: compared.head.name, commits: compared.comparison.commits, diff: compared.diff },
);
});