feat(workflow): orchestrate resumable dataflow handoffs

This commit is contained in:
2026-07-30 03:11:56 +02:00
parent a1654e70cf
commit a6e0e89829
18 changed files with 3938 additions and 27 deletions
+155
View File
@@ -84,6 +84,75 @@ export type WorkflowGovernance = {
automation_runtime_reason?: string | null;
};
export type WorkflowInstanceStatus =
| "running"
| "waiting"
| "completed"
| "failed"
| "cancelled";
export type WorkflowStepStatus =
| "running"
| "waiting"
| "completed"
| "failed"
| "cancelled"
| "superseded";
export type WorkflowInstanceStep = {
id: string;
sequence: number;
node_id: string;
node_type: string;
status: WorkflowStepStatus;
attempt: number;
input: Record<string, unknown>;
output: Record<string, unknown>;
handoff: Record<string, unknown>;
external_ref?: string | null;
started_at?: string | null;
finished_at?: string | null;
error?: string | null;
completed_by?: string | null;
created_at: string;
updated_at: string;
};
export type WorkflowInstanceEvent = {
id: string;
sequence: number;
step_id?: string | null;
kind: string;
actor_id?: string | null;
payload: Record<string, unknown>;
created_at: string;
};
export type WorkflowInstance = {
id: string;
definition_id: string;
definition_name: string;
definition_revision: number;
definition_hash: string;
status: WorkflowInstanceStatus;
idempotency_key: string;
correlation_id?: string | null;
current_step_id?: string | null;
input: Record<string, unknown>;
context: Record<string, unknown>;
output: Record<string, unknown>;
started_at: string;
finished_at?: string | null;
cancellation_requested_at?: string | null;
error?: string | null;
created_by?: string | null;
created_at: string;
updated_at: string;
steps: WorkflowInstanceStep[];
events: WorkflowInstanceEvent[];
replayed: boolean;
};
export type WorkflowDefinitionPayload = {
name: string;
description?: string | null;
@@ -232,3 +301,89 @@ export function workflowScopeReferenceProvider(
{ scope_type: scopeType }
);
}
export async function listWorkflowInstances(
settings: ApiSettings,
definitionId?: string | null
): Promise<WorkflowInstance[]> {
const params = new URLSearchParams();
if (definitionId) params.set("definition_id", definitionId);
const query = params.size ? `?${params.toString()}` : "";
const response = await apiFetch<{ instances: WorkflowInstance[] }>(
settings,
`/api/v1/workflow/instances${query}`
);
return response.instances;
}
export function startWorkflowInstance(
settings: ApiSettings,
definitionId: string,
payload: {
idempotency_key: string;
input?: Record<string, unknown>;
correlation_id?: string | null;
}
): Promise<WorkflowInstance> {
return apiFetch(
settings,
`/api/v1/workflow/definitions/${encodeURIComponent(definitionId)}/instances`,
{
method: "POST",
body: JSON.stringify(payload)
}
);
}
export function getWorkflowInstance(
settings: ApiSettings,
instanceId: string
): Promise<WorkflowInstance> {
return apiFetch(
settings,
`/api/v1/workflow/instances/${encodeURIComponent(instanceId)}`
);
}
export function reconcileWorkflowInstance(
settings: ApiSettings,
instanceId: string
): Promise<WorkflowInstance> {
return apiFetch(
settings,
`/api/v1/workflow/instances/${encodeURIComponent(instanceId)}/reconcile`,
{ method: "POST" }
);
}
export function resolveWorkflowStep(
settings: ApiSettings,
instanceId: string,
stepId: string,
payload: {
action: "complete" | "approve" | "changes" | "reject" | "resume" | "retry" | "cancel";
output?: Record<string, unknown>;
evidence?: string[];
comment?: string | null;
}
): Promise<WorkflowInstance> {
return apiFetch(
settings,
`/api/v1/workflow/instances/${encodeURIComponent(instanceId)}/steps/${encodeURIComponent(stepId)}/actions`,
{
method: "POST",
body: JSON.stringify(payload)
}
);
}
export function cancelWorkflowInstance(
settings: ApiSettings,
instanceId: string
): Promise<WorkflowInstance> {
return apiFetch(
settings,
`/api/v1/workflow/instances/${encodeURIComponent(instanceId)}/cancel`,
{ method: "POST" }
);
}