Add agent workflows & stuff
Build and Push Next App / quality (push) Failing after 48s
Build and Push Next App / build-next (push) Has been skipped

This commit is contained in:
Gabriel Brown
2026-06-21 21:15:15 -05:00
parent cf7ff2ee4e
commit 2dfa97ee4f
102 changed files with 8488 additions and 161 deletions
+140
View File
@@ -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 };
},
});