# Chatoyant
[](https://www.npmjs.com/package/chatoyant)
[](https://github.com/Anonyfox/chatoyant/actions/workflows/ci.yml)
[](https://ocaml.org/)
[](https://www.typescriptlang.org/)
[](https://opensource.org/licenses/MIT)
OCaml-first SDK for LLM providers with an Eio native runtime and a
zero-runtime-dependency JavaScript package generated by Melange. Chatoyant
provides typed provider clients, structured outputs, tool calling, streaming,
token/cost accounting, and root-only npm exports.
_chatoyant_ /shuh-TOY-uhnt/ - having a changeable lustre.
## Highlights
- Native OCaml API built around Eio, result-returning calls, `.mli` contracts,
and typed tool definitions.
- Melange-generated npm package with one root import path, ESM and CommonJS
entrypoints, colocated `.d.ts` and `.d.cts` declarations, and no runtime npm
dependencies.
- Unified `Chat` session API, one-shot text/data/stream shortcuts, tool calling,
streaming accumulation, JSON roundtrip, and token/cost accounting.
- Raw provider clients for OpenAI, Anthropic, xAI, Meta (Muse Spark), OpenRouter, and local
OpenAI-compatible servers.
- Standalone Draft 2020-12 JSON Schema parser/validator with OpenAI strict
projection and typed OCaml codec generation.
- Production-derived JS usage tests, OCaml native tests, TypeScript declaration
checks, package metadata checks, and the official JSON Schema suite against
the bundled npm package.
## Package Size Next To Other JS LLM Libraries
Measured on 2026-10-27 with Node v20.19.2 and npm 11.21.1. Each case uses
fresh production installs of registry latest versions. Install sizes count
node_modules file bytes (1 MB = 1024 KB); bundles use a one-request script, esbuild 0.25
(minified ESM for Node 20), and gzip level 9.
| SDK | Versions | Installed packages | node_modules | Minified bundle | Gzip |
| --- | --- | ---: | ---: | ---: | ---: |
| chatoyant | chatoyant@0.16.0 | 1 | 0.6 MB | 215.2 KB | 54.1 KB |
| openai | openai@7.45.0 | 1 | 22.1 MB | 376.5 KB | 83.1 KB |
| @anthropic-ai/sdk | @anthropic-ai/sdk@1.3.0 | 8 | 16.1 MB | 384.6 KB | 91.1 KB |
| ai + @ai-sdk/openai | ai@7.0.154, @ai-sdk/openai@4.0.103 | 12 | 21.9 MB | 885.3 KB | 198.6 KB |
| langchain + @langchain/openai | langchain@1.5.20, @langchain/core@1.3.0, @langchain/openai@1.7.1 | 25 | 76.5 MB | 1495.3 KB | 349.0 KB |
Chatoyant has the smallest install and bundles in this sample; openai ties its
installed package count. The openai and Anthropic cases each cover one provider;
chatoyant includes all six provider adapters plus JSON Schema validation and
token/cost tables. One root import still pulls all adapters into the bundle.
See [Smallest JavaScript LLM SDK: measured sizes](https://anonyfox.github.io/chatoyant/chatoyant/js_llm_sdk_size.html)
for the method, source scripts, measured JSON and a typechecked example.
Rerun with `node scripts/measure-sdk-size.mjs`.
## Provider Routing
| Provider | Env var | Detection |
| --- | --- | --- |
| OpenAI | `OPENAI_API_KEY` | `gpt-*`, `o1-*`, `o3-*`, `o4-*`, `chatgpt-*` |
| Anthropic | `ANTHROPIC_API_KEY` | `claude-*` |
| xAI | `XAI_API_KEY` | `grok-*` |
| Meta | `META_API_KEY` (or `MODEL_API_KEY`) | `muse-*` |
| OpenRouter | `OPENROUTER_API_KEY` | Slash notation such as `openai/gpt-4o` |
| Local | `LOCAL_BASE_URL` | Explicit `provider: "local"` or local fallback |
Model presets are available for quick intent-based calls: `fast`, `cheap`,
`balanced`, `best`, and `reasoning`.
| Preset | OpenAI | Anthropic | xAI | Meta |
| --- | --- | --- | --- | --- |
| fast / cheap | gpt-6-luna | claude-haiku-5-5 | grok-4.20-0309-non-reasoning | muse-spark-1.3 |
| balanced | gpt-6.1-sol | claude-sonnet-5-5 | grok-4.3 | muse-spark-1.3 |
| best / reasoning | gpt-6-astra | claude-fable-5-1 | grok-4.7 | muse-spark-1.3 |
Also recognized: gpt-6.1-terra (text/image input, 1,050,000 context tokens,
128,000 max output tokens), gpt-6-sol, gpt-5.6-cyber, gpt-5.5-cyber, gpt-5.3-codex,
chat-latest, gpt-5-search-api, claude-mythos-5-1, claude-opus-5-5,
claude-opus-5, grok-4.6, grok-build-0.1, muse-spark-1.3-contributor,
muse-wonder-1.0, grok-imagine-image-2.0, grok-imagine-image-quality,
grok-imagine-video-1.5, and grok-imagine-video-1.5-lite.
OpenAI prices use the short-context tier (up to 272K input tokens); higher
long-context rates are not modelled. GPT-5.6 Sol uses OpenAI's promotional
price, at least through 2026-11-21. Haiku 5.5 prompts above 100K tokens
and Grok Build prompts at or above 200K tokens have higher rates not modelled here.
Retired on first-party APIs (ids still resolve for pricing/detection): claude-opus-4-1, claude-opus-4, claude-sonnet-4, claude-3-5-haiku/claude-3-*; xAI no longer lists grok-4-1-fast-*, grok-code-fast-1, grok-3*, grok-4-0709.
## OCaml Quick Start
```ocaml
open Chatoyant
let () =
Eio_main.run @@ fun env ->
let ai = Chatoyant.openai ~model:"gpt-6-luna" env in
match Chatoyant.gen_text ai "Say hello in three words." with
| Ok text -> print_endline text
| Error err -> prerr_endline (Chatoyant.Error.provider err)
```
Typed tools are ordinary modules. Comments become schema descriptions, `option`
means optional, and the generated `tool` value plugs into a chat.
```ocaml
module%tool Calculate = struct
type operation =
| Add
| Divide
type request = {
operation : operation; (** Operation to apply. *)
values : float list [@min_items 1]; (** Numbers to combine in order. *)
}
type answer = { result : float }
(** Combine numbers with a typed arithmetic operation. *)
let run : request -> (answer, string) result =
fun { operation; values } ->
match operation, values with
| _, [] -> Error "at least one value is required"
| Add, values -> Ok { result = List.fold_left ( +. ) 0. values }
| Divide, first :: rest ->
List.fold_left
(fun acc value -> Result.bind acc (fun n ->
if value = 0. then Error "division by zero" else Ok (n /. value)))
(Ok first) rest
|> Result.map (fun result -> { result })
end
let () =
Eio_main.run @@ fun env ->
let ai =
Chatoyant.openai ~model:"gpt-6-luna" ~tools:[ Calculate.tool ] env
in
ignore (Chatoyant.gen_text ai "Divide 83 by 3.")
```
For the full native guide, see [OCAML.md](OCAML.md).
## JavaScript Quick Start
```ts
import { Chat, Schema, createTool, genData, genStream, genText } from "chatoyant";
const text = await genText("What is 2+2?", {
model: "fast",
system: "Return short answers.",
});
class Person extends Schema {
name = Schema.String({ description: "Person name" });
age = Schema.Integer({ minimum: 0 });
}
const person = await genData("Extract: Alice is 30 years old", Person);
for await (const chunk of genStream("Write a haiku about typed APIs.")) {
process.stdout.write(chunk);
}
const lookup = createTool({
name: "lookup",
description: "Lookup data",
parameters: { q: Schema.String({ minLength: 1 }) },
async execute({ args }) {
return { found: args.q };
},
});
const chat = new Chat({ model: "gpt-4o" });
chat.system("Use tools when useful.").user("Find needle").addTool(lookup);
console.log(await chat.generate());
```
All JavaScript imports come from the package root:
```ts
import { Chat, OpenAI, OpenRouter, Tokens, JsonSchema, genText } from "chatoyant";
```
Former subpath imports from the TypeScript package intentionally move to this
root surface. See [JAVASCRIPT.md](JAVASCRIPT.md).
## Build And Test
From the repository root:
```bash
make build # OCaml + Melange build, then the esbuild npm bundle
make test # native tests, JS parity tests, tsc, and the JSON Schema suite
make check # the full release gate
make help # list all targets
```
`make check` builds and tests the native OCaml package first, emits Melange ESM,
bundles the npm package with esbuild, runs Node's native tests against
`dist/index.js`, checks `dist/index.d.ts` with `tsc`, runs the pinned official
JSON Schema suite through the bundled package, lints opam metadata, checks local
documentation links, verifies package metadata, and dry-packs the npm artifact.
See [CONTRIBUTING.md](CONTRIBUTING.md) for setup, the project layout, and the
release process, and [CHANGELOG.md](CHANGELOG.md) for release history.
## Support
If this package helps your project, consider sponsoring its maintenance:
[GitHub Sponsors](https://github.com/sponsors/Anonyfox).
[Anonyfox](https://anonyfox.com) | [MIT License](LICENSE)