feat: add OpenRouter audit generation pipeline
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
import { v } from "convex/values";
|
||||
|
||||
import { normalizeListLimit } from "./domain";
|
||||
import { mutation, query } from "./_generated/server";
|
||||
import { internalMutation, mutation, query } from "./_generated/server";
|
||||
|
||||
const auditStatus = v.union(
|
||||
v.literal("draft"),
|
||||
@@ -17,6 +17,13 @@ const usedSkillsValidator = v.array(
|
||||
source: v.optional(v.string()),
|
||||
}),
|
||||
);
|
||||
const skillSummaryValidator = v.array(
|
||||
v.object({
|
||||
name: v.string(),
|
||||
purpose: v.string(),
|
||||
summary: v.string(),
|
||||
}),
|
||||
);
|
||||
|
||||
export const create = mutation({
|
||||
args: {
|
||||
@@ -71,6 +78,81 @@ export const get = query({
|
||||
},
|
||||
});
|
||||
|
||||
export const upsertFromAuditGeneration = internalMutation({
|
||||
args: {
|
||||
leadId: v.id("leads"),
|
||||
runId: v.id("agentRuns"),
|
||||
auditId: v.optional(v.id("audits")),
|
||||
checkedDomain: v.string(),
|
||||
checkedPages: v.array(v.string()),
|
||||
internalSummary: v.optional(v.string()),
|
||||
multimodalSummary: v.optional(v.string()),
|
||||
publicSummary: v.optional(v.string()),
|
||||
publicBody: v.optional(v.string()),
|
||||
usedSkills: v.optional(usedSkillsValidator),
|
||||
skillSummaries: v.optional(skillSummaryValidator),
|
||||
},
|
||||
handler: async (ctx, args) => {
|
||||
const now = Date.now();
|
||||
const lead = await ctx.db.get(args.leadId);
|
||||
if (!lead) {
|
||||
throw new Error("Lead wurde nicht gefunden.");
|
||||
}
|
||||
|
||||
if (args.auditId) {
|
||||
const existing = await ctx.db.get(args.auditId);
|
||||
if (!existing) {
|
||||
throw new Error("Audit wurde nicht gefunden.");
|
||||
}
|
||||
|
||||
await ctx.db.patch(args.auditId, {
|
||||
checkedDomain: args.checkedDomain,
|
||||
checkedPages: args.checkedPages,
|
||||
internalSummary: args.internalSummary,
|
||||
multimodalSummary: args.multimodalSummary,
|
||||
publicSummary: args.publicSummary,
|
||||
publicBody: args.publicBody,
|
||||
usedSkills: args.usedSkills,
|
||||
skillSummaries: args.skillSummaries,
|
||||
updatedAt: now,
|
||||
});
|
||||
|
||||
return args.auditId;
|
||||
}
|
||||
|
||||
const safeCheckedDomain = args.checkedDomain.trim().toLowerCase();
|
||||
const domainTag = safeCheckedDomain.length > 0
|
||||
? safeCheckedDomain.replace(/[^a-z0-9]+/g, "-").slice(0, 50)
|
||||
: "lead";
|
||||
let slug = `audit-${domainTag}-${args.leadId}-${now}`;
|
||||
|
||||
const slugCandidates = await ctx.db
|
||||
.query("audits")
|
||||
.withIndex("by_slug", (q) => q.eq("slug", slug))
|
||||
.take(1);
|
||||
|
||||
if (slugCandidates.length > 0) {
|
||||
slug = `${slug}-${Math.floor(now / 1_000)}`;
|
||||
}
|
||||
|
||||
return await ctx.db.insert("audits", {
|
||||
leadId: args.leadId,
|
||||
status: "draft",
|
||||
slug,
|
||||
checkedDomain: args.checkedDomain,
|
||||
checkedPages: args.checkedPages,
|
||||
internalSummary: args.internalSummary,
|
||||
multimodalSummary: args.multimodalSummary,
|
||||
publicSummary: args.publicSummary,
|
||||
publicBody: args.publicBody,
|
||||
usedSkills: args.usedSkills,
|
||||
skillSummaries: args.skillSummaries,
|
||||
createdAt: now,
|
||||
updatedAt: now,
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
export const getBySlug = query({
|
||||
args: { slug: v.string() },
|
||||
handler: async (ctx, args) => {
|
||||
|
||||
Reference in New Issue
Block a user