mirror of
https://github.com/harivansh-afk/sandbox-agent.git
synced 2026-04-16 21:03:46 +00:00
Refactor Foundry GitHub and sandbox flows
This commit is contained in:
parent
4bccd5fc8d
commit
ec8e816d0d
112 changed files with 4026 additions and 2715 deletions
160
foundry/packages/backend/src/actors/runtime-issues.ts
Normal file
160
foundry/packages/backend/src/actors/runtime-issues.ts
Normal file
|
|
@ -0,0 +1,160 @@
|
|||
import type { WorkflowErrorEvent } from "rivetkit/workflow";
|
||||
import type { FoundryActorRuntimeIssue, FoundryActorRuntimeType } from "@sandbox-agent/foundry-shared";
|
||||
import { sql } from "drizzle-orm";
|
||||
import { organizationActorIssues } from "./organization/db/schema.js";
|
||||
import { getOrCreateOrganization } from "./handles.js";
|
||||
|
||||
export interface ActorRuntimeIssueRecord extends FoundryActorRuntimeIssue {}
|
||||
|
||||
interface NormalizedWorkflowIssue {
|
||||
workflowId: string | null;
|
||||
stepName: string | null;
|
||||
attempt: number | null;
|
||||
willRetry: boolean;
|
||||
retryDelayMs: number | null;
|
||||
message: string;
|
||||
}
|
||||
|
||||
interface ReportWorkflowIssueInput {
|
||||
actorType: FoundryActorRuntimeType;
|
||||
scopeId?: string | null;
|
||||
scopeLabel: string;
|
||||
organizationId: string;
|
||||
}
|
||||
|
||||
async function ensureOrganizationActorIssuesTable(c: any): Promise<void> {
|
||||
await c.db.run(sql`
|
||||
CREATE TABLE IF NOT EXISTS organization_actor_issues (
|
||||
actor_id text PRIMARY KEY NOT NULL,
|
||||
actor_type text NOT NULL,
|
||||
scope_id text,
|
||||
scope_label text NOT NULL,
|
||||
message text NOT NULL,
|
||||
workflow_id text,
|
||||
step_name text,
|
||||
attempt integer,
|
||||
will_retry integer DEFAULT 0 NOT NULL,
|
||||
retry_delay_ms integer,
|
||||
occurred_at integer NOT NULL,
|
||||
updated_at integer NOT NULL
|
||||
)
|
||||
`);
|
||||
}
|
||||
|
||||
export async function upsertActorRuntimeIssue(c: any, issue: ActorRuntimeIssueRecord): Promise<void> {
|
||||
await ensureOrganizationActorIssuesTable(c);
|
||||
await c.db
|
||||
.insert(organizationActorIssues)
|
||||
.values({
|
||||
actorId: issue.actorId,
|
||||
actorType: issue.actorType,
|
||||
scopeId: issue.scopeId,
|
||||
scopeLabel: issue.scopeLabel,
|
||||
message: issue.message,
|
||||
workflowId: issue.workflowId,
|
||||
stepName: issue.stepName,
|
||||
attempt: issue.attempt,
|
||||
willRetry: issue.willRetry ? 1 : 0,
|
||||
retryDelayMs: issue.retryDelayMs,
|
||||
occurredAt: issue.occurredAt,
|
||||
updatedAt: issue.occurredAt,
|
||||
})
|
||||
.onConflictDoUpdate({
|
||||
target: organizationActorIssues.actorId,
|
||||
set: {
|
||||
actorType: issue.actorType,
|
||||
scopeId: issue.scopeId,
|
||||
scopeLabel: issue.scopeLabel,
|
||||
message: issue.message,
|
||||
workflowId: issue.workflowId,
|
||||
stepName: issue.stepName,
|
||||
attempt: issue.attempt,
|
||||
willRetry: issue.willRetry ? 1 : 0,
|
||||
retryDelayMs: issue.retryDelayMs,
|
||||
occurredAt: issue.occurredAt,
|
||||
updatedAt: issue.occurredAt,
|
||||
},
|
||||
})
|
||||
.run();
|
||||
}
|
||||
|
||||
export async function listActorRuntimeIssues(c: any): Promise<ActorRuntimeIssueRecord[]> {
|
||||
await ensureOrganizationActorIssuesTable(c);
|
||||
const rows = await c.db.select().from(organizationActorIssues).orderBy(organizationActorIssues.occurredAt).all();
|
||||
return rows
|
||||
.map((row) => ({
|
||||
actorId: row.actorId,
|
||||
actorType: row.actorType as FoundryActorRuntimeType,
|
||||
scopeId: row.scopeId ?? null,
|
||||
scopeLabel: row.scopeLabel,
|
||||
message: row.message,
|
||||
workflowId: row.workflowId ?? null,
|
||||
stepName: row.stepName ?? null,
|
||||
attempt: row.attempt ?? null,
|
||||
willRetry: Boolean(row.willRetry),
|
||||
retryDelayMs: row.retryDelayMs ?? null,
|
||||
occurredAt: row.occurredAt,
|
||||
}))
|
||||
.sort((left, right) => right.occurredAt - left.occurredAt);
|
||||
}
|
||||
|
||||
function normalizeWorkflowIssue(event: WorkflowErrorEvent): NormalizedWorkflowIssue {
|
||||
if ("step" in event) {
|
||||
const error = event.step.error;
|
||||
return {
|
||||
workflowId: event.step.workflowId,
|
||||
stepName: event.step.stepName,
|
||||
attempt: event.step.attempt,
|
||||
willRetry: event.step.willRetry,
|
||||
retryDelayMs: event.step.retryDelay ?? null,
|
||||
message: `${error.name}: ${error.message}`,
|
||||
};
|
||||
}
|
||||
|
||||
if ("rollback" in event) {
|
||||
const error = event.rollback.error;
|
||||
return {
|
||||
workflowId: event.rollback.workflowId,
|
||||
stepName: event.rollback.stepName,
|
||||
attempt: null,
|
||||
willRetry: false,
|
||||
retryDelayMs: null,
|
||||
message: `${error.name}: ${error.message}`,
|
||||
};
|
||||
}
|
||||
|
||||
const error = event.workflow.error;
|
||||
return {
|
||||
workflowId: event.workflow.workflowId,
|
||||
stepName: null,
|
||||
attempt: null,
|
||||
willRetry: false,
|
||||
retryDelayMs: null,
|
||||
message: `${error.name}: ${error.message}`,
|
||||
};
|
||||
}
|
||||
|
||||
export async function reportWorkflowIssueToOrganization(c: any, event: WorkflowErrorEvent, input: ReportWorkflowIssueInput): Promise<void> {
|
||||
const normalized = normalizeWorkflowIssue(event);
|
||||
const issue: ActorRuntimeIssueRecord = {
|
||||
actorId: c.actorId,
|
||||
actorType: input.actorType,
|
||||
scopeId: input.scopeId ?? null,
|
||||
scopeLabel: input.scopeLabel,
|
||||
message: normalized.message,
|
||||
workflowId: normalized.workflowId,
|
||||
stepName: normalized.stepName,
|
||||
attempt: normalized.attempt,
|
||||
willRetry: normalized.willRetry,
|
||||
retryDelayMs: normalized.retryDelayMs,
|
||||
occurredAt: Date.now(),
|
||||
};
|
||||
|
||||
if (input.actorType === "organization" && input.organizationId === c.state.workspaceId) {
|
||||
await upsertActorRuntimeIssue(c, issue);
|
||||
return;
|
||||
}
|
||||
|
||||
const organization = await getOrCreateOrganization(c, input.organizationId);
|
||||
await organization.recordActorRuntimeIssue(issue);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue