# Frameworks

> LangChain, the Vercel AI SDK, n8n, TanStack AI and Pipecat, each checked against a running server: what to set, and what to know.

Source: https://opendecisio.com/docs/use-from/frameworks/

Five third-party integrations of TypeSafe’s wire format were run against a decisio server (Gemma 4 31B, decisio 0.9.0, from a Mac through an SSH tunnel, 2026-10-08); every check passed. They are plumbing checks: the client sends a request, the server answers, the client parses it. They say nothing about accuracy, and each is written and maintained by someone else.

 

[Figure: Five integrations, each checked against a running server. Five third-party integrations were checked against a decisio server: LangChain (0.0.1a3), 42 of 42 checks passed, base URL has no /v1; Vercel AI SDK (ai 7.0.131, @ai-sdk/typesafe-ai 3.0.15), 42 of 42 checks passed, base URL ends in /v1; n8n (n8n 2.35.7, n8n-nodes-jev 0.2.3), 44 of 44 checks passed, base URL has no /v1; TanStack AI (@tanstack/ai 0.65.1, @tanstack/ai-typesafe 0.1.8), 39 of 39 checks passed, base URL has no /v1; Pipecat (pipecat-ai 1.12.0), 39 of 39 checks passed, base URL has no /v1.]

 

## TL;DR

 

Every integration needs the same three things, in its own spelling:

 

```
base URL   http://127.0.0.1:8000          (the Vercel AI SDK's provider wants http://127.0.0.1:8000/v1)
API key    any string                     (every integration requires one; the server ignores it)
model      decisio-gemma-4-31b-it-letters (the name GET /v1/models lists; the server ignores it)
```

 

A shape to fill in, not a command to run.

  

| Word | Meaning |
| --- | --- |
| integration | a package written and maintained by someone else that speaks System One |
| plumbing check | a run that sends requests and parses answers, to see that the pieces fit; it does not measure accuracy |
| abstention | a server run with `--abstain-option` can answer the best of the other options when its “can’t tell” option is the likeliest; most of the integrations drop the two fields that say so (n8n with Simplify Output off, and Pipecat’s client, pass them through), and that was emulated, not seen on a real abstaining server |

 

Common mistake

Whether the base URL carries `/v1` is the one setting that differs: the Vercel AI SDK’s provider wants it, and the other four append it themselves (adding it to TanStack AI’s adapter posted to `/v1/v1/systemone` and failed with a 404).

 

## 1. LangChain

 

