@aparte/provider-openai-compat

中文文档
1.0.0发布于 2026/11/07MITTypeScriptES Module零依赖构建来源已验证近 30 天下载 6106

One OpenAI-compatible chat-completions adapter for any /v1 endpoint — OpenAI, Mistral, OpenRouter, Z.ai, Groq, LM Studio, Ollama and friends, via presets or plain config.

原始使用文档
文档目录3 节
  1. Context window
  2. Sources and citations
  3. Errors and finish reason

@aparte/provider-openai-compat

One adapter for every OpenAI-compatible /chat/completions endpoint — OpenAI, Mistral, OpenRouter, Z.ai, Groq, Together, LM Studio, Ollama (/v1) and friends all speak the same wire format, so they share a single, zero-dependency format adapter. Vendors differ only by data (base URL, auth header, branding), passed as config or picked from presets.

npm install @aparte/provider-openai-compat @aparte/core

@aparte/core is the only peer dependency; this adapter itself has none.

import { createOpenAICompatProvider, presets } from '@aparte/provider-openai-compat';
import { aparteGlobalConfig } from '@aparte/core';

aparteGlobalConfig.registerAIProvider(createOpenAICompatProvider(presets.OPENROUTER));
// …or any compat endpoint, no preset needed:
aparteGlobalConfig.registerAIProvider(createOpenAICompatProvider({ id: 'groq', baseURL: 'https://api.groq.com/openai/v1' }));

@aparte/core is a peer dependency. For vendors outside the OpenAI-compat family (Anthropic, Gemini, …) use @aparte/provider-ai-sdk instead.

Works on the server too. Nothing here touches the DOM, and core resolves its DOM-free entry under Node's export condition — so you can reuse this adapter from a backend, an Electron main process or an SSR pass instead of re-writing one. Pair buildRequest / parseStream with your own fetch when you already own the request (your AbortSignal, your headers), or hand it to createAparteChatHandler from core.

Part of the aparté monorepo. ESM-only. See the Providers guide in the docs for the full usage.

Context window

fetchModels fills each model's contextWindow, which is what the token gauge and compaction measure against. It reads the first positive integer among context_length (OpenRouter, Together), max_model_len (vLLM), context_window (Groq) and max_context_length (Mistral) on the GET /models entry. A local server also needs to say which one it is, because most of them do not put the window on /models:

createOpenAICompatProvider({ id: 'my-box', baseURL: 'http://localhost:8080/v1', isLocal: true, server: 'llamacpp' });

With server set, one extra request goes to the endpoint's origin (the /v1 path stripped) and the effective window wins over the trained maximum, since that is where the server truncates:

PresetserverReadsNotes
LMSTUDIOlmstudio/api/v1/models: a loaded model's config.context_lengthan unloaded model gets none
OLLAMAollama/api/ps: the loaded runner's context_lengtha model that is not loaded gets none
LLAMACPPllamacpp/props: default_generation_settings.n_ctxper slot, one value for the served model
VLLMvllmmax_model_len on /v1/modelsno extra request

An unloaded model gets no window rather than its trained maximum: that number is not what the server will run with. A probe that fails (CORS, an older server, a closed port) leaves the models without a window and logs one warning; it never fails the model list.

A model you declare in models with a contextWindow wins over anything read from the server.

