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
@@ -0,0 +1,81 @@
import { NextResponse } from 'next/server';
import { proxyWorker } from '@/lib/agent-worker-proxy';
import { convexAuthNextjsToken } from '@convex-dev/auth/nextjs/server';
import { fetchMutation, fetchQuery } from 'convex/nextjs';
import type { Id } from '@spoon/backend/convex/_generated/dataModel.js';
import { api } from '@spoon/backend/convex/_generated/api.js';
const activeJobStatuses = new Set([
'claimed',
'preparing',
'running',
'checks_running',
'changes_ready',
]);
const activeWorkspaceStatuses = new Set(['active', 'idle']);
export const POST = async (
request: Request,
context: { params: Promise<{ threadId: string }> },
) => {
try {
const token = await convexAuthNextjsToken();
if (!token) {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
}
const { threadId: rawThreadId } = await context.params;
const threadId = rawThreadId as Id<'threads'>;
const body = (await request.json()) as { content?: string };
const content = body.content?.trim() ?? '';
if (!content) {
return NextResponse.json(
{ error: 'Message is required.' },
{ status: 400 },
);
}
const details = await fetchQuery(api.threads.get, { threadId }, { token });
const latestJob = details.latestJob;
const canSendToWorker =
latestJob &&
activeJobStatuses.has(latestJob.status) &&
activeWorkspaceStatuses.has(latestJob.workspaceStatus ?? '');
if (!canSendToWorker) {
await fetchMutation(
api.threads.appendUserMessage,
{ threadId, content },
{ token },
);
return NextResponse.json({
success: true,
mode: 'note',
message: latestJob
? 'Message was added as a thread note because the latest workspace is not active.'
: 'Message was added as a thread note.',
});
}
const proxied = await proxyWorker(latestJob._id, 'message', {
method: 'POST',
body: JSON.stringify({ content }),
});
if (!proxied.ok) {
const text = await proxied.text();
return NextResponse.json(
{
error: text,
recoverable:
text.includes('workspace is not active') ||
text.includes('not active on this worker'),
},
{ status: proxied.status === 500 ? 409 : proxied.status },
);
}
return proxied;
} catch (error) {
const message = error instanceof Error ? error.message : String(error);
return NextResponse.json({ error: message }, { status: 500 });
}
};