Add features & update project
Build and Push Spoon Images / quality (push) Successful in 1m41s
Build and Push Spoon Images / build-images (push) Successful in 7m4s

This commit is contained in:
Gabriel Brown
2026-06-23 02:06:58 -04:00
parent fe72fc2957
commit d207b8b0b8
26 changed files with 1257 additions and 231 deletions
+39 -2
View File
@@ -219,6 +219,11 @@ const isDeletableWorkspace = (job: Doc<'agentJobs'>) =>
['failed', 'cancelled', 'timed_out'].includes(job.status) ||
['stopped', 'expired', 'failed'].includes(job.workspaceStatus ?? '');
const isTerminalJob = (job: Doc<'agentJobs'>) =>
['failed', 'cancelled', 'timed_out', 'draft_pr_opened'].includes(
job.status,
) || ['stopped', 'expired', 'failed'].includes(job.workspaceStatus ?? '');
const deleteWorkspaceRows = async (ctx: MutationCtx, job: Doc<'agentJobs'>) => {
const messages = await ctx.db
.query('agentJobMessages')
@@ -546,7 +551,10 @@ export const createForThread = mutation({
throw new ConvexError('Thread not found.');
}
if (thread.latestAgentJobId) {
throw new ConvexError('This thread already has an agent job.');
const latestJob = await ctx.db.get(thread.latestAgentJobId);
if (latestJob && !isTerminalJob(latestJob)) {
throw new ConvexError('This thread already has an active agent job.');
}
}
const spoon = await getOwnedSpoon(ctx, thread.spoonId, ownerId);
const promptMessage = await ctx.db
@@ -609,7 +617,12 @@ export const createForThreadInternal = internalMutation({
if (thread?.ownerId !== args.ownerId || !thread.spoonId) {
throw new ConvexError('Thread not found.');
}
if (thread.latestAgentJobId) return thread.latestAgentJobId;
if (thread.latestAgentJobId) {
const latestJob = await ctx.db.get(thread.latestAgentJobId);
if (latestJob && !isTerminalJob(latestJob)) {
return thread.latestAgentJobId;
}
}
const spoon = await ctx.db.get(thread.spoonId);
if (spoon?.ownerId !== args.ownerId) {
throw new ConvexError('Spoon not found.');
@@ -929,6 +942,30 @@ export const deleteWorkspace = mutation({
},
});
export const markWorkspaceLost = mutation({
args: { jobId: v.id('agentJobs') },
handler: async (ctx, { jobId }) => {
const ownerId = await getRequiredUserId(ctx);
const job = await ctx.db.get(jobId);
if (job?.ownerId !== ownerId) throw new ConvexError('Agent job not found.');
const now = Date.now();
await ctx.db.patch(jobId, {
status: 'failed',
workspaceStatus: 'failed',
error: 'Workspace is not active on the configured worker.',
completedAt: job.completedAt ?? now,
updatedAt: now,
});
if (job.threadId) {
await ctx.db.patch(job.threadId, {
status: 'failed',
updatedAt: now,
});
}
return { success: true };
},
});
export const countOldWorkspaces = query({
args: { olderThanDays: v.optional(v.number()) },
handler: async (ctx, { olderThanDays }) => {