feat: add durable AgentOS slice execution
This commit is contained in:
80
packages/backend/convex/workExecutionAgent.ts
Normal file
80
packages/backend/convex/workExecutionAgent.ts
Normal file
@@ -0,0 +1,80 @@
|
||||
"use node";
|
||||
|
||||
import { env } from "@code/env/convex";
|
||||
import { decodeWorkAttemptExecutionResult } from "@code/primitives/execution-runtime";
|
||||
import { ConvexError, v } from "convex/values";
|
||||
import { Effect } from "effect";
|
||||
|
||||
import { internal } from "./_generated/api";
|
||||
import { internalAction } from "./_generated/server";
|
||||
import { decryptCredential } from "./gitConnections";
|
||||
|
||||
const backendUrl = () => env.AGENT_BACKEND_URL ?? env.FLUE_URL;
|
||||
|
||||
export const executeAttempt = internalAction({
|
||||
args: { attemptId: v.id("workAttempts") },
|
||||
handler: async (ctx, args) => {
|
||||
const running = await ctx.runMutation(
|
||||
internal.workExecutionWorkflow.markAttemptRunning,
|
||||
args
|
||||
);
|
||||
if (!running) {
|
||||
throw new ConvexError("Attempt is no longer runnable");
|
||||
}
|
||||
const context = await ctx.runQuery(
|
||||
internal.workExecutionWorkflow.executionContext,
|
||||
args
|
||||
);
|
||||
const credential = await decryptCredential(
|
||||
context.connection.credentialCiphertext,
|
||||
context.connection.credentialIv
|
||||
);
|
||||
const response = await fetch(
|
||||
`${backendUrl()}/internal/work-attempts/execute`,
|
||||
{
|
||||
body: JSON.stringify({
|
||||
attemptId: String(context.attempt._id),
|
||||
auth: {
|
||||
credential,
|
||||
provider: context.connection.provider,
|
||||
serverUrl: context.connection.serverUrl,
|
||||
username: context.connection.username,
|
||||
},
|
||||
baseBranch: context.project.defaultBranch ?? "main",
|
||||
prompt: context.prompt,
|
||||
repositoryUrl: context.project.sourceUrl,
|
||||
runId: String(context.run._id),
|
||||
workId: String(context.work._id),
|
||||
workspaceKey: context.attempt.workspaceKey,
|
||||
}),
|
||||
headers: {
|
||||
authorization: `Bearer ${env.FLUE_DB_TOKEN}`,
|
||||
"content-type": "application/json",
|
||||
},
|
||||
method: "POST",
|
||||
}
|
||||
);
|
||||
const payload = (await response.json()) as unknown;
|
||||
if (!response.ok) {
|
||||
throw new ConvexError(
|
||||
typeof payload === "object" && payload && "error" in payload
|
||||
? String(payload.error)
|
||||
: `Agent backend returned ${response.status}`
|
||||
);
|
||||
}
|
||||
return await Effect.runPromise(decodeWorkAttemptExecutionResult(payload));
|
||||
},
|
||||
});
|
||||
|
||||
export const cancelAttempt = internalAction({
|
||||
args: { workspaceKey: v.string() },
|
||||
handler: async (_ctx, args) => {
|
||||
await fetch(
|
||||
`${backendUrl()}/internal/work-attempts/${encodeURIComponent(args.workspaceKey)}/cancel`,
|
||||
{
|
||||
headers: { authorization: `Bearer ${env.FLUE_DB_TOKEN}` },
|
||||
method: "POST",
|
||||
}
|
||||
);
|
||||
},
|
||||
});
|
||||
Reference in New Issue
Block a user