> ## Documentation Index
> Fetch the complete documentation index at: https://docs.obversa.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Jev API Engine

> @obversa/engine-jev-api answers decision questions over recorded run state through the Jev API.

`@obversa/engine-jev-api` is an engine plugin that makes one Jev decision call
per attempt over the TypeSafe API. A Jev call reads structured state your
workflow already recorded and answers the questions you put to it; the adapter
returns those answers as the attempt's structured result.

## Requirements

* Node.js 22.12 or later
* A Jev endpoint and API key, supplied through adapter options

## Install

```bash theme={null}
pnpm add @obversa/engine-jev-api
```

## Request shape

The prompt is a JSON document of the shape `{state, questions}`:

```json theme={null}
{
  "state": { "diff": "..." },
  "questions": {
    "send_back": {
      "type": "noul",
      "instructions": "Should this work be sent back for more iteration?",
      "criteria": {
        "true": "A finding describes incorrect behaviour a user would see",
        "false": "The findings are cosmetic or advisory only"
      }
    },
    "which_stage": {
      "type": "choice",
      "instructions": "Which stage should the work go back to?",
      "criteria": {
        "implement": "The defect is in the code itself",
        "test": "The code is right but the tests do not prove it",
        "none": "Nothing needs to go back"
      }
    },
    "readiness": {
      "type": "score",
      "instructions": "How ready is this change to land?",
      "criteria": ["Unsafe to land", "Needs another round", "Lands clean"]
    }
  }
}
```

`state` is whatever your run recorded. Each entry in `questions` names a type —
`noul`, `choice`, or `score` — with instructions and criteria. `choice`
criteria map each option to its description; `score` criteria are the array of
labels the score indexes; `noul` criteria describe what true and false mean.

The adapter does not validate the answer objects; it returns them unchanged.
The shapes described here are what the provider has been observed to return,
not types the adapter checks: `noul` answers have been observed carrying a
probability with no separate `confidence` field, while `choice` and `score`
answers have been observed carrying a `confidence` (and may carry
`probabilities`).

The adapter validates the document shape — that it parses to an object, that
`questions` is a non-empty object, and that every question names one of the
three types — before any network call. A missing or `null` `state` is sent as
an empty object; `questions` is required. It does not inspect `criteria`;
criteria are forwarded to the provider unchanged. Malformed input fails as
`invalid-config`.

## Usage

```ts theme={null}
import { JevApiEngine } from '@obversa/engine-jev-api';

const apiKey = process.env.TYPESAFE_API_KEY;
if (!apiKey) {
  throw new Error('TYPESAFE_API_KEY is not set');
}

const engine = new JevApiEngine({
  endpoint: 'https://api.typesafe.ai/v1/systemone',
  apiKey,
});
```

The structured result value is the raw `answers` object, so a binding's
`parseResult` reads `part.value.send_back` directly.

## Unsupported requests

These request fields fail as `invalid-config` before any network call:

* `system` or `systemMode` — Jev requests carry no system prompt
* `env` — credentials come from adapter configuration, not the request
* `maxTokens` — Jev has no server-side token cap
* `workspaceMode` other than `none` — Jev performs no filesystem access
* a non-empty `tools` list — the adapter declares no tools

## Limits

* One HTTP request per attempt. The adapter never retries on its own; retry
  safety belongs to the node binding.
* The bearer key comes from adapter configuration at construction; a
  `request.env` field is refused. Provider response data — including error
  bodies — is recorded in the result and in error details.
* `timeoutMs`, plus `timeoutGraceMs` when set, bounds the whole call —
  connection and response body read. Exceeding the deadline fails as
  `timeout`; a caller abort fails as `aborted`.
* `maxOutputBytes`, when supplied on the request, caps the response body the
  adapter reads. It applies only when set and is not a general memory bound.
* A low-confidence answer completes like any other result. Thresholds and
  routing are the caller's policy, not the adapter's.
* When the API does not echo a model — or echoes one that is not readable —
  the recorded effective model and model family are both `null`, and the
  answers are still returned.
