Add agent workflows & stuff
This commit is contained in:
@@ -0,0 +1,140 @@
|
||||
import { ConvexError, v } from 'convex/values';
|
||||
|
||||
import type { Doc, Id } from './_generated/dataModel';
|
||||
import { internalMutation, query } from './_generated/server';
|
||||
import { getOwnedSpoon, getRequiredUserId } from './model';
|
||||
|
||||
const reviewStatus = v.union(
|
||||
v.literal('queued'),
|
||||
v.literal('running'),
|
||||
v.literal('completed'),
|
||||
v.literal('failed'),
|
||||
);
|
||||
|
||||
const reviewType = v.union(
|
||||
v.literal('upstream_update'),
|
||||
v.literal('manual_prompt'),
|
||||
v.literal('merge_safety'),
|
||||
);
|
||||
|
||||
const risk = v.union(
|
||||
v.literal('unknown'),
|
||||
v.literal('low'),
|
||||
v.literal('medium'),
|
||||
v.literal('high'),
|
||||
);
|
||||
|
||||
const recommendedAction = v.union(
|
||||
v.literal('sync'),
|
||||
v.literal('open_review_pr'),
|
||||
v.literal('manual_review'),
|
||||
v.literal('do_not_sync'),
|
||||
v.literal('unknown'),
|
||||
);
|
||||
|
||||
export const listForSpoon = query({
|
||||
args: { spoonId: v.id('spoons'), limit: v.optional(v.number()) },
|
||||
handler: async (ctx, { spoonId, limit }) => {
|
||||
const ownerId = await getRequiredUserId(ctx);
|
||||
await getOwnedSpoon(ctx, spoonId, ownerId);
|
||||
return await ctx.db
|
||||
.query('aiReviews')
|
||||
.withIndex('by_spoon', (q) => q.eq('spoonId', spoonId))
|
||||
.order('desc')
|
||||
.take(limit ?? 25);
|
||||
},
|
||||
});
|
||||
|
||||
export const getLatestForSpoon = query({
|
||||
args: { spoonId: v.id('spoons') },
|
||||
handler: async (ctx, { spoonId }) => {
|
||||
const ownerId = await getRequiredUserId(ctx);
|
||||
await getOwnedSpoon(ctx, spoonId, ownerId);
|
||||
return await ctx.db
|
||||
.query('aiReviews')
|
||||
.withIndex('by_spoon', (q) => q.eq('spoonId', spoonId))
|
||||
.order('desc')
|
||||
.first();
|
||||
},
|
||||
});
|
||||
|
||||
export const listRecent = query({
|
||||
args: { limit: v.optional(v.number()) },
|
||||
handler: async (ctx, { limit }) => {
|
||||
const ownerId = await getRequiredUserId(ctx);
|
||||
return await ctx.db
|
||||
.query('aiReviews')
|
||||
.withIndex('by_owner', (q) => q.eq('ownerId', ownerId))
|
||||
.order('desc')
|
||||
.take(limit ?? 25);
|
||||
},
|
||||
});
|
||||
|
||||
export const createInternal = internalMutation({
|
||||
args: {
|
||||
spoonId: v.id('spoons'),
|
||||
ownerId: v.id('users'),
|
||||
syncRunId: v.optional(v.id('syncRuns')),
|
||||
model: v.string(),
|
||||
status: reviewStatus,
|
||||
reviewType,
|
||||
inputSummary: v.string(),
|
||||
},
|
||||
handler: async (ctx, args): Promise<Id<'aiReviews'>> => {
|
||||
const now = Date.now();
|
||||
return await ctx.db.insert('aiReviews', {
|
||||
...args,
|
||||
risk: 'unknown',
|
||||
compatible: false,
|
||||
requiresHumanReview: true,
|
||||
recommendedAction: 'unknown',
|
||||
createdAt: now,
|
||||
updatedAt: now,
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
export const completeInternal = internalMutation({
|
||||
args: {
|
||||
reviewId: v.id('aiReviews'),
|
||||
outputSummary: v.string(),
|
||||
risk,
|
||||
compatible: v.boolean(),
|
||||
requiresHumanReview: v.boolean(),
|
||||
recommendedAction,
|
||||
potentialConflicts: v.array(v.string()),
|
||||
importantFiles: v.array(v.string()),
|
||||
reasoningSummary: v.string(),
|
||||
},
|
||||
handler: async (ctx, args) => {
|
||||
const review = await ctx.db.get(args.reviewId);
|
||||
if (!review) throw new ConvexError('AI review not found.');
|
||||
const patch: Partial<Doc<'aiReviews'>> = {
|
||||
status: 'completed',
|
||||
outputSummary: args.outputSummary,
|
||||
risk: args.risk,
|
||||
compatible: args.compatible,
|
||||
requiresHumanReview: args.requiresHumanReview,
|
||||
recommendedAction: args.recommendedAction,
|
||||
potentialConflicts: args.potentialConflicts,
|
||||
importantFiles: args.importantFiles,
|
||||
reasoningSummary: args.reasoningSummary,
|
||||
updatedAt: Date.now(),
|
||||
completedAt: Date.now(),
|
||||
};
|
||||
await ctx.db.patch(args.reviewId, patch);
|
||||
return review;
|
||||
},
|
||||
});
|
||||
|
||||
export const failInternal = internalMutation({
|
||||
args: { reviewId: v.id('aiReviews'), error: v.string() },
|
||||
handler: async (ctx, { reviewId, error }) => {
|
||||
await ctx.db.patch(reviewId, {
|
||||
status: 'failed',
|
||||
error,
|
||||
updatedAt: Date.now(),
|
||||
});
|
||||
return { success: true };
|
||||
},
|
||||
});
|
||||
Reference in New Issue
Block a user