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

@jsonstudio/llms

v0.6.1643

Published

> 自 0.4.3 起,原 `rcc-llmswitch-core` npm 包已迁移并更名为 `@jsonstudio/llms`。开发 / 发布流程保持不变,仅需更新 package 依赖与文档引用。

Readme

@jsonstudio/llms(RouteCodex LLM Switch 核心)

自 0.4.3 起,原 rcc-llmswitch-core npm 包已迁移并更名为 @jsonstudio/llms。开发 / 发布流程保持不变,仅需更新 package 依赖与文档引用。

本包是 RouteCodex V2 的“工具治理唯一入口 + 协议转换核心”,实现严格的“前半段/后半段”双向流水线,并通过 defaultSseCodecRegistry 统一治理所有 SSE ↔ JSON 转换。核心事实:

  1. 唯一入口:所有 HTTP 请求(Chat/Responses/Anthropic/Gemini)必须先进入前半段 Conversion,SSE 输入一律由 SSEInputNodedefaultSseCodecRegistry → 对应协议 JSON,再映射为标准 Chat 请求。
  2. 唯一治理点:后半段 Chat Pipeline 是唯一可修改工具行为的位置;其他节点仅做形状转换或流式编解码。
  3. 唯一出站规则:响应阶段的 output 格式 (JSON/SSE) 只看原入口端点与入站 streaming 标记;providerType 只能决定 inbound converter 与 provider 调用,不得改写 outbound 协议。
  • 前半段(Front-Half,Conversion):按端点最小映射为 OpenAI Chat 标准形状(不做工具治理、不兜底)。
  • 后半段(Back-Half,Chat Pipeline):统一工具治理、参数修复、MCP 两步暴露、流/非流一致化与最终响应组装。

遵循 AGENTS.md 的 9 大架构原则:职责单一、最小兼容、Fail Fast、无兜底、配置驱动、统一出口/入口。

版本提示:

  • 从 0.2.95 起,Responses→Chat 的映射严格“只做形状转换”,不再注入兜底文本或工具;所有治理只在后半段进行。
  • 从 0.3.20 起,Anthropic/Chat/Responses 三端在 V2 前后半段上实现双向闭环:请求侧统一 Anth/Chat/Responses→Chat→providerProtocol,响应侧统一 providerProtocol→Chat→入口协议,所有工具调用/结果在 Anth↔Chat↔Anth 与 Responses↔Chat↔Responses 流程中保持字段/分组不变。
  • 自 0.4.2 起,Responses ↔ Anthropic 走完整的 Chat 桥后可直接互通:Responses upstream SSE → Chat canonical → Anthropic outbound,以及 Anthropic inbound → Chat canonical → Responses outbound,工具调用/函数输出在双向往返中保持 shape,不再需要任何协议猜测或字段兜底。
  • 规划中:Gemini/Chat 双向闭环(gemini-messages 协议)将按与 Anthropic 完全平行的方式接入,仅在前半段/后半段增加独立 codec,不影响现有 Chat/Responses/Anthropic 行为。

👉 Hub Pipeline 是当前唯一入口。 如果 Host 需要直接编排 Virtual Router,请参见 docs/HUB_PIPELINE_USAGE.md,了解如何通过 bootstrapVirtualRouterConfig + HubPipeline 完成初始化与热更新。

👉 ServerTool 是所有 server-side 工具的唯一统一框架。 web_search / vision followup 等服务端工具均在 llmswitch-core 内部通过 ServerTool 执行,Host 只需提供 providerInvoker/reenterPipeline 即可。设计与接入方式详见 docs/SERVERTOOL_DESIGN.md

总览

入站请求(任意端点)
  ├─ Chat (/v1/chat)        ┐
  ├─ Responses (/v1/responses) ├─ 前半段 Conversion → 规范化为 Chat 标准 JSON(非流)
  └─ Anthropic (/v1/messages) ┘   - 仅做字段/形状映射;不做工具治理/文本收割
                                     - 统一关闭上游直通,前半段需要时将 SSE 合成为非流 JSON

                ▼
         Chat Back-Half(唯一治理入口)
           - 工具治理(canonicalize/repair/去重/ID配对)
           - MCP 两步暴露(列表→读取/模板)
           - reasoning/think 标准化(按端点策略保留或过滤)
           - finalize:确保 tool_calls / tool role、finish_reason、content 形状一致

                ▼
          Provider(HTTP 通信,仅转发)

                ▼
         出站响应(统一从 Chat 反向映射)
           - Chat:直接输出标准 OpenAI Chat 形状
           - Responses:从 Chat 还原 required_action / output / items
           - Anthropic:映射为 Anthropic 支持的形状

