PYAE1994's picture
Upload folder using huggingface_hub
dd480ef verified
/**
* POST /api/workflows/simulate
* Dry-run simulation - offloaded entirely to external compute service
* CF Worker just proxies the request and stores results in KV
*/
import { Hono } from 'hono';
import { z } from 'zod';
import type { Env } from '../types/env';
import type { WorkflowJob } from '../types/workflow';
import { createAuditEvent } from '../utils/audit';
export const simulateWorkflowRoute = new Hono<{ Bindings: Env }>();
const SimulateRequestSchema = z.object({
jobId: z.string().min(1),
mockData: z.record(z.unknown()).optional(),
});
simulateWorkflowRoute.post('/simulate', async (c) => {
const body = await c.req.json().catch(() => null);
if (!body) return c.json({ success: false, error: 'Invalid JSON body' }, 400);
const parsed = SimulateRequestSchema.safeParse(body);
if (!parsed.success) {
return c.json({ success: false, error: 'Validation failed', details: parsed.error.flatten() }, 400);
}
const { jobId, mockData } = parsed.data;
const raw = await c.env.WFO_CACHE.get(`job:${jobId}`, 'text');
if (!raw) return c.json({ success: false, error: `Job ${jobId} not found` }, 404);
const job = JSON.parse(raw) as WorkflowJob;
if (!job.compiledWorkflow || !job.graph) {
return c.json({
success: false,
error: 'Workflow not compiled or validated. Run /generate and /validate first.',
}, 409);
}
if (job.validationReport && !job.validationReport.valid) {
return c.json({
success: false,
error: 'Cannot simulate an invalid workflow. Fix validation issues first.',
validationReport: job.validationReport,
}, 409);
}
// Offload simulation to external compute (CPU-intensive)
const resp = await fetch(`${c.env.SIMULATOR_URL}/process/simulate`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Internal-Secret': c.env.INTERNAL_API_SECRET,
},
body: JSON.stringify({
jobId,
workflow: job.compiledWorkflow,
graph: job.graph,
architecturePlan: job.architecturePlan,
mockData: mockData ?? {},
}),
signal: AbortSignal.timeout(25000),
}).catch((e) => { throw new Error(`Simulator error: ${e instanceof Error ? e.message : 'unknown'}`); });
if (!resp.ok) {
return c.json({ success: false, error: `Simulator returned ${resp.status}` }, 502);
}
const result = await resp.json() as { simulationReport: WorkflowJob['simulationReport'] };
const updated: WorkflowJob = {
...job,
state: result.simulationReport?.passed ? 'simulated' : 'validated',
simulationReport: result.simulationReport,
updatedAt: new Date().toISOString(),
auditLog: [
...job.auditLog,
createAuditEvent(jobId, 'simulation.completed', 'system', {
passed: result.simulationReport?.passed,
readinessScore: result.simulationReport?.readinessScore,
}),
],
};
await c.env.WFO_CACHE.put(`job:${jobId}`, JSON.stringify(updated), { expirationTtl: 86400 * 7 });
return c.json({ success: true, jobId, simulationReport: result.simulationReport });
});