npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@molecule/api-ai-decisions-intern-decision

v1.1.2

Published

Intern-Decision decisions provider for molecule.dev — typed choice/score/yes-no answers about text and images from the open-weights Intern-Decision models on your own server

Readme

@molecule/api-ai-decisions-intern-decision

Intern-Decision decisions provider for molecule.dev — typed decisions about text AND images from the open-weights Intern-Decision models on a server you run.

Intern-Decision (github.com/internlm/Intern-Decision, from InternLM) is a family of Qwen3.5 fine-tunes — 0.8B, 2B and 4B — that answer choice, score and yes/no questions with a probability per option, and can read up to 8 images alongside the text (a screenshot, a photo, a scanned form). Its maker reports 90.0% average accuracy for the 4B (44 ms/request) and 84.7% for the 2B (33 ms on an RTX 4090). This bond speaks the service's POST /v1/decisions route; the question and answer shapes match the Jev / Laya / Jeff bonds, so swapping is a one-line change.

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.ts JSDoc, not this file.

Quick Start

# Run the service on a GPU host (it binds 127.0.0.1:7860 and has NO auth)
git clone https://github.com/internlm/Intern-Decision && cd Intern-Decision
python -m venv .venv && . .venv/bin/activate
pip install -r requirements-inference.txt
MODEL_CHECKPOINT=/models/Intern-Decision-2B bash scripts/demo.sh
import { readFileSync } from 'node:fs'

import { setProvider, requireProvider } from '@molecule/api-ai-decisions'
import { provider } from '@molecule/api-ai-decisions-intern-decision'

setProvider(provider) // reads INTERN_DECISION_URL (+ INTERN_DECISION_API_KEY for a proxy) on first use

const { answers } = await requireProvider().decide({
  state: 'A screenshot of the app preview after deploy.',
  images: [{ mimeType: 'image/png', data: readFileSync('preview.png').toString('base64') }],
  questions: {
    blank: { type: 'yesNo', instructions: 'The page is blank or shows only an error.' },
    layout: {
      type: 'choice',
      instructions: 'What does the page show?',
      criteria: { landing: 'a marketing page', app: 'an app screen', error: 'an error page' },
    },
  },
})
answers.blank.probability // 0.04
answers.layout.choice // 'landing'

Type

provider

Installation

npm install @molecule/api-ai-decisions-intern-decision @molecule/api-ai-decisions @molecule/api-secrets

API

Interfaces

InternDecisionConfig

Configuration for the Intern-Decision decisions provider.

interface InternDecisionConfig {
  /**
   * Base URL of the Intern-Decision service (or of an authenticating proxy in
   * front of it). Defaults to `INTERN_DECISION_URL`, then `http://127.0.0.1:7860`.
   */
  baseUrl?: string
  /**
   * Bearer token for a proxy in front of the service. The service itself has
   * no authentication. Defaults to the `INTERN_DECISION_API_KEY` env var.
   */
  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>>
}

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 postDecisions}.

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 (`'Intern-Decision'`). */
  label: string
  /** Max retries on a retryable status (default 3). */
  maxRetries?: number
}

Functions

createProvider(config)

Creates an Intern-Decision decisions provider.

function createProvider(config?: InternDecisionConfig): AIDecisionsProvider
  • config — Base URL and optional proxy API key.

Returns: An AIDecisionsProvider backed by an Intern-Decision service.

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,
): DecisionAnswer
  • id — 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<Q extends Record<string, DecisionQuestion>>(
  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.

postDecisions(opts)

POSTs a decision request with retry on 429/5xx-busy, honouring Retry-After. Throws an Error carrying status on a non-2xx response.

function postDecisions(opts: PostOptions): Promise<WireResponse>
  • opts — Request options.

Returns: The parsed response body.

Constants

DEFAULT_INTERN_DECISION_URL

The service's default bind (scripts/demo.sh: DEMO_HOST 127.0.0.1, DEMO_PORT 7860).

const DEFAULT_INTERN_DECISION_URL: 'http://127.0.0.1:7860'

INTERN_DECISION_LIMITS

The service's request limits (src/inference/pipeline.py, src/service/uploads.py).

const INTERN_DECISION_LIMITS: {
  readonly maxQuestions: 16
  readonly maxOptions: 62
  readonly maxImages: 8
  readonly maxImageBytes: number
  readonly maxTotalImageBytes: number
}

INTERN_DECISION_IMAGE_TYPES

Image media types the service decodes (GIFs must be still).

const INTERN_DECISION_IMAGE_TYPES: readonly string[]

provider

The provider implementation — lazy, so env vars are read on first use.

const provider: AIDecisionsProvider

aiDecisionsInternDecisionSecretDefinitions

Secret definitions used by the Intern-Decision decisions bond.

const aiDecisionsInternDecisionSecretDefinitions: 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-intern-decision'

export function setupAiDecisionsInternDecision(): void {
  setProvider(provider)
}

Injection Notes

Requirements

Peer dependencies:

  • @molecule/api-ai-decisions ^1.1.0
  • @molecule/api-secrets ^1.0.1

Environment Variables

  • INTERN_DECISION_URL (optional) — Intern-Decision server URL
    • Setup: The base URL of your Intern-Decision service (clone github.com/internlm/Intern-Decision, pip install -r requirements-inference.txt, set MODEL_CHECKPOINT, then bash scripts/demo.sh), or of an authenticating proxy in front of it. Defaults to http://127.0.0.1:7860.
    • Get it here: https://github.com/internlm/Intern-Decision#readme
    • Example: http://127.0.0.1:7860
  • INTERN_DECISION_API_KEY (optional) — Intern-Decision proxy API key

Runtime Dependencies

  • @molecule/api-ai-decisions

  • @molecule/api-secrets

  • The service has NO authentication and binds 127.0.0.1 by default. Never publish its port: reach it over a private network, or put an authenticating reverse proxy in front and set INTERN_DECISION_API_KEY (sent as Authorization: Bearer … — the service itself ignores it).

  • Default port is 7860, not 8000: INTERN_DECISION_URL defaults to http://127.0.0.1:7860.

  • One checkpoint per server; model is ignored. The service answers with whatever MODEL_CHECKPOINT it loaded (result.model is always 'intern-decision'). Run a second server for a second size.

  • Limits (checked here before sending, else a 422): 1–16 questions per request, 1–62 options per choice or levels per score, up to 8 images of PNG / JPEG / WebP / still GIF, each ≤12 MB decoded and ≤32 MB total (and ≤16 million pixels — checked by the server only). images[].data is raw base64 — no data: prefix.

  • Input is capped at 8,192 tokens by default (MAX_INPUT_LENGTH on the server). Put the decisive text first.

  • Requests are serialized on the server (one model lock); concurrent calls queue rather than fail. A loading server answers 503; this bond retries 429/502/503/504/529 up to 3 times. Errors carry the HTTP status.

  • Calibration: each checkpoint ships a fitted temperature (2B: 2.1), applied only when the server is configured with its calibration file — and the HF and XTuner backends give slightly different probabilities. Calibrate on labelled samples of your inputs and gate on minConfidence.

  • Not a chat model and does not reason. It picks among the options you describe; the service's optional "thinking" handoff to an external LLM is not used by this bond.

  • License: the code is Apache-2.0; the weights' Hugging Face cards say Apache-2.0 while the repo README says Qwen model terms apply — check LICENSE-QWEN before offering it to third parties.

  • 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, not bond('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.