@uipath/vs-policy-engine
v1.1.1
Published
UiPath Vertical Solution Policy Engine SDK: a typed fetch client for the Vertical Solution Service policy-engine API (v1) and the document types and schemas
Maintainers
Keywords
Readme
@uipath/vs-policy-engine
SDK for the policy-engine API of the Vertical Solution Service (VSS,
…/verticalsolution_/policy-engine/v1): a typed fetch client and the
document types and zod schemas the API reads and writes.
- ESM only,
fetchonly: no Node built-ins, no environment or config reads. Runs in browsers, Node 20+ and Bun. - One peer dependency,
zod4 (the schemas are composable with yours). - Pinned to API version 1; the SDK major is the API version it calls
(
1.xcalls/policy-engine/v1/…).
npm install @uipath/vs-policy-engine zodClient
import { createPolicyEngineClient } from "@uipath/vs-policy-engine";
const client = createPolicyEngineClient({
baseUrl: "https://cloud.uipath.com",
orgName: "acme",
tenantName: "DefaultTenant",
getAuthToken: () => getAccessToken(),
folderKey: "0f8fad5b-d9cb-469f-a165-70867728950e", // optional Orchestrator folder GUID, sent as X-UIPATH-FolderKey
client: "fins/2.3.0", // optional `<vertical-id>/<app-version>`, sent as x-client
});
const policies = await client.policies.list();
const policy = await client.policies.create({ profileId, name: "Underwriting" });
const model = await client.decisionModels.create({ policyId: policy.id, model: decisionModel });
const latest = await client.decisionModels.latest(policy.id); // newest successful revision or null
const started = await client.evaluations.create({
decisionModelId: model.id,
caseId: "case-42",
parameters: { amount: { value: 1200 }, is_active: { value: true } },
});
const evaluation = await client.evaluations.waitUntilSettled(started.evaluationId, {
pollIntervalMs: 2000,
timeoutMs: 10 * 60_000,
});
if (evaluation.status === "success") {
console.log(evaluation.outcome, evaluation.reasoning?.rules);
}baseUrl, orgName, tenantName and getAuthToken are the same fields the
other @uipath/vs-* packages take, so one PlatformServiceConfig configures
them all. Requests go to
{baseUrl}/{orgName}/{tenantName}/verticalsolution_/policy-engine/v1/…; an
empty baseUrl targets the page's own origin behind a dev proxy.
folderKey scopes the client to one Orchestrator folder: it reads and writes
only that folder's rows, and the caller must have access to the folder.
Without it the client acts on tenant-level rows only. Every row carries its
folderKey (null for a tenant-level row). One client is one scope; a
consumer working in several folders creates a client per folder.
Resources: profiles, policies, supportingDocuments, decisionModels,
evaluations. Every method takes a trailing { signal }. Lists return the
complete array in the client's scope, newest first: API v1 pages nothing, and
a paged list would be a new API version and so a new SDK major.
decisionModels.latest reads the policy's successful revisions and keeps the
newest. waitUntilSettled returns the row once its status is no longer
pending, for success and faulted alike, and throws
PolicyEngineTimeoutError when the timeout passes. evaluations.createAndWait
is the two calls in one.
Uploads take a FilePart ({ blob, filename, contentType? }):
policies.createWithDocument, policies.uploadDocument,
supportingDocuments.create, supportingDocuments.uploadFile,
evaluations.createWithDocuments. Downloads return a Blob.
Flows
client.flows composes the steps that go together, each waiting for the run
it starts and returning the settled rows (a faulted row is returned, not
thrown):
const { profile, policy, decisionModel } = await client.flows.onboardPolicy({
profile: { name: "Underwriting", query: "…", outcomes: [{ value: "approved" }] }, // or { id }
name: "Policy A",
document: { blob: pdf, filename: "policy.pdf" },
});
const model = await client.flows.ensureDecisionModel(policy.id); // latest success, or generate + wait
const evaluation = await client.flows.evaluateCase({ policyId: policy.id, documents: [casePdf] });
const child = await client.flows.reEvaluateAndWait(evaluation.id, { overrides: { amount: { value: 2 } } });
const { decisionModel: stored, evaluation: result } = await client.flows.evaluateWithModel({
policyId: policy.id,
model: decisionModel, // stored as a new success revision first
parameters: { amount: { value: 1200 } },
});A flow never rolls back. When a step fails after an earlier one had side
effects, it rejects with PolicyEngineFlowError: completed holds the records
that exist (profile, policy, generation, decisionModel, evaluation),
step names the failed step and cause is the step's own error (a
PolicyEngineError, a PolicyEngineTimeoutError or an abort). A failure of
the first step rejects with that error directly.
Response metadata
The default surface returns plain data. client.withMeta has the same
resources returning { data, meta }, where meta carries the status, the
response headers and the correlation id. client.request() sends any method
and path under the versioned base and returns { data, meta }.
Responses are never validated or converted: a document comes back exactly as the service stores it, so unknown fields survive a read-modify-write.
Errors
Every non-2xx answer rejects with a PolicyEngineError (status, code,
message, correlationId, details). Subclasses for the cases callers branch
on: PolicyEngineValidationError (issues), UnauthorizedError,
ForbiddenError (403, access denied, e.g. to the folder), NotFoundError,
ConflictError, UnsupportedApiVersionError (supportedVersions),
TooManyRequestsError (retryAfterMs), ServiceUnavailableError (503,
including when folder access could not be verified; retry),
MalformedResponseError,
PolicyEngineTimeoutError. Network failures propagate as the fetch errors
they are. isPolicyEngineError(err) narrows.
Documents, types and schemas
DecisionModel, Outcomes, Parameters, ParameterOverrides, Reasoning
and their parts are exported as TypeScript types and as zod schemas
(decisionModelSchema, reasoningSchema, …). POLICY_ENGINE_API_VERSION
is the API version these map to.
import { validateDecisionModel, safeValidateDecisionModel } from "@uipath/vs-policy-engine";
const model = validateDecisionModel(candidate); // throws DecisionModelValidationErrorvalidateDecisionModel accepts exactly what POST /decision-models accepts:
the v1 schema plus the reserved top-level keys (schemaVersion, kind)
rejected. checkDecisionModelReferences(model) reports dangling condition and
rule references, duplicate ids, rule cycles and outcome mismatches the schema
cannot express; it never throws.