要点:

  • “后半段唯一治理点”:三端(Chat/Responses/Anthropic)最终都走同一套 Chat 后半段。
  • Responses↔Anthropic 互通:Responses provider 输出先回落到 Chat,再由入口端点(例如 /v1/messages)决定重新构建 Anthropic wire 形状;反向同理,Anthropic 输入先 canonical 化为 Chat 后再落地 Responses 请求,由 outbound streaming 配置决定最终 SSE/JSON 行为。
  • “前半段最小映射”:只做协议字段/工具形状转换,不做文本工具收割/兜底/治理。
  • “流式一致”:默认不上游直通(upstream SSE OFF),前半段将流合成为非流 JSON,再走后半段,保证一致。

Conversion V3 节点架构与工具治理约束

  • 唯一入口:RouteCodex 主包只能通过 src/modules/llmswitch/bridge.tsdist/bridge/routecodex-adapter.js 调用 conversion v3;禁止旁路 import。
  • 配置驱动管线config/llmswitch/pipeline-config.json(或通过 LLMSWITCH_PIPELINE_CONFIG 指定)声明每条入/出站线路的节点序列:SSE Input → Provider Input → Chat Process → Provider Output → SSE Output,Responses/Anthropic 线路结构一致。
  • 节点职责
    • nodes/sse/*:入站 SSE 正规化、出站 SSE 序列化以及纯透传,占位但不改写业务数据。
    • nodes/input/*:OpenAI Chat / Responses / Anthropic 请求解析器,校验 model/messages,输出 canonical standardizedRequest
    • nodes/process/chat-process-node:唯一的工具治理点,负责 tool_calls 修复、MCP 两步暴露、上下文与 streaming 策略、passthrough 判定等。
    • nodes/output/*:基于 processedRequest 生成 Provider 协议响应(choices、usage、content blocks)。
    • nodes/response/*:出站方向入口,把 Provider 响应重新映射为 canonical,再交由 output/sse 节点返回。
  • 工具治理原则
    • 除 Compatibility 层为了满足 Provider/OpenAI 形状所做的最小字段修剪外,任何模块都不得修改工具语义。
    • Input/Output/SSE/Response 节点只做格式转换或序列化;所有工具解析/修复/透传/执行判定必须发生在 process 链路。
    • 如需新增与工具相关的功能,必须在 chat-process-node 中实现或扩展新的 process 节点,并由 pipeline 配置显式启用。

流水线节点与职能(入站→出站)

  1. HTTP Server 入站(端点路由)
  • 接收 /v1/chat、/v1/responses、/v1/messages 的原始请求体
  • 写入 http-request 快照(可选:.parsed 摘要)
  1. 前半段 Conversion(本包 v2/conversion/...)
  • Chat:校验/轻量规范(保持 OpenAI Chat 标准)
  • Responses:instructions + input 映射为 Chat.messages;function_call/tool_result → assistant.tool_calls / role='tool'(只形状,不治理)
  • Anthropic:Claude 消息/工具映射为 OpenAI Chat(仅形状)
  • SSE:如入站为 SSE,先在前半段合成为非流 JSON(默认),确保后续统一路径
  1. 后半段 Chat Pipeline(本包 v2/conversion/openai-chat/...)
  • request-shape:
    • 统一 messages.content 为 string
    • 删除不支持字段(如 stream)
  • request-tools-stage:
    • canonicalizeChatResponseTools:不变式(content=null,finish_reason=tool_calls)
    • JSON/JSON5 风格参数修复,失败回退 "{}"
    • 工具 ID 生成/去重
    • MCP 两步暴露(仅在后半段)
  • provider 调用(Provider 层):HTTP 转发 + 快照;不做工具处理
  • response-shape:
    • 统一 Chat 响应形状、finish_reason、content
    • reasoning/think 清理或保留(按端点策略)
  • response-tools-stage:
    • 工具结果配对(role='tool' 与 tool_calls.id 对齐)
    • Responses 反向桥接(仅映射,不治理):required_action + items/output 还原
  1. 出站响应
  • Chat:OpenAI Chat
  • Responses:OpenAI Responses
  • Anthropic:Anthropic Messages

三端前半段:具体滤波器与映射(伪代码)

Chat 前半段

function chatFrontHalf(payload):
  assert(Array.isArray(payload.messages))
  drop(payload.stream)          // 统一非流
  ensureOpenAIChatShape(payload)
  return payload

Responses 前半段(严格不兜底)

function responsesFrontHalf(payload):
  ctx = captureResponsesContext(payload)
  tools = normalizeTools(payload.tools)
  msgs = []
  if ctx.instructions: msgs.push({role:'system', content:trim(ctx.instructions)})

  for entry in payload.input:
    switch(entry.type):
      case 'function_call'|'tool_call':
        name = entry.name || entry.function?.name
        args = parseArguments(entry.arguments || entry.function?.arguments)
        msgs.push({role:'assistant', tool_calls:[{id:genId(entry), type:'function', function:{name, arguments:stringify(args)}}]})
      case 'function_call_output'|'tool_result'|'tool_message':
        id = entry.tool_call_id || entry.call_id || entry.tool_use_id || entry.id
        out = normalizeToolOutput(entry.output)
        msgs.push({role:'tool', tool_call_id:id, content:String(out ?? '')})
      default:
        // 优先 entry.message.content[]
        if entry.message?.content: text = collectText(entry.message.content)
        else if entry.content:      text = collectText(entry.content)
        else if entry.text:         text = entry.text
        if text: msgs.push({role:normalizeRole(entry.role), content:text})

  return { model, messages: msgs, tools: tools, tool_choice: payload.tool_choice }

注意:不注入“伪 user”,不做文本工具收割/治理,严格只做形状转换。

Anthropic 前半段

function anthropicFrontHalf(payload):
  // Claude → OpenAI Chat 映射
  for m in payload.messages:
    map role/parts → Chat message
  map tools → OpenAI function tools
  drop(stream)
  return chatPayload

Gemini 前半段(规划中)

Gemini REST 规范使用 contents[].role + parts[] + tools.functionDeclarations 的结构,与 Anthropic 的 Messages 协议类似,本包会以完全平行的方式接入一个 gemini-messages 协议线:

目标:

  • 仅在前半段/后半段增加 gemini-messages 的 codec,既有 Chat/Responses/Anthropic 行为不受影响。
  • 非 passthrough 流水线继续遵循统一约束:entryProtocol → Chat → providerProtocol(请求)与 providerProtocol → Chat → entryProtocol(响应),中段只认 Chat。

计划中的 main codec 文件:

  • src/conversion/codecs/gemini-openai-codec.ts
    • buildOpenAIChatFromGeminiRequest(gReq):Gemini 请求 → OpenAI Chat 请求
    • buildGeminiRequestFromOpenAIChat(chatReq):OpenAI Chat 请求 → Gemini 请求
    • buildOpenAIChatFromGeminiResponse(gResp):Gemini 响应 → OpenAI Chat completion
    • buildGeminiFromOpenAIChat(chatResp):OpenAI Chat completion → Gemini 响应(用于“入口/出口都是 Gemini”的回环测试与 /v1/gemini 出口)

请求侧(Gemini → Chat)映射要点:

  • contents: Content[]
    • Content.role
      • "user" → Chat role: "user"
      • "model" → Chat role: "assistant"
      • "system" → Chat role: "system"(或汇总进顶层 systemInstruction,再统一收敛为 Chat system 消息)
      • "tool" → Chat role: "tool"(对应 functionResponse)
    • Content.parts: Part[]
      • { text } → Chat message.content 文本(可继续使用 text-markup-normalizer 做轻量标准化,不做治理)
      • { functionCall: { name, args } }
        • 映射为 Chat assistant.tool_calls[]
          • type: "function"
          • function.name = name
          • function.arguments = JSON 字符串(通过现有 jsonish.repairArgumentsToString 进行安全修复)
      • { functionResponse: { name, response } }
        • 映射为 Chat role: "tool" 消息:
          • tool_call_id 与前一轮 tool_calls 对齐(ID 生成与去重仍由后半段工具治理负责)
          • content 为字符串化后的结果(不丢失结构,可放入 metadata 保留原始 JSON)
      • 其它多模态部件(inlineData/fileData/...):
        • 按“不丢失信息”原则,先透传到 Chat 消息的 metadata.vendor.gemini.parts[],后续再根据需要扩展。
  • systemInstruction?: Content
    • 统一转换为 Chat 顶层 system 消息(或合并进 messages 中的 system 段),保持与 Anthropic 一致的“所有系统指令在 Chat 段收敛”策略。
  • tools.functionDeclarations
    • 映射为 Chat tools[].function,字段基本一一对应(name/description/parameters)。
  • 采样/安全配置:
    • generationConfig.temperature/topP/topK/maxOutputTokens/stopSequences 映射为 Chat 顶层采样参数;
    • safetySettings 透传到 metadata.vendor.gemini.safetySettings,保证信息不丢。

响应侧(Gemini → Chat)映射要点:

  • candidates[0].content.parts[]
    • text 部分 → Chat choices[0].message.content(多段合并)
    • functionCall 部分 → Chat choices[0].message.tool_calls[](与请求侧规则对应)
  • finishReason → Chat finish_reason(STOP → "stop"、MAX_TOKENS → "length" 等)
  • usageMetadata → Chat usage(prompt_tokens/output_tokens/total)

Chat → Gemini(请求与响应):

  • 与 Anthropic 完全平行,在 buildGeminiRequestFromOpenAIChat / buildGeminiFromOpenAIChat 内按 Chat canonical 重新投影回 Gemini wire 形状:
    • system → systemInstruction 或系统 Content;
    • assistant + tool_calls → role: "model", parts:[{ functionCall... }]
    • role: "tool"role: "tool", parts:[{ functionResponse... }]
    • tools → functionDeclarations
    • 采样/安全配置 → generationConfig / safetySettings

与现有协议的隔离性:

  • gemini-messages 只在 providerProtocol 显式配置为 "gemini-messages" 时参与路由,且 codec 文件和分支独立存在:
    • 不修改 openai-chatopenai-responsesanthropic-messages 的现有逻辑;
    • 中段 Chat 工具治理/最终器不依赖具体 provider 协议,只认 canonical Chat completion。
  • RouteCodex 主包侧仅需:
    • providerType: "gemini"providerProtocol: "gemini-messages"
    • Provider 继续复用 OpenAIStandard,仅负责 HTTP 通信。

测试与回环(规划):

  • 类似 Anthropic/Responses,将新增:
    • gemini-request-closed-loop.ts:Gemini 请求 → Chat 请求 → Gemini 请求',检查字段/工具/role 数量与顺序一致。
    • gemini-in-out-closed-loop.ts:通过 routecodex-adapter 的 processIncoming / processOutgoing 对真实 codex-samples 做闭环。
    • 如有需要,扩展 streaming 测试,验证 streamGenerateContent → Chat SSE delta → Responses/Anthropic SSE 的一致性。

后半段:主要处理点与职责

  • request-shape(v2/conversion/openai-chat/request-shape.ts)
    • 统一 messages.content 为 string
    • 删除不支持字段(如 stream)
  • request-tools-stage(v2/conversion/openai-chat/request-tools-stage.ts)
    • canonicalizeChatResponseTools:不变式(content=null,finish_reason=tool_calls)
    • jsonish.repairArgumentsToString:把任意形态 arguments 修复为安全 JSON 字符串
    • 工具 ID 生成/去重
    • MCP 两步暴露(仅在后半段)
  • response-shape(v2/conversion/openai-chat/response-shape.ts)
    • Chat 响应标准化;think/推理文本按端点策略保留/清理
  • response-tools-stage(v2/conversion/openai-chat/response-tools-stage.ts)
    • role='tool' 与 tool_calls.id 配对
    • Responses 反向桥接(仅映射,不治理):required_action + items/output 还原

流式(SSE)策略

  • 默认不上游直通(provider 配置未显式允许时)。
  • 前半段把 SSE 合成为非流 JSON;后半段统一处理,再需要时用本包 streaming 模块合成 Responses SSE。

快照与排错

  • 快照目录:~/.routecodex/codex-samples/<endpoint>/
    • *_http-request.json / *_http-request.parsed.json
    • *_pipeline.llmswitch.request.post.json(进入后半段前的 Chat 形状)
    • *_pipeline.provider.request.pre.json(上游请求体,顶层仅 Chat 字段)
  • 常见 1214 根因:
    • 缺失用户消息(Responses 输入未包含 user 文本,且前半段不兜底)
    • 顶层出现 data/metadata/stream 等额外键(应移除“添加逻辑”,而非末端清理)

设计原则与边界

  • 工具治理唯一在后半段;前半段绝不进行文本工具收割/参数修复
  • 兼容层只做 provider 特定最小映射;Provider 只做 HTTP 通信
  • Fail Fast:形状不合规直接报错,不做隐藏兜底

版本与构建

  • 构建:npm run build
  • 打包:npm pack
  • 发布:npm publish