|
|
|
@@ -4,6 +4,7 @@ import type { Doc, Id } from './_generated/dataModel';
|
|
|
|
|
import type { MutationCtx } from './_generated/server';
|
|
|
|
|
import { internalMutation, mutation, query } from './_generated/server';
|
|
|
|
|
import { getOwnedSpoon, getRequiredUserId, optionalText } from './model';
|
|
|
|
|
import { assertWorkerToken } from './workerAuth';
|
|
|
|
|
|
|
|
|
|
const jobStatus = v.union(
|
|
|
|
|
v.literal('queued'),
|
|
|
|
@@ -152,14 +153,6 @@ const defaultAgentSettings = {
|
|
|
|
|
allowUserFileEditing: true,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const getWorkerToken = () => process.env.SPOON_WORKER_TOKEN?.trim();
|
|
|
|
|
|
|
|
|
|
const requireWorkerToken = (workerToken: string) => {
|
|
|
|
|
const expected = getWorkerToken();
|
|
|
|
|
if (!expected) throw new ConvexError('SPOON_WORKER_TOKEN is not configured.');
|
|
|
|
|
if (workerToken !== expected) throw new ConvexError('Invalid worker token.');
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const mergeMessageMetadata = (
|
|
|
|
|
metadata: string | undefined,
|
|
|
|
|
patch: Record<string, unknown>,
|
|
|
|
@@ -1123,7 +1116,7 @@ export const updateStatus = mutation({
|
|
|
|
|
summary: v.optional(v.string()),
|
|
|
|
|
},
|
|
|
|
|
handler: async (ctx, args) => {
|
|
|
|
|
requireWorkerToken(args.workerToken);
|
|
|
|
|
assertWorkerToken(args.workerToken);
|
|
|
|
|
const job = await ctx.db.get(args.jobId);
|
|
|
|
|
if (job?.claimedBy !== args.workerId) {
|
|
|
|
|
throw new ConvexError('Agent job not claimed by this worker.');
|
|
|
|
@@ -1193,7 +1186,7 @@ export const markWorkspaceActive = mutation({
|
|
|
|
|
workspaceExpiresAt: v.optional(v.number()),
|
|
|
|
|
},
|
|
|
|
|
handler: async (ctx, args) => {
|
|
|
|
|
requireWorkerToken(args.workerToken);
|
|
|
|
|
assertWorkerToken(args.workerToken);
|
|
|
|
|
const job = await ctx.db.get(args.jobId);
|
|
|
|
|
if (job?.claimedBy !== args.workerId) {
|
|
|
|
|
throw new ConvexError('Agent job not claimed by this worker.');
|
|
|
|
@@ -1223,7 +1216,7 @@ export const setRuntimeSession = mutation({
|
|
|
|
|
containerId: v.optional(v.string()),
|
|
|
|
|
},
|
|
|
|
|
handler: async (ctx, args) => {
|
|
|
|
|
requireWorkerToken(args.workerToken);
|
|
|
|
|
assertWorkerToken(args.workerToken);
|
|
|
|
|
const job = await ctx.db.get(args.jobId);
|
|
|
|
|
if (job?.claimedBy !== args.workerId) {
|
|
|
|
|
throw new ConvexError('Agent job not claimed by this worker.');
|
|
|
|
@@ -1247,7 +1240,7 @@ export const setCodexSessionId = mutation({
|
|
|
|
|
codexSessionId: v.string(),
|
|
|
|
|
},
|
|
|
|
|
handler: async (ctx, args) => {
|
|
|
|
|
requireWorkerToken(args.workerToken);
|
|
|
|
|
assertWorkerToken(args.workerToken);
|
|
|
|
|
const job = await ctx.db.get(args.jobId);
|
|
|
|
|
if (job?.claimedBy !== args.workerId) {
|
|
|
|
|
throw new ConvexError('Agent job not claimed by this worker.');
|
|
|
|
@@ -1275,7 +1268,7 @@ export const createInteractionRequest = mutation({
|
|
|
|
|
metadata: v.optional(v.string()),
|
|
|
|
|
},
|
|
|
|
|
handler: async (ctx, args) => {
|
|
|
|
|
requireWorkerToken(args.workerToken);
|
|
|
|
|
assertWorkerToken(args.workerToken);
|
|
|
|
|
const job = await ctx.db.get(args.jobId);
|
|
|
|
|
if (job?.claimedBy !== args.workerId) {
|
|
|
|
|
throw new ConvexError('Agent job not claimed by this worker.');
|
|
|
|
@@ -1327,7 +1320,7 @@ export const patchInteractionRequest = mutation({
|
|
|
|
|
metadata: v.optional(v.string()),
|
|
|
|
|
},
|
|
|
|
|
handler: async (ctx, args) => {
|
|
|
|
|
requireWorkerToken(args.workerToken);
|
|
|
|
|
assertWorkerToken(args.workerToken);
|
|
|
|
|
const interaction = await ctx.db.get(args.interactionId);
|
|
|
|
|
if (!interaction) throw new ConvexError('Interaction request not found.');
|
|
|
|
|
const job = await ctx.db.get(interaction.jobId);
|
|
|
|
@@ -1352,7 +1345,7 @@ export const markWorkspaceStopped = mutation({
|
|
|
|
|
workspaceStatus: v.optional(workspaceStatus),
|
|
|
|
|
},
|
|
|
|
|
handler: async (ctx, args) => {
|
|
|
|
|
requireWorkerToken(args.workerToken);
|
|
|
|
|
assertWorkerToken(args.workerToken);
|
|
|
|
|
const job = await ctx.db.get(args.jobId);
|
|
|
|
|
if (job?.claimedBy !== args.workerId) {
|
|
|
|
|
throw new ConvexError('Agent job not claimed by this worker.');
|
|
|
|
@@ -1373,7 +1366,7 @@ export const heartbeatWorkspace = mutation({
|
|
|
|
|
jobId: v.id('agentJobs'),
|
|
|
|
|
},
|
|
|
|
|
handler: async (ctx, args) => {
|
|
|
|
|
requireWorkerToken(args.workerToken);
|
|
|
|
|
assertWorkerToken(args.workerToken);
|
|
|
|
|
const job = await ctx.db.get(args.jobId);
|
|
|
|
|
if (job?.claimedBy !== args.workerId) {
|
|
|
|
|
throw new ConvexError('Agent job not claimed by this worker.');
|
|
|
|
@@ -1398,7 +1391,7 @@ export const completeWithDraftPr = mutation({
|
|
|
|
|
summary: v.string(),
|
|
|
|
|
},
|
|
|
|
|
handler: async (ctx, args) => {
|
|
|
|
|
requireWorkerToken(args.workerToken);
|
|
|
|
|
assertWorkerToken(args.workerToken);
|
|
|
|
|
const job = await ctx.db.get(args.jobId);
|
|
|
|
|
if (job?.claimedBy !== args.workerId) {
|
|
|
|
|
throw new ConvexError('Agent job not claimed by this worker.');
|
|
|
|
@@ -1445,7 +1438,7 @@ export const applyMaintenanceDecision = mutation({
|
|
|
|
|
requiresUserApproval: v.boolean(),
|
|
|
|
|
},
|
|
|
|
|
handler: async (ctx, args) => {
|
|
|
|
|
requireWorkerToken(args.workerToken);
|
|
|
|
|
assertWorkerToken(args.workerToken);
|
|
|
|
|
const job = await ctx.db.get(args.jobId);
|
|
|
|
|
if (job?.claimedBy !== args.workerId) {
|
|
|
|
|
throw new ConvexError('Agent job not claimed by this worker.');
|
|
|
|
@@ -1526,7 +1519,7 @@ export const appendEvent = mutation({
|
|
|
|
|
metadata: v.optional(v.string()),
|
|
|
|
|
},
|
|
|
|
|
handler: async (ctx, args) => {
|
|
|
|
|
requireWorkerToken(args.workerToken);
|
|
|
|
|
assertWorkerToken(args.workerToken);
|
|
|
|
|
const job = await ctx.db.get(args.jobId);
|
|
|
|
|
if (job?.claimedBy !== args.workerId) {
|
|
|
|
|
throw new ConvexError('Agent job not claimed by this worker.');
|
|
|
|
@@ -1555,7 +1548,7 @@ export const appendMessage = mutation({
|
|
|
|
|
metadata: v.optional(v.string()),
|
|
|
|
|
},
|
|
|
|
|
handler: async (ctx, args) => {
|
|
|
|
|
requireWorkerToken(args.workerToken);
|
|
|
|
|
assertWorkerToken(args.workerToken);
|
|
|
|
|
const job = await ctx.db.get(args.jobId);
|
|
|
|
|
if (job?.claimedBy !== args.workerId) {
|
|
|
|
|
throw new ConvexError('Agent job not claimed by this worker.');
|
|
|
|
@@ -1601,7 +1594,7 @@ export const updateMessage = mutation({
|
|
|
|
|
metadata: v.optional(v.string()),
|
|
|
|
|
},
|
|
|
|
|
handler: async (ctx, args) => {
|
|
|
|
|
requireWorkerToken(args.workerToken);
|
|
|
|
|
assertWorkerToken(args.workerToken);
|
|
|
|
|
const message = await ctx.db.get(args.messageId);
|
|
|
|
|
if (!message) throw new ConvexError('Agent message not found.');
|
|
|
|
|
const job = await ctx.db.get(message.jobId);
|
|
|
|
@@ -1656,7 +1649,7 @@ export const recordWorkspaceChange = mutation({
|
|
|
|
|
diff: v.optional(v.string()),
|
|
|
|
|
},
|
|
|
|
|
handler: async (ctx, args) => {
|
|
|
|
|
requireWorkerToken(args.workerToken);
|
|
|
|
|
assertWorkerToken(args.workerToken);
|
|
|
|
|
const job = await ctx.db.get(args.jobId);
|
|
|
|
|
if (job?.claimedBy !== args.workerId) {
|
|
|
|
|
throw new ConvexError('Agent job not claimed by this worker.');
|
|
|
|
@@ -1685,7 +1678,7 @@ export const addArtifact = mutation({
|
|
|
|
|
contentType: artifactContentType,
|
|
|
|
|
},
|
|
|
|
|
handler: async (ctx, args) => {
|
|
|
|
|
requireWorkerToken(args.workerToken);
|
|
|
|
|
assertWorkerToken(args.workerToken);
|
|
|
|
|
const job = await ctx.db.get(args.jobId);
|
|
|
|
|
if (job?.claimedBy !== args.workerId) {
|
|
|
|
|
throw new ConvexError('Agent job not claimed by this worker.');
|
|
|
|
|