Fix sai changes integration blockers
This commit is contained in:
174
packages/backend/convex/agentWorkspace.ts
Normal file
174
packages/backend/convex/agentWorkspace.ts
Normal file
@@ -0,0 +1,174 @@
|
||||
import { env } from "@code/env/convex";
|
||||
import { ConvexError, v } from "convex/values";
|
||||
|
||||
import { mutation, query } from "./_generated/server";
|
||||
import { artifactPath } from "./artifactModel";
|
||||
|
||||
const requireAgent = (token: string) => {
|
||||
if (token !== env.FLUE_DB_TOKEN) {
|
||||
throw new ConvexError("Invalid agent control token");
|
||||
}
|
||||
};
|
||||
|
||||
const agentStatus = v.union(
|
||||
v.literal("working"),
|
||||
v.literal("needs-input"),
|
||||
v.literal("completed"),
|
||||
v.literal("failed")
|
||||
);
|
||||
|
||||
export const get = query({
|
||||
args: { issueId: v.id("projectIssues"), token: v.string() },
|
||||
handler: async (ctx, args) => {
|
||||
requireAgent(args.token);
|
||||
const issue = await ctx.db.get("projectIssues", args.issueId);
|
||||
if (!issue) {
|
||||
throw new ConvexError("Issue not found");
|
||||
}
|
||||
const project = await ctx.db.get("projects", issue.projectId);
|
||||
if (!project) {
|
||||
throw new ConvexError("Project not found");
|
||||
}
|
||||
const artifacts = await ctx.db
|
||||
.query("projectArtifacts")
|
||||
.withIndex("by_project", (q) => q.eq("projectId", project._id))
|
||||
.take(25);
|
||||
return { artifacts, issue, project };
|
||||
},
|
||||
});
|
||||
|
||||
export const ensureRun = mutation({
|
||||
args: {
|
||||
daemonId: v.string(),
|
||||
issueId: v.id("projectIssues"),
|
||||
token: v.string(),
|
||||
},
|
||||
handler: async (ctx, args) => {
|
||||
requireAgent(args.token);
|
||||
const issue = await ctx.db.get("projectIssues", args.issueId);
|
||||
if (!issue) {
|
||||
throw new ConvexError("Issue not found");
|
||||
}
|
||||
const existing = await ctx.db
|
||||
.query("projectWorkRuns")
|
||||
.withIndex("by_issue", (q) => q.eq("issueId", issue._id))
|
||||
.unique();
|
||||
if (existing) {
|
||||
return existing;
|
||||
}
|
||||
const timestamp = Date.now();
|
||||
const actorKey = [
|
||||
"project",
|
||||
String(issue.projectId),
|
||||
"issue",
|
||||
String(issue._id),
|
||||
];
|
||||
const runId = await ctx.db.insert("projectWorkRuns", {
|
||||
actorKey,
|
||||
agentId: String(issue._id),
|
||||
createdAt: timestamp,
|
||||
daemonId: args.daemonId,
|
||||
issueId: issue._id,
|
||||
projectId: issue.projectId,
|
||||
status: "queued",
|
||||
updatedAt: timestamp,
|
||||
});
|
||||
await ctx.db.insert("projectSignals", {
|
||||
createdAt: timestamp,
|
||||
data: { actorKey, daemonId: args.daemonId },
|
||||
issueId: issue._id,
|
||||
kind: "agent.workspace.created",
|
||||
projectId: issue.projectId,
|
||||
runId,
|
||||
});
|
||||
return await ctx.db.get("projectWorkRuns", runId);
|
||||
},
|
||||
});
|
||||
|
||||
export const updateArtifact = mutation({
|
||||
args: {
|
||||
content: v.string(),
|
||||
issueId: v.id("projectIssues"),
|
||||
path: artifactPath,
|
||||
token: v.string(),
|
||||
},
|
||||
handler: async (ctx, args) => {
|
||||
requireAgent(args.token);
|
||||
if (args.content.length > 200_000) {
|
||||
throw new ConvexError("Artifact content exceeds 200000 characters");
|
||||
}
|
||||
const issue = await ctx.db.get("projectIssues", args.issueId);
|
||||
if (!issue) {
|
||||
throw new ConvexError("Issue not found");
|
||||
}
|
||||
const artifact = await ctx.db
|
||||
.query("projectArtifacts")
|
||||
.withIndex("by_project_and_path", (q) =>
|
||||
q.eq("projectId", issue.projectId).eq("path", args.path)
|
||||
)
|
||||
.unique();
|
||||
if (!artifact) {
|
||||
throw new ConvexError(`Artifact ${args.path} not found`);
|
||||
}
|
||||
const timestamp = Date.now();
|
||||
await ctx.db.patch("projectArtifacts", artifact._id, {
|
||||
content: args.content,
|
||||
revision: artifact.revision + 1,
|
||||
updatedAt: timestamp,
|
||||
});
|
||||
await ctx.db.insert("projectSignals", {
|
||||
createdAt: timestamp,
|
||||
data: { path: args.path, revision: artifact.revision + 1 },
|
||||
issueId: issue._id,
|
||||
kind: "artifact.updated",
|
||||
projectId: issue.projectId,
|
||||
});
|
||||
return artifact.revision + 1;
|
||||
},
|
||||
});
|
||||
|
||||
export const setStatus = mutation({
|
||||
args: {
|
||||
issueId: v.id("projectIssues"),
|
||||
status: agentStatus,
|
||||
summary: v.optional(v.string()),
|
||||
token: v.string(),
|
||||
},
|
||||
handler: async (ctx, args) => {
|
||||
requireAgent(args.token);
|
||||
const issue = await ctx.db.get("projectIssues", args.issueId);
|
||||
if (!issue) {
|
||||
throw new ConvexError("Issue not found");
|
||||
}
|
||||
const run = await ctx.db
|
||||
.query("projectWorkRuns")
|
||||
.withIndex("by_issue", (q) => q.eq("issueId", issue._id))
|
||||
.unique();
|
||||
if (!run) {
|
||||
throw new ConvexError("Agent work run not found");
|
||||
}
|
||||
const timestamp = Date.now();
|
||||
const terminal = args.status === "completed" || args.status === "failed";
|
||||
await ctx.db.patch("projectIssues", issue._id, {
|
||||
status: args.status,
|
||||
updatedAt: timestamp,
|
||||
});
|
||||
await ctx.db.patch("projectWorkRuns", run._id, {
|
||||
status: args.status,
|
||||
summary: args.summary?.slice(0, 4000),
|
||||
updatedAt: timestamp,
|
||||
...(args.status === "working" && run.startedAt === undefined
|
||||
? { startedAt: timestamp }
|
||||
: {}),
|
||||
...(terminal ? { completedAt: timestamp } : {}),
|
||||
});
|
||||
await ctx.db.insert("projectSignals", {
|
||||
createdAt: timestamp,
|
||||
data: { summary: args.summary?.slice(0, 1000) },
|
||||
issueId: issue._id,
|
||||
kind: `agent.${args.status}`,
|
||||
projectId: issue.projectId,
|
||||
runId: run._id,
|
||||
});
|
||||
},
|
||||
});
|
||||
Reference in New Issue
Block a user