{"ref":"artifact:hendrik77-cap-decisions","page":"/artifacts/hendrik77-cap-decisions","json":"/artifacts/hendrik77-cap-decisions.json","generated":"2026-10-29","drafted_with_ai":true,"entity":{"id":"hendrik77-cap-decisions","name":"cap-decisions","artifact_type":"cds-plugin","ecosystem":"cap","domain":"ai-and-agents","secondary_domains":["integration-and-messaging"],"origin_ring":"independent","use_as":"dependency","source_available":true,"description":{"one_line":"Adds a `decisions` service to a CAP Node.js application that answers typed questions about one text or JSON state through an HTTP decision endpoint.","short":"CAP service for typed decisions about one text or JSON state","what_it_solves":"Adds a `decisions` required service to a CAP Node.js application: `cds.connect.to('decisions')` returns a client whose `decide()` call sends one text or JSON state and a map of named `choice`, `score` and `noul` questions to an HTTP endpoint that speaks the Jev protocol, and gets one typed answer per question back with its probabilities and a confidence value. Which endpoint that is comes from a kind under `cds.requires.decisions`, one per provider: [TypeSafe System One](external:typesafe-system-one), [SubQ Snap](https://docs.subq.ai/endpoints/decisions-api/), the [clef](https://developers.cloudflare.com/workers-ai/models/clef/) model on Cloudflare Workers AI, a [Laya](https://github.com/WhoIsMrSentry/laya-system-one) server, or any Jev-compatible URL under the generic kind. `cds add decisions` writes that choice into a CAP profile. In TypeScript the choice labels are inferred from the criteria keys, so the selected label is typed as a union of those keys and a handler map that misses one does not compile. In the `development` and `test` profiles an application without an explicit kind gets `decisions-mock`, which answers in-process from fixtures without a server, a token or network access, and `npx cap-decisions-mock` serves the same answers over HTTP. The package serves no service of its own: it creates no OData endpoint and produces no text, and the action that calls `decide()`, with the `@requires` that protects it, belongs to the application.","when_not_to_use":"CAP Java is outside it: the plugin is written for CAP Node.js applications, and `cds add decisions` prints a message and writes nothing in a Java project. A decision needs an answer, so the service cannot be queued: a truthy `queued`, `outboxed` or `outbox` setting fails with `INVALID_CONFIG`, which rules out handing a call to the outbox. The package is not yet on npm, so it is installed from a GitHub release archive, and the subclass hooks, the HTTP mock server, the `cds add` facet and the provider test kit are marked experimental.","to_build_on_it":"A provider is added at one of three levels: a kind in the application's `package.json` for a server that already speaks the Jev protocol, a `DecisionsService` subclass named by a kind's `impl` for a protocol that differs, or a provider package that ships both and whose kind is selectable with `cds add decisions --kind`. One call of `cap-decisions/testing` registers the checks every kind must pass as `node:test` tests, which is what a provider package runs instead of copying the plugin's own tests. The subclass hooks are experimental until the first npm publication, so a provider written against them may have to follow a change."},"links":{"repo":"https://github.com/hendrik77/cap-decisions","docs":"https://github.com/hendrik77/cap-decisions#readme","changelog":"https://github.com/hendrik77/cap-decisions/blob/main/CHANGELOG.md","issues":"https://github.com/hendrik77/cap-decisions/issues"},"identity":{"author":"hendrik77","license":"MIT"},"maintainers":["actor:hendrik77"],"compat":{"runtimes":["node"],"cds_range":"^9 || ^10","typed":true},"provides":[{"capability":"capability:llm-integration","what_it_does":"Calls a decision model over HTTP from a CAP handler with the endpoint and the credentials kept in CAP's configuration: the kind carries the URL, the `modelId` that is sent as `model` and the request limits, the token comes from a secret source or from a BTP destination, and the plugin does the timeout, the retries on 429, 502, 503, 504 and 529, and the error codes. What comes back is one typed answer per named question: a choice label with a probability per key, a score with its legend, or the probability that a yes/no answer is true. There is no text to parse.","facets":[{"key":"model_access","value":"Other providers","source":{"url":"https://github.com/hendrik77/cap-decisions","title":"hendrik77/cap-decisions — README, what it talks to","checked":"2026-10-29","quote":"It works with any HTTP endpoint that speaks the Jev protocol (the request and response schema of TypeSafe's System One API), and with providers whose protocol differs through a subclass."},"sources":[{"url":"https://github.com/hendrik77/cap-decisions","title":"hendrik77/cap-decisions — README, provider kinds","checked":"2026-10-29","quote":"Select a provider kind under `cds.requires.decisions` with its full name; `cds add decisions` writes this for a profile (see [Set up with `cds add decisions`](#set-up-with-cds-add-decisions))."}],"applies_to":{"ecosystems":["cap"]}}],"sources":[{"url":"https://github.com/hendrik77/cap-decisions","title":"hendrik77/cap-decisions — README, opening","checked":"2026-10-29","quote":"It evaluates `choice`, `score`, and `noul` questions against one text or JSON state, using a decision model such as Jev, Laya or Clef."},{"url":"https://github.com/hendrik77/cap-decisions","title":"hendrik77/cap-decisions — README, credentials","checked":"2026-10-29","quote":"When `true`, connecting fails with `INVALID_CONFIG` unless a `credentials.token` is set, or a `credentials.destination` that supplies an `Authorization` header"},{"url":"https://github.com/hendrik77/cap-decisions","title":"hendrik77/cap-decisions — README, retries","checked":"2026-10-29","quote":"HTTP 429, 502, 503, 504 and 529, and network failures (including interrupted response bodies), are retried at most twice, honoring `Retry-After` or using jittered backoff."}]},{"capability":"capability:service-integration","what_it_does":"Puts a remote decision endpoint behind a CAP service: the kind holds its URL and limits, `cds.connect.to('decisions')` checks the configuration and rejects an invalid one with `INVALID_CONFIG`, and `decide()` sends an internal CAP `decide` event that an application can hang `before` and `after` handlers on. For work off the network it ships a mock: `decisions-mock` is the kind an application without an explicit one gets in the `development` and `test` profiles, answering in-process from fixtures in `test/data/decisions.json`, with `latencyMs` and `fail` to simulate a slow or failing provider, and `npx cap-decisions-mock` serves the same answers over HTTP so retries, timeouts and tokens are exercised too.","facets":[{"key":"protocols","value":["http"],"source":{"url":"https://github.com/hendrik77/cap-decisions","title":"hendrik77/cap-decisions — README, endpoint","checked":"2026-10-29","quote":"It works with any HTTP endpoint that speaks the Jev protocol (the request and response schema of TypeSafe's System One API), and with providers whose protocol differs through a subclass."},"applies_to":{"ecosystems":["cap"]}}],"sources":[{"url":"https://github.com/hendrik77/cap-decisions","title":"hendrik77/cap-decisions — README, the decide event","checked":"2026-10-29","quote":"`decide()` sends an internal CAP `decide` event. Applications can register `before` and `after` handlers on the connected service."},{"url":"https://github.com/hendrik77/cap-decisions","title":"hendrik77/cap-decisions — README, local development","checked":"2026-10-29","quote":"In the `development` and `test` profiles, an application without an explicit `kind` gets the `decisions-mock` kind. It answers in-process, deterministically and without a server, a token or network access, so `cds watch`, `cds serve` and `cds.test` work out of the box."},{"url":"https://github.com/hendrik77/cap-decisions","title":"hendrik77/cap-decisions — README, HTTP mock server","checked":"2026-10-29","quote":"It gives the same answers as the in-process mock over HTTP."}]}],"requires":[{"ref":"artifact:sap-cds","requirement":"required","basis":"binding","role":"framework","for":"The framework it extends: CAP loads the package's `cds-plugin.js` and adds the `decisions` required service, which the application reaches with `cds.connect.to('decisions')`. The peer range is `^9 || ^10`.","sources":[{"url":"https://github.com/hendrik77/cap-decisions","title":"hendrik77/cap-decisions — README, requirements","checked":"2026-10-29","quote":"Requirements: Node.js 22 or newer and `@sap/cds` 9 or 10 (the peer range is `^9 || ^10`)."},{"url":"https://github.com/hendrik77/cap-decisions","title":"hendrik77/cap-decisions — README, plugin loading","checked":"2026-10-29","quote":"CAP loads the package's `cds-plugin.js` and adds the `decisions` required service."}]},{"ref":"artifact:sap-cds-dk","requirement":"conditional","basis":"binding","role":"command-line host","condition":"`cds add decisions` is used to write the configuration; without it the same entries are written by hand.","for":"The `cds add decisions` facet runs inside CAP's `cds add` command, so it needs the development kit; the package itself does not depend on it.","sources":[{"url":"https://github.com/hendrik77/cap-decisions","title":"hendrik77/cap-decisions — README, cds add","checked":"2026-10-29","quote":"The `cds add decisions` command (see below) needs `@sap/cds-dk` 9 or 10, like every `cds add`; the package itself does not depend on it."},{"url":"https://github.com/hendrik77/cap-decisions","title":"hendrik77/cap-decisions — README, by hand","checked":"2026-10-29","quote":"Without `@sap/cds-dk`, write the same by hand."}]},{"ref":"artifact:sap-cloud-sdk-connectivity","requirement":"conditional","basis":"binding","role":"destination resolver","condition":"`credentials.destination` names a Destination service entry instead of a `url` and a `token`.","for":"Resolving the named destination: the optional peer package is installed in the CAP application, and the plugin calls its `getDestination()`.","sources":[{"url":"https://github.com/hendrik77/cap-decisions","title":"hendrik77/cap-decisions — README, destinations","checked":"2026-10-29","quote":"Install the optional peer package `@sap-cloud-sdk/connectivity` in the CAP application."}]},{"ref":"artifact:btp-destination","requirement":"conditional","basis":"binding","role":"endpoint and header source","condition":"`credentials.destination` is set instead of `url` and `token`.","for":"Holds the full POST endpoint and the static `Authorization` header for the provider, so neither is in the application's configuration. The entry is a `NoAuthentication` destination with a `URL.headers.Authorization` property; other destination authentication flows are outside the integration's scope.","sources":[{"url":"https://github.com/hendrik77/cap-decisions","title":"hendrik77/cap-decisions — README, destinations","checked":"2026-10-29","quote":"On SAP BTP, you can set `credentials.destination` to the name of a Destination service entry instead of supplying `url` and `token`."},{"url":"https://github.com/hendrik77/cap-decisions","title":"hendrik77/cap-decisions — README, destination scope","checked":"2026-10-29","quote":"This integration reads the destination URL and static headers; other destination authentication flows are outside its scope."}]},{"ref":"external:typesafe-system-one","requirement":"conditional","basis":"binding","role":"decision provider","condition":"The `decisions-typesafe` kind is selected.","for":"The endpoint the kind posts to, `https://api.typesafe.ai/v1/systemone`, with the `jev-latest` model and a token the kind requires.","sources":[{"url":"https://github.com/hendrik77/cap-decisions","title":"hendrik77/cap-decisions — README, kinds table","checked":"2026-10-29","quote":"| `decisions-typesafe` | `https://api.typesafe.ai/v1/systemone` | `jev-latest` | `true` | `choiceOptions`: 255; `scoreCriteria`: 2 to 10 |"}]}],"connects":[{"ref":"external:typesafe-system-one","kind":"data","direction":"outbound","style":"sync","condition":"The `decisions-typesafe` kind is selected.","for":"Posts the state and the questions to `https://api.typesafe.ai/v1/systemone` with `jev-latest` as the model and a bearer token, and reads the typed answers back.","sources":[{"url":"https://github.com/hendrik77/cap-decisions","title":"hendrik77/cap-decisions — README, kinds table","checked":"2026-10-29","quote":"| `decisions-typesafe` | `https://api.typesafe.ai/v1/systemone` | `jev-latest` | `true` | `choiceOptions`: 255; `scoreCriteria`: 2 to 10 |"},{"url":"https://github.com/hendrik77/cap-decisions","title":"hendrik77/cap-decisions — README, the Jev protocol","checked":"2026-10-29","quote":"It works with any HTTP endpoint that speaks the Jev protocol (the request and response schema of TypeSafe's System One API), and with providers whose protocol differs through a subclass."}]},{"ref":"artifact:btp-destination","kind":"data","direction":"outbound","condition":"`credentials.destination` is set.","for":"Reads the destination's URL and static headers to reach the provider: the plugin resolves it when the service is created and again for each call, and a destination that is not found, or that carries a bad URL or bad headers, fails the connection.","sources":[{"url":"https://github.com/hendrik77/cap-decisions","title":"hendrik77/cap-decisions — README, destination resolution","checked":"2026-10-29","quote":"The plugin resolves the destination with `getDestination()` when the service is created and for each call; it uses the SDK's cache."},{"url":"https://github.com/hendrik77/cap-decisions","title":"hendrik77/cap-decisions — README, destination failures","checked":"2026-10-29","quote":"A destination that is not found, or that has a bad URL or bad headers, still fails the connection."}]}],"interfaces":[{"key":"decisions-service","name":"the `decisions` service","kind":"api","direction":"in","for":"Connecting with `cds.connect.to('decisions')` and calling `decide()` with a state and named questions. The call is an internal CAP `decide` event, so an application can register `before` and `after` handlers on the connected service, and `{ signal }` cancels a call.","url":"https://github.com/hendrik77/cap-decisions#install-and-use","sources":[{"url":"https://github.com/hendrik77/cap-decisions","title":"hendrik77/cap-decisions — README, the decide event","checked":"2026-10-29","quote":"`decide()` sends an internal CAP `decide` event. Applications can register `before` and `after` handlers on the connected service."},{"url":"https://github.com/hendrik77/cap-decisions","title":"hendrik77/cap-decisions — README, no service of its own","checked":"2026-10-29","quote":"`cap-decisions` serves no service of its own."}]}],"provenance":{"discovered_via":[{"source":"source:github","channel":"hendrik77/cap-decisions"}],"first_seen":"2026-10-29"},"drafted_with_ai":true},"effective_normative_relations":[{"instrument":"instrument:sap-developer-license-3-2-cap","relation":"use-constrained-by","sections":["1","2","3"],"applies_when":"A cds-plugin is used with SAP CAP materials, or an artifact is explicitly identified as a CAP plugin or application.","note":"This is inherited applicability, not a licence verdict about the artifact itself. Review the agreement for the actual materials and use; an explicit artifact relationship to another revision takes precedence.","scope":{"kind":"artifact"},"sources":[{"url":"https://cap.cloud.sap/resources/license/developer-license-3_2_CAP.txt","title":"SAP Developer License Agreement 3.2 CAP","checked":"2026-09-16","quote":"documentation, plug-ins, templates, scripts and sample code, libraries, software development kits"}],"inherited_from":"cap-plugins-and-applications","relevant_capabilities":["agent-systems-access","async-processing","data-import-export","database-connectors","deployment","destinations","llm-integration","mcp-servers","plugin-authoring","replication","retrieval-augmented-generation","rfc-connectivity"]}],"readings":{"liveness":[{"label":"Maintenance","tier":"unknown","evidence":"not crawled"},{"label":"Continuity","tier":"unknown","evidence":"not crawled"},{"label":"Repository","tier":"unknown","evidence":"not crawled"}],"compatibility":[{"label":"Declared for","tier":"fair","evidence":"^9 || ^10 — cds 9 only, in maintenance until 2027-06"},{"label":"Survived majors","tier":"unknown","evidence":"no release dates"},{"label":"Maintainer's CI","tier":"unknown","evidence":"not crawled"}],"practice":[{"label":"Tests","tier":"unknown","evidence":"not crawled"},{"label":"Docs","tier":"unknown","evidence":"docs link declared, tree not read"},{"label":"Changelog","tier":"unknown","evidence":"not crawled"}],"reach":[{"value":null,"unit":"installs/week"},{"value":null,"unit":"watching"}]},"signals":null,"edges":{"maintainers":[{"ref":"actor:hendrik77","name":"Hendrik Neumann","json":"/actors/hendrik77.json"}],"contributors":[],"explained_by":[],"alternative_to_this":[],"needed_by":[],"available_via":[],"parts":[],"add_on_to":{"ref":"artifact:sap-cds","name":"@sap/cds","json":"/artifacts/sap-cds.json"},"add_ons":[],"answered_through_parts":[]}}