LLAMACPP (http://localhost:8080/v1) and VLLM (http://localhost:8000/v1) are presets like the others: local, key optional.

Sources and citations

A reply that cites its sources arrives with them: the provider ends the turn with one sources event, just before done, and aparté lists the sources under the reply and puts a chip where each is cited. Nothing to configure — an endpoint that sends no citations leaves the stream exactly as it was.

import { createOpenAICompatProvider, presets } from '@aparte/provider-openai-compat';
import { aparteGlobalConfig } from '@aparte/core';

// Perplexity's Sonar models search the web and cite what they read.
aparteGlobalConfig.registerAIProvider(createOpenAICompatProvider(presets.PERPLEXITY));
// OpenRouter's `:online` models and the OpenAI search models cite through annotations.
aparteGlobalConfig.registerAIProvider(createOpenAICompatProvider(presets.OPENROUTER));

Two shapes are read:

  • url_citation annotations (OpenAI, OpenRouter) on delta.annotations, or on message.annotations for a server that streams the whole message shape. They carry the offsets of the passage they support, which become the citation's start / end; an offset past the end of the text is brought back into it.
  • Perplexity's citations and search_results, at the root of a chunk, with no offsets: the text carries [1], [2], so each marker found in the text becomes a citation (marker: true, the chip takes the marker's place) on that source. A marker that names no source is left as text.

The same page cited twice is one source (de-duplicated by URL), and two sources on one passage are one citation, which the bubble shows as "+1". A URL is passed on as the endpoint sent it: core's renderer links only the schemes its sanitizer allows, so a javascript: URL is shown as text, never as a link.

The PERPLEXITY preset declares its models (sonar, sonar-pro, sonar-reasoning-pro, sonar-deep-research) because Perplexity has no GET /models to ask; pass your own models to change the list.

A non-streamed answer (stream: false) is read the same way, by parseSources: when it cites anything, it resolves to the stream a streamed answer is — its text, its sources, its end — through the direct transport and through your backend alike.

Errors and finish reason

A server that answers 200 and then streams data: {"error": {...}} (LM Studio on a context overflow, OpenAI and vLLM mid-stream) ends the turn with an error event carrying its message, not an empty completed reply. The last finish_reason of the stream travels on the done event as finishReason (stop, length, tool-calls, content-filter, other).

版本与发布记录

@aparte/provider-openai-compat 共发布 66 个版本,首次发布于 2026/07/24;过去 12 个月发布了 66 个版本。最新版本附带 npm provenance 构建来源证明,可追溯到公开的 CI 构建记录。

版本发布日期距今
1.0.0latest2026/11/07今天
0.32.12026/11/025 天前
0.32.02026/11/025 天前
0.31.02026/11/026 天前
0.30.12026/11/016 天前
0.30.02026/11/016 天前

其他发布通道:alpha → 0.17.0。

关于 @aparte/provider-openai-compat 的常见问题

@aparte/provider-openai-compat 是什么?

One OpenAI-compatible chat-completions adapter for any /v1 endpoint — OpenAI, Mistral, OpenRouter, Z.ai, Groq, LM Studio, Ollama and friends, via presets or plain config.

如何安装 @aparte/provider-openai-compat?

在项目目录运行 npm install @aparte/provider-openai-compat,或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖:@aparte/core(>=1.0.0 <2.0.0)。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖,Yarn 需要手动安装。

@aparte/provider-openai-compat 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@aparte/provider-openai-compat 支持 ESM 还是 CommonJS?

以 ES Module 形式发布,推荐使用 import 引入。在 CommonJS 项目中,Node.js 20.19+ / 22.12+ 可以直接 require() 不含顶层 await 的 ES Module,更早的版本需要改用动态 import()。

@aparte/provider-openai-compat 需要什么版本的 Node.js?

package.json 的 engines 字段要求 Node.js >=18。版本不符时 npm 默认只给出警告,开启 engine-strict 后会拒绝安装。

@aparte/provider-openai-compat 可以商用吗?

@aparte/provider-openai-compat 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@aparte/provider-openai-compat 的下载量有多少?

根据 npm 官方下载统计,@aparte/provider-openai-compat 在 2026/10/06 – 2026/11/04 这 30 天内被下载 6,106 次,日均约 204 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@aparte/provider-openai-compat 还在维护吗?

最新版本 1.0.0 发布于 2026/11/07(今天);至今共发布 66 个版本,其中过去 12 个月发布了 66 个;首次发布于 2026/07/24。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。