Python 3.12; `langchain-typesafe`, 0.0.1a3: 42 of 42 checks passed against a running server ([the check and its record](https://github.com/aminry/decisio-examples/tree/343691565ad708f99389bc863e3f64c398856fed/integrations/langchain)). It uses TypeSafeClassifier.

  Base URLno /v1: the class appends it; the base_url argument or TYPESAFE_BASE_URL API keyrequired: a dummy one works (ValueError without) If the server answers 422TypeSafeUnprocessableEntityError, status 422, the server's detail on its body; not retried Timeout and retries30 seconds, no retries  

```
from langchain_typesafe import TypeSafeClassifier

classifier = TypeSafeClassifier(base_url="http://127.0.0.1:8000", api_key="unused")
```

 

A shape to fill in, not a command to run.

 

Nothing broke. The class marks itself beta and logs a warning when built. It checks a question before sending (a choice with no options never reaches the server), and it drops the abstention fields, so a caller cannot tell that a server abstained.

 

## 2. Vercel AI SDK

 

Node 22; `ai + @ai-sdk/typesafe-ai`, ai 7.0.131, @ai-sdk/typesafe-ai 3.0.15: 42 of 42 checks passed against a running server ([the check and its record](https://github.com/aminry/decisio-examples/tree/343691565ad708f99389bc863e3f64c398856fed/integrations/ai-sdk)). It uses createTypeSafeAi(...).decisionModel(...) with experimental_decide.

  Base URLmust end in /v1 (http://host:port/v1); TYPESAFE_AI_BASE_URL is read when the provider is created API keyrequired: apiKey or TYPESAFE_AI_API_KEY (LoadAPIKeyError without) If the server answers 422APICallError, statusCode 422, not retryable; the message is the server's detail as JSON Timeout and retriesnone set (Node's fetch defaults apply); maxRetries 2 for retryable failures  

```
import { createTypeSafeAi } from "@ai-sdk/typesafe-ai";

const typesafe = createTypeSafeAi({ baseURL: "http://127.0.0.1:8000/v1", apiKey: "unused" });
const model = typesafe.decisionModel("decisio-gemma-4-31b-it-letters");
```

 

A shape to fill in, not a command to run.

 

The one real difference from the other integrations is that baseURL needs /v1; without it the call fails loudly with a 404. The decision function throws if the chosen option is not the most probable one, which a server run with --abstain-option can produce; that case was emulated, not seen on a real abstaining server.

 

## 3. n8n

 

Node 22 (n8n 2.42 and later need Node 24 and were not run); `n8n-nodes-jev`, n8n 2.35.7, n8n-nodes-jev 0.2.3: 44 of 44 checks passed against a running server ([the check and its record](https://github.com/aminry/decisio-examples/tree/343691565ad708f99389bc863e3f64c398856fed/integrations/n8n)). It uses the community node's credential and its decision nodes.

  Base URLthe credential's Base URL, with no /v1; its default is the hosted address, so a self-hosted server changes it API keyrequired in the credential: any string If the server answers 422a NodeApiError with httpCode 422 and the server's detail; with Continue on Error the detail is only in the item's error object Timeout and retriesnone unless added under Options; retries only on 429 and 529  

Nothing broke. Simplify Output is on by default and returns one flat value per question, so probabilities, legend and usage are dropped; turn it off to get the server's response unchanged.

 

## 4. TanStack AI

 

Node 22; `@tanstack/ai + @tanstack/ai-typesafe`, @tanstack/ai 0.65.1, @tanstack/ai-typesafe 0.1.8: 39 of 39 checks passed against a running server ([the check and its record](https://github.com/aminry/decisio-examples/tree/343691565ad708f99389bc863e3f64c398856fed/integrations/tanstack)). It uses createTypesafeDecider(...) with decide().

  Base URLno /v1: the adapter posts to {baseURL}/v1/systemone; there is no environment variable for it API keyrequired: createTypesafeDecider takes it directly, typesafeDecider reads TYPESAFE_API_KEY If the server answers 422an Error whose message starts "TypeSafe evaluate request failed: 422 Unprocessable Entity" and carries the body; not retried Timeout and retriesnone set (Node's fetch defaults apply); no retries  

```
import { createTypesafeDecider } from "@tanstack/ai-typesafe";

const adapter = createTypesafeDecider("decisio-gemma-4-31b-it-letters", "unused", { baseURL: "http://127.0.0.1:8000" });
```

 

A shape to fill in, not a command to run.

 

Nothing broke. A base URL ending in /v1 posts to /v1/v1/systemone and fails with a 404, the opposite of the Vercel AI SDK's provider. The adapter drops the abstention fields and the x-decisio response headers.

 

## 5. Pipecat

 

Python 3.12; `pipecat-ai[jev]`, pipecat-ai 1.12.0: 39 of 39 checks passed against a running server ([the check and its record](https://github.com/aminry/decisio-examples/tree/343691565ad708f99389bc863e3f64c398856fed/integrations/pipecat)). It uses JevClient and JevClassifier in pipecat.classifiers.jev.

  Base URLno /v1; always pass base_url, because the default is the hosted address API keyrequired: JevClient(api_key="") raises ValueError If the server answers 422ClassifierError "HTTP 422"; the server's detail is discarded Timeout and retries10 seconds; 3 retries, on 429 and 529 only  

```
from pipecat.classifiers.jev import JevClient

client = JevClient(api_key="unused", base_url="http://127.0.0.1:8000")
```

 

A shape to fill in, not a command to run.

 

Nothing broke. A 422 loses its reason (only "HTTP 422" is raised), the default timeout is short at 10 seconds, and the classifier's results leave out the abstention fields.

 

## What next

 

- [System One clients](https://opendecisio.com/docs/migrating/): the differences that matter once a client is pointed at the server.
- [Python](https://opendecisio.com/docs/use-from/python/) and [JavaScript and TypeScript](https://opendecisio.com/docs/use-from/javascript/): the same call without a framework.
- [The HTTP API](https://opendecisio.com/docs/api/): every route, request field and response field.
