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

nanollm

v0.0.19

Published

Hono server that proxies llm request

Readme

nanollm

一个类似litellm的llm模型代理服务,主打一个轻量和本地化,适合个人本地聚合多个模型的场景。

支持的功能:

  • 1 可以配置chat/completions(下面称chat), responsesmessages三种接口(暂不支持google接口)的模型供应商,并且同时对外暴露这三种接口,带/v1前缀。
  • 2 可以配置修改请求中的headersbody,传自定义数据,其中body支持深度合并。
  • 3 可以配置兜底方案,设置兜底分组,如果调用的模型下游接口失败,并且在某个分组中,则会尝试分组其他模型。
  • 4 支持配置文件热更新和本地管理页:modelsfallbackserver.ttfb_timeoutrecord.max_size 保存后立即生效,server.port 写回后需重启进程。

Configure

Example:

server:
  port: 3000 # default 3000
  ttfb_timeout: 5000 # optional, upstream first-byte timeout in ms

record:
  max_size: 100 # optional, default 10

models:
  - name: gpt-5.4-a
    # responses规范
    provider: openai-responses
    base_url: https://example.com/v1
    api_key: YOUR_KEY1
    model: openai/gpt-5.4

  - name: gpt-5.4-b
    # responses规范
    provider: openai-responses
    base_url: https://example.com/v1
    api_key: YOUR_KEY1
    model: openai/gpt-5.4
      
  - name: glm5.1
    # chat/completions规范
    provider: openai-chat
    base_url: https://example.com/v1
    api_key: YOUR_KEY2
    model: glm5.1
    image: true # optional, default true; only effective for openai-chat provider
    ttfb_timeout: 3000 # optional, overrides server.ttfb_timeout
    proxy: http://127.0.0.1:7890 # optional, overrides HTTPS_PROXY/HTTP_PROXY for this model
    headers:
      user-agent: nanollm
    body:
      temperature: 1
      store: false
      text: '{"verbosity":"high"}'
    bodyExpression: |
      ({
        ...body,
        messages: body.messages?.map((message) => ({
          ...message,
          updatedAt: Date.now()
        }))
      })
  
  - name: claude-sonnet-4-6
    # messages规范
    provider: anthropic
    base_url: https://example.com/v1
    api_key: ${YOUR_KEY3_FROM_ENV_VAR}
    model: claude-sonnet-4-6
    ignore_invalid_history: true # optional, default true; Anthropic转换时丢弃空signature的thinking历史

fallback:
  gpt-5.4:
    - gpt-5.4-a
    - gpt-5.4-b
    - glm5.1

Run the proxy server:

npx nanollm --config /path/to/config.yaml

对外提供的模型为所有models[i].namefallback.[group_name]例如上面demo配置就提供了

gpt-5.4-a
gpt-5.4-b
glm5.1
claude-sonnet-4-6
gpt-5.4

这样5个模型,其中gpt-5.4是兜底分组名,当使用这个模型的时候,会在下属列表的模型中寻找可用的模型,尝试顺序为按max(0, 最近5min失败次数-1)升序;如果分数相同,则保持配置里的原始顺序。

动态请求体表达式

models[*].bodyExpression 可以在请求发往上游前动态改写最终 request body。表达式运行时会拿到变量 body,并且必须同步返回新的 body;执行顺序是先应用 body 深度合并,再执行 bodyExpression

models:
  - name: gpt-5.4-a
    provider: openai-chat
    base_url: https://example.com/v1
    api_key: YOUR_KEY1
    model: openai/gpt-5.4
    bodyExpression: |
      ({
        ...body,
        messages: body.messages?.map((message, index) => ({
          ...message,
          content: index === 0 ? `${message.content}\nextra prompt` : message.content
        }))
      })

Anthropic 历史 thinking 签名

models[*].ignore_invalid_history 目前只影响 provider: anthropic 的协议转换,默认值为 true。当 OpenAI Chat/Responses 历史消息里的明文 reasoning 被转换到 Anthropic Messages 时,如果对应 thinking block 没有 signaturesignature 为空字符串,默认会丢弃该 thinking block,避免 Anthropic 上游校验空签名时报错。

如果需要保留旧行为,可以显式设置为 false,这时无签名 thinking 会继续带着空字符串 signature 发往 Anthropic 上游:

models:
  - name: claude-sonnet
    provider: anthropic
    base_url: https://example.com/v1
    api_key: YOUR_KEY
    model: claude-sonnet-4-6
    ignore_invalid_history: false

模型级 HTTP proxy

models[*].proxy 可以为单个模型配置请求下游供应商时使用的 HTTP proxy URL:

models:
  - name: claude-sonnet
    provider: anthropic
    base_url: https://example.com/v1
    api_key: YOUR_KEY
    model: claude-sonnet-4-6
    proxy: http://127.0.0.1:7890

代理优先级为:

  1. models[*].proxy
  2. HTTPS_PROXY
  3. HTTP_PROXY
  4. 直连

proxy 为空字符串或未配置时,会继续回退到环境变量;当前支持 http://https:// 代理 URL。

模型名通配符 *

models[*].name 支持后缀通配写法,可以把一类未显式配置的模型名路由到同一个上游配置:

