# @agentrun/jev

Optional [TypeSafe Jev](https://docs.typesafe.ai/) support for AgentRun DSL. Jev answers focused questions with typed values and probability distributions. The workflow decides how to use them.

Requires Node.js 22.19 or later. This is a public-beta release candidate; package publication is pending.

After publication to npm:

```sh
npm install @agentrun/dsl @agentrun/jev
export TYPESAFE_API_KEY="your-key"
```

```ts
import { createJevRunner } from '@agentrun/jev';

const runJudge = createJevRunner();
// Supply runJudge alongside your other runWorkflow dependencies.
const result = await runJudge({
  label: 'triage',
  kind: 'judge',
  state: { ticket: 'I was charged twice.' },
  questions: {
    team: {
      type: 'choice',
      instructions: 'Which team should handle this ticket?',
      criteria: { billing: 'Invoices, payments, or refunds', other: 'Everything else' },
    },
  },
});
console.log(result.answers.team);
```

`judge`, `pick`, `sift`, `route`, semantic predicates, and judgment verification use the same `runJudge` adapter. Choice, Noul, and Score answers retain their raw probabilities. The core validates answer IDs, probability keys and normalization, score rubrics, and value ranges before consuming a result. A typed answer remains a model judgment, not proof that a real-world claim is true.

`System One` is TypeSafe's typed-question interface, exposed by the SDK as `systemOne`. A **Noul** answer is a truth probability from 0 to 1; the DSL converts probabilities of at least 0.5 to `true` and retains the probability beside that value. Choice and Score confidence comes from the response. Jev does not return a separate confidence for Noul; the DSL derives its own gate-strength value from the distance from 0.5, scaled to 0–1. These numbers are useful gate inputs, not calibrated guarantees.

The public adapter API is `createJevRunner`, `JevError`, and the types `JevOptions`, `JevClient`, `JevErrorCode`. The shared question, answer and distribution helpers live in `@agentrun/dsl`.

## Configuration

```ts
const controller = new AbortController();
const runJudge = createJevRunner({
  timeoutMs: 30_000,       // Total budget, including retry waits.
  maxAttempts: 3,         // Includes the first attempt; maximum 10.
  retryBaseMs: 500,
  retryMaxMs: 5_000,
  signal: controller.signal,
});
```

The official `@typesafe-ai/sdk` resolves `TYPESAFE_API_KEY` and `TYPESAFE_BASE_URL`. Explicit `apiKey` and `baseURL` options take precedence. An API root ends before `/v1/systemone`. Set `fetch` for a custom transport, or supply a `client` with a `systemOne(request, options)` method. A custom client must honor the request signal and disable its own retries; it owns its credentials and cannot be combined with transport options.

The adapter owns retries: transient HTTP 408, 429, 5xx responses and connection failures retry with bounded exponential delays. SDK retries are disabled. Validation failures and other HTTP errors do not retry. The deadline and either the runner or per-call signal interrupt both requests and backoff. Cancellation bounds when the adapter returns; an uncooperative custom client can still continue its own work.

Request state is limited to 48 KiB of serialized UTF-8 JSON. The core allows up to 240 options per choice and 2–10 levels per score rubric. Adapter timeouts are positive integer milliseconds up to 2,147,483,647; retry delays may also be zero. `maxAttempts` is 1–10, with a default of 3.

`JevError` provides a stable `code`, `attempts`, and optional HTTP `status`. Errors deliberately omit raw service bodies, headers, input state, and causes. SDK logging is disabled. Custom clients and transports own their own logging. Do not expose credentials in browser code.

Successful results retain `answers`, reported `model`, reported token `usage`, and a SHA-256 of the submitted request. `cost_usd` is `null` unless both usage and explicit `pricing: { inputUsdPerMillionTokens, outputUsdPerMillionTokens }` are available. Configured prices produce an estimate for the successful response; costs from unsuccessful or interrupted attempts are unknown.

## Offline tests

From the repository root, run `npm run build` and `npm test -w @agentrun/jev`. Tests inject fake HTTP responses and do not load provider credentials or call a model.

## Use Jev from an existing agent loop

The [movie decision tool](../../docs/jev-decisions.md) composes actual `judge`, `route`, `sift`, and `pick` nodes behind one callable function. Register that function as a tool in your existing host. The host keeps the agent loop, tool permissions, and writing; Jev supplies the typed judgments.
