@molecule/api-ai-decisions-jev
v1.1.1
Published
Jev decisions provider for molecule.dev — typed choice/score/yes-no answers from TypeSafe's hosted Jev System One API
Maintainers
Readme
@molecule/api-ai-decisions-jev
Jev decisions provider for molecule.dev — typed decisions from TypeSafe AI's hosted Jev "System One" model.
Jev answers choice, score and yes/no questions about text or JSON with a
probability distribution instead of generated text. This bond calls
POST https://api.typesafe.ai/v1/systemone with your TYPESAFE_API_KEY.
The open-weights Laya server speaks the same protocol, so
@molecule/api-ai-decisions-laya is a drop-in self-hosted swap.
Auto-generated, AI-first package reference for the molecule.dev ecosystem. It is written to be read by coding agents as much as by people, and is generated from this package's source — edit
src/index.tsJSDoc, not this file.
Quick Start
import { setProvider, requireProvider } from '@molecule/api-ai-decisions'
import { provider } from '@molecule/api-ai-decisions-jev'
setProvider(provider) // reads TYPESAFE_API_KEY on first use
const { answers } = await requireProvider().decide({
state: { from: '[email protected]', body: 'Your app deleted my notes!!' },
questions: {
severity: {
type: 'score',
instructions: 'How severe is the problem?',
criteria: ['cosmetic', 'annoying', 'blocking', 'data loss'],
},
churnRisk: { type: 'yesNo', instructions: 'The customer is likely to cancel.' },
},
})
answers.severity.level // 3
answers.churnRisk.probability // 0.81Type
provider
Installation
npm install @molecule/api-ai-decisions-jev @molecule/api-ai-decisions @molecule/api-secretsAPI
Interfaces
JevConfig
Configuration for the Jev decisions provider.
interface JevConfig {
/** TypeSafe API key. Defaults to the `TYPESAFE_API_KEY` env var (the name TypeSafe's own SDKs read). */
apiKey?: string
/**
* Extra request headers, resolved before each call and merged over the
* defaults — for a host whose auth expires or is not a bearer token (a Cloud
* Run ID token, Modal proxy auth). Pair with `@molecule/api-model-hosting`:
* `headers: () => hosting.authHeaders(endpoint.id)`.
*/
headers?: () => Record<string, string> | Promise<Record<string, string>>
/**
* API base URL. Defaults to `TYPESAFE_BASE_URL`, then `https://api.typesafe.ai`.
* Point it at a gateway that relays `/v1/systemone` (or at a `laya-serve`
* host — same protocol) without changing code.
*/
baseUrl?: string
/** Default model id. Defaults to `'jev-latest'`. */
model?: string
}WireQuestion
One question as sent on the wire.
interface WireQuestion {
type: 'choice' | 'score' | 'noul'
instructions: string
criteria?: Record<string, string> | string[]
}WireAnswer
One answer as received on the wire (only the fields we read).
interface WireAnswer {
type?: string
choice?: string
score?: number
noul?: number
probabilities?: Record<string, number>
}WireResponse
The response body (only the fields we read).
interface WireResponse {
model?: string
answers?: Record<string, WireAnswer>
usage?: { input_tokens?: number; output_tokens?: number }
}PostOptions
Options for {@link postSystemOne}.
interface PostOptions {
/** Full endpoint URL. */
url: string
/** Bearer token, if any. */
apiKey?: string
/** Extra headers resolved before the request (merged over the defaults). */
headers?: () => Record<string, string> | Promise<Record<string, string>>
/** Request body. */
body: Record<string, unknown>
/** Abort signal. */
signal?: AbortSignal
/** Label for error messages (`'Laya'`, `'Jev'`). */
label: string
/** Max retries on a retryable status (default 3). */
maxRetries?: number
}Functions
createProvider(config)
Creates a Jev decisions provider.
function createProvider(config?: JevConfig): AIDecisionsProviderconfig— API key, base URL and default model.
Returns: An AIDecisionsProvider backed by TypeSafe's Jev API.
toWireQuestions(questions)
Converts the core's questions into wire questions (yesNo → noul).
function toWireQuestions(questions: Record<string, DecisionQuestion>): Record<string, WireQuestion>questions— The questions keyed by id.
Returns: The wire questions object.
fromWireAnswer(id, question, wire, minConfidence)
Converts one wire answer into the core's answer for question.
function fromWireAnswer(
id: string,
question: DecisionQuestion,
wire: WireAnswer | undefined,
minConfidence?: number,
): DecisionAnswerid— The question id (for error messages).question— The question that was asked.wire— The wire answer.minConfidence— Optional low-confidence threshold.
Returns: The typed answer.
fromWireResponse(questions, body, minConfidence)
Converts a whole wire response into the core's result.
function fromWireResponse(questions: Q, body: WireResponse, minConfidence?: number): DecideResult<Q>questions— The questions that were asked.body— The parsed response body.minConfidence— Optional low-confidence threshold.
Returns: The typed result.
postSystemOne(opts)
POSTs a /v1/systemone request with retry on 429/5xx-busy, honouring
Retry-After. Throws an Error carrying status on a non-2xx response.
function postSystemOne(opts: PostOptions): Promise<WireResponse>opts— Request options.
Returns: The parsed response body.
Constants
DEFAULT_JEV_URL
TypeSafe's API host.
const DEFAULT_JEV_URL: 'https://api.typesafe.ai'DEFAULT_JEV_MODEL
TypeSafe's flagship model id.
const DEFAULT_JEV_MODEL: 'jev-latest'provider
The provider implementation — lazy, so env vars are read on first use.
const provider: AIDecisionsProvideraiDecisionsJevSecretDefinitions
Secret definitions required by the Jev decisions bond.
const aiDecisionsJevSecretDefinitions: SecretDefinition[]Core Interface
Implements @molecule/api-ai-decisions interface.
Bond Wiring
Setup function to register this provider with the core interface:
import { setProvider } from '@molecule/api-ai-decisions'
import { provider } from '@molecule/api-ai-decisions-jev'
export function setupAiDecisionsJev(): void {
setProvider(provider)
}Injection Notes
Requirements
Peer dependencies:
@molecule/api-ai-decisions^1.0.0@molecule/api-secrets^1.0.1
Environment Variables
TYPESAFE_API_KEY(required) — TypeSafe API key- Setup: Create an API key in your TypeSafe AI account; it is sent as a bearer token to the Jev API.
- Get it here: https://docs.typesafe.ai/api
- Example:
ts-...
Runtime Dependencies
@molecule/api-ai-decisions@molecule/api-secretsConfig:
TYPESAFE_API_KEY(required — sent asAuthorization: Bearer …),TYPESAFE_BASE_URL(optional; a gateway, or alaya-servehost), andcreateProvider({ model })(default'jev-latest', or passmodelper call).Limits (TypeSafe docs): up to 255 options per
choice, 2–10 levels perscore. 429 (rate limit) and 529 (overloaded) are retried up to 3 times with backoff; 401 and 422 throw immediately with the API's message and astatusproperty.English-first. TypeSafe describes English as Jev's primary training language; for other languages evaluate carefully or use Laya's multilingual checkpoint.
Your data leaves your servers (TypeSafe processes the
state). For data that must stay in your environment, bond the Laya provider instead.confidencein the answers is the probability of the reported answer, NOT Jev's ownconfidencefield (see the core's remarks).Hosted on rented compute? Pass
headers: () => hosting.authHeaders(endpoint.id)(@molecule/api-model-hosting) when the host's auth expires or is not a bearer token — e.g. a Cloud Run ID token or Modal proxy auth. It runs before every request and is merged over the defaults.Use the core's
setProvider, notbond('ai-decisions', …)directly.
E2E Tests
Integration checklist — drive the real UI (live preview, no mocks), adapt each item to this app's actual screens/flows, and check every box off one by one. A box you can't check is an integration bug to fix — not a skip:
- [ ] Each flow that makes a decision (routing, triage, moderation, a guardrail) runs it from the real UI, and the answer DRIVES what happens next (the item lands in the chosen queue, the badge shows, the action is blocked) — not just printed.
- [ ] Both directions: a clearly-billing input routes to billing AND a clearly-technical one routes elsewhere. One label for every input is a broken integration.
- [ ] A low-confidence answer takes the app's fallback path (human review, "unsure" state) instead of being acted on.
- [ ] Provider errors (service down, bad key) show a visible, recoverable state — never a blank screen or an unhandled rejection.
- [ ] The call runs server-side: no provider request or key in the browser's Network tab.
