type CriterionValues = Record; type DecisionOption = { optionId: string; name: string; values: CriterionValues }; type ExecutionRequest = { decisionId: string; profileId: string; scenarioId: string; algorithm: string; weightStrategy: string; runSensitivity: boolean; requestContext: { correlationId: string }; options: DecisionOption[]; }; const required = (name: string): string => { const value = process.env[name]; if (!value) throw new Error(`Set ${name} before running this example.`); return value; }; const identityUrl = process.env.DECISIOQ_IDENTITY_URL ?? "https://identity.vinquery.com/connect/token"; const catalogUrl = (process.env.DECISIOQ_DKS_URL ?? "https://dks.vinquery.com").replace(/\/$/, ""); const decisionServiceUrl = (process.env.DECISIOQ_DDE_URL ?? "https://dde.vinquery.com").replace(/\/$/, ""); const correlationId = `auto-tow-019-ts-${crypto.randomUUID()}`; const values = (proximity: number, certification: number, load: number, safety: number, rating: number): CriterionValues => ({ proximity_score: proximity, certification_match_score: certification, current_job_load: load, safety_history_score: safety, customer_rating_score: rating }); const tokenResponse = await fetch(identityUrl, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ clientId: required("DECISIOQ_CLIENT_ID"), clientSecret: required("DECISIOQ_CLIENT_SECRET"), audience: process.env.DECISIOQ_AUDIENCE ?? "vinquery:api:decisioq" }) }); if (!tokenResponse.ok) throw new Error(await tokenResponse.text()); const token = await tokenResponse.json() as { jwtToken: string }; const detailResponse = await fetch(`${catalogUrl}/decisioncatalog/decisions/AUTO-TOW-019`, { headers: { Authorization: `Bearer ${token.jwtToken}`, "X-Correlation-Id": correlationId } }); if (!detailResponse.ok) throw new Error(`Decision detail failed: ${detailResponse.status}`); const decisionDetail = await detailResponse.json(); const constraints = decisionDetail.constraints ?? []; if (constraints.length === 0) { console.log("No catalog-defined hard constraints; all validated candidates proceed to criteria-based ranking."); } const executionRequest: ExecutionRequest = { decisionId: "AUTO-TOW-019", profileId: "balanced", scenarioId: "standard", algorithm: "TOPSIS", weightStrategy: "Expert", runSensitivity: false, requestContext: { correlationId }, options: [ { optionId: "OPTION-001", name: "Operator North Zone", values: values(88, 88, 1, 88, 88) }, { optionId: "OPTION-002", name: "Operator Central Zone", values: values(80, 80, 3, 80, 80) }, { optionId: "OPTION-003", name: "Operator East Zone", values: values(72, 72, 5, 72, 72) } ] }; const executionResponse = await fetch(`${decisionServiceUrl}/api/v1/decide`, { method: "POST", headers: { Authorization: `Bearer ${token.jwtToken}`, "Content-Type": "application/json", "X-Correlation-Id": correlationId }, body: JSON.stringify(executionRequest) }); const responseText = await executionResponse.text(); console.log(responseText); try { const response = JSON.parse(responseText); console.log("Constraint summary:", response.constraintSummary ?? { excludedOptions: response.decisionResult?.excludedOptions ?? [] }); } catch { // Non-JSON errors are printed above. } if (!executionResponse.ok) process.exitCode = 1;