models:
  - name: gpt-*
    provider: openai-chat
    base_url: https://example.com/v1
    api_key: YOUR_KEY
    model: openai/gpt-*

  - name: gpt-5.5-a
    provider: openai-chat
    base_url: https://example.com/v1
    api_key: YOUR_KEY
    model: openai/gpt-5.5

  - name: "*"
    provider: openai-chat
    base_url: https://example.com/v1
    api_key: YOUR_KEY
    model: fallback-model

fallback:
  gpt-5.5:
    - gpt-5.5-a

规则:

  • * 必须只出现一次,并且只能放在结尾。合法例子:gpt-*claude-**;非法例子:gpt-*-xg*p*tgpt**
  • 匹配优先级是:精确 fallback 分组名 > 精确 model 名 > 通配 model 名。
  • 如果多个通配 model 都能匹配,选择 * 前缀最长的那个;前缀长度相同则按 models 配置顺序。
  • 单独的 * 可以匹配任意请求模型名,适合作为最后兜底。
  • /v1/models 会直接展示配置中的通配名称,例如 gpt-**

以上面配置为例:

  • 请求 gpt-5.5:优先命中 fallback 分组 gpt-5.5
  • 请求 gpt-5.5-a:命中同名 model gpt-5.5-a
  • 请求 gpt-5.6:没有同名分组或同名 model,于是命中 gpt-*
  • 请求 llama-4:命中最后的 *

通配命中时,下游 model 字段里的 * 会被替换为请求中被 models[*].name 捕获的部分。例如:

  • name: gpt-*
  • 请求模型名:gpt-5.6
  • 捕获部分:5.6
  • model: openai/gpt-*
  • 实际发给上游的 modelopenai/gpt-5.6

如果下游 model 中没有 *,则始终使用固定模型名;如果下游 model 中有多个 *,会全部替换为同一个捕获部分。

openai-chat 的图片兼容选项

models[*].image 目前只对 provider: openai-chat 生效,主要用于兼容不同 OpenAI-compatible chat 服务对图片输入的支持差异。默认值为 true

  • image: true(默认):如果请求中包含图片,转为 chat 接口时保留 OpenAI chat 多模态 content 数组,例如:
{
  "role": "user",
  "content": [
    { "type": "text", "text": "请解释这张图" },
    { "type": "image_url", "image_url": { "url": "https://example.com/cat.png" } }
  ]
}
  • image: false:用于 DeepSeek 等只接受 content: string 的 chat 上游;图片、文件、音频等非文本内容会降级为字符串描述,文本内容用换行拼接,例如:
{
  "role": "user",
  "content": "请解释这张图\nAttached image: https://example.com/cat.png"
}

注意:image: false 当前不影响 provider: openai-responsesprovider: anthropic,这两类上游仍按各自协议保留图片结构。

也可以指定配置文件运行:

npx nanollm --config /path/to/config.yaml

如果希望 /status/record 跨进程重启保留最近数据,可以启用 SQLite 存储:

npx nanollm --config /path/to/config.yaml --storage sqlite

不传 --storage 时默认使用 memory,行为与旧版本一致。SQLite 文件固定保存在 ~/.nanollm/nanollm.sqlite3

如果当前目录就有 config.yaml,也可以直接运行:

npx nanollm

注意:npm 发布包不会包含作者本地的 config.yaml,需要你自己准备配置文件。

Config Admin

提供了 http://localhost:3000/admin 的本地配置管理页。

  • 页面使用表单方式编辑常用配置项:全局设置、模型列表和 fallback 分组;server.port 仅展示当前运行值,不提供页面编辑。
  • 常见使用方式是:先在 /admin 中新增或修改模型,再调整 fallback 分组成员顺序,最后点击“保存并应用”立即生效。
  • 页面内提供跳转到 /status/record 的快捷入口,方便保存后继续查看当前模型状态和最近请求记录。
  • 如果只是想放弃当前改动,可以点击“撤销未保存修改”;如果配置文件已被外部改动,可以点击“从服务端刷新”重新加载最新内容。
  • 点击保存后会先把表单数据转换成 YAML、校验配置,再原子写回配置文件。
  • modelsfallbackserver.ttfb_timeoutrecord.max_size 会立即热更新到新请求。
  • server.port 会写回文件,但需要重启进程后才会真正生效。
  • 已有模型上未在表单中展开的高级字段会在保存时自动保留。
  • 如果你在外部手动修改 config.yaml,服务也会自动检测并加载新配置;若新内容非法,则继续保留上一份有效配置并在管理页显示错误。

注意:/admin/config 设计目标是本机单用户管理,不建议暴露到局域网或公网。

Monitor

提供了http://localhost:3000/status的监控页面,可以查看模型健康状态。

提供了http://localhost:3000/record的采样记录页面,可以查看请求记录,对debug非常有用(默认只保留最新10次请求,可通过record.max_size配置修改)。

默认情况下,上述数据都只存在内存中,进程结束即消失。使用 --storage sqlite 启动后,/status 会在 SQLite 中保留最近 1 个月的稀疏 5 分钟统计 bucket(页面仍只展示最近 6 小时),/record 会持久化最近 record.max_size 条请求记录。