@liustack/modlens 3.14.0 → 3.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -0
- package/README.md +49 -2
- package/README.zh-CN.md +68 -17
- package/dist/main.js +55 -11
- package/docs/cli.md +2 -0
- package/docs/cli.zh-CN.md +98 -0
- package/docs/harness-setup.md +18 -4
- package/docs/harness-setup.zh-CN.md +67 -0
- package/docs/output-schema.md +2 -0
- package/docs/output-schema.zh-CN.md +74 -0
- package/docs/security.md +2 -0
- package/docs/security.zh-CN.md +43 -0
- package/docs/troubleshooting.md +2 -0
- package/docs/troubleshooting.zh-CN.md +210 -0
- package/dsh/client.js +87 -19
- package/dsh/index.js +329 -80
- package/package.json +1 -1
- package/skills/modlens/SKILL.md +5 -5
- package/skills/modlens/references/configure.md +4 -2
- package/skills/modlens/references/configure.zh-CN.md +177 -0
- package/skills/modlens/references/runtime.md +1 -1
- package/skills/modlens/scripts/run.ps1 +1 -1
- package/skills/modlens/scripts/run.sh +1 -1
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
# 配置 ModLens
|
|
2
|
+
|
|
3
|
+
[English](configure.md) | 中文
|
|
4
|
+
|
|
5
|
+
用户询问如何安装、配置或切换 ModLens provider 时读这份文档。优先替用户把命令跑掉,而不是解释给他听。
|
|
6
|
+
|
|
7
|
+
## 配置放在哪
|
|
8
|
+
|
|
9
|
+
`~/.modlens/config.json`,由 CLI 管理。优先级:CLI 参数 > 环境变量 > 配置文件 > 内置默认值。不设 `provider` 时按失败切换链依次尝试(有 `gemini-api` key 会先于 agent CLI 被试到),机器上什么都没配才会落在 `antigravity-cli`。
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
modlens config init # 写入一份起步配置(已存在则拒绝,--force 重写)
|
|
13
|
+
modlens config show # 生效的配置文件,API key 打码显示
|
|
14
|
+
modlens config set provider <name> # 更改默认 provider
|
|
15
|
+
modlens config set <provider>.<field> <value> # 字段:apiKey、baseUrl、model、extraBody
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
`config set` 写文件时权限为 0600。
|
|
19
|
+
|
|
20
|
+
## 配置文件的完整形状
|
|
21
|
+
|
|
22
|
+
所有内容都在四个顶层键之下,全部可选。下面的示例一次性展示了所有支持的键和字段(真实文件只需要写你用到的部分)。文件不存在就全用默认值。provider 的设置放在 `providers.<name>` 下面,不在顶层,手工编辑最常犯的就是这个错。
|
|
23
|
+
|
|
24
|
+
```json
|
|
25
|
+
{
|
|
26
|
+
"provider": "gemini-api",
|
|
27
|
+
"proxy": "http://127.0.0.1:7890",
|
|
28
|
+
"reuse": { "claude": true, "codex": true, "opencode": false, "pi": true, "grok": true },
|
|
29
|
+
"guards": {
|
|
30
|
+
"allowModels": ["deepseek-v4-*", "glm-5.*", "minimax-m2.5*", "qwen3-coder*"],
|
|
31
|
+
"denyModels": ["glm-*v*", "deepseek-vl*"],
|
|
32
|
+
"denyWhenUnknown": false
|
|
33
|
+
},
|
|
34
|
+
"providers": {
|
|
35
|
+
"antigravity-cli": { "model": "gemini-3.6-flash-low" },
|
|
36
|
+
"gemini-api": {
|
|
37
|
+
"apiKey": "AIza...",
|
|
38
|
+
"baseUrl": "https://generativelanguage.googleapis.com",
|
|
39
|
+
"model": "gemini-3.6-flash"
|
|
40
|
+
},
|
|
41
|
+
"openai": {
|
|
42
|
+
"apiKey": "sk-...",
|
|
43
|
+
"baseUrl": "https://dashscope.aliyuncs.com/compatible-mode/v1",
|
|
44
|
+
"model": "qwen3.6-27b",
|
|
45
|
+
"extraBody": { "thinking": { "type": "disabled" } }
|
|
46
|
+
},
|
|
47
|
+
"anthropic": {
|
|
48
|
+
"apiKey": "sk-ant-...",
|
|
49
|
+
"baseUrl": "https://api.anthropic.com",
|
|
50
|
+
"model": "claude-haiku-4-5-20251001"
|
|
51
|
+
},
|
|
52
|
+
"claude-cli": { "model": "haiku" }
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
字段含义:
|
|
58
|
+
|
|
59
|
+
- `provider`:不传 `-p` 时由哪个 provider 执行。标准名和别名都行(`agy`/`antigravity` 对应 `antigravity-cli`,`gemini` 对应 `gemini-api`,`openai-compat` 对应 `openai`,`claude` 对应 `anthropic`,`claude-code` 对应 `claude-cli`)。留空或缺失表示不钉任何一个:由失败切换链决定,已配置的 API provider 先于 agent CLI 被尝试。
|
|
60
|
+
- `providers.<name>.<field>`:共四个字段,`apiKey`、`baseUrl`、`model`、`extraBody`。每个 provider 条目都可选,条目里的每个字段也都可选。别名键同样会被读取(存在 `gemini` 下的设置在解析到 `gemini-api` 时也能找到),冲突时标准键胜出。
|
|
61
|
+
- `providers.<name>.extraBody`:一个 JSON 对象,合并进 API provider(`gemini-api`、`openai`、`anthropic`)的请求体,用来传厂商有而 modlens 没有对应参数的开关。最常见的用途是关掉思考,见下文小节。嵌套对象逐键合并,所以加一个开关不会动到该块里的其他内容。承载图片、提示词和 schema 约束的字段会被拒绝,报错会点名该字段。两个 CLI provider 不发请求体,所以在 `antigravity-cli` 或 `claude-cli` 上运行时它会被忽略,并在 `meta.warnings` 里说明。
|
|
62
|
+
- `guards`:调用 guard,给在同一个客户端里既跑纯文本模型又跑视觉模型的人用。两个列表都放 glob 模式(支持 `*` 和 `?`,不区分大小写,同时匹配模型名和 `provider/model`),用 `modlens config set guards.denyModels '["gemini-3*"]'` 或 `guards.allowModels` 设置(JSON 数组或逗号分隔的列表都行,传空则清除)。两种写法表达同一个意图,选列表更短的那种:
|
|
63
|
+
- 只用 `denyModels`:除了列出的视觉模型,其余全部运行引擎。适合你接入的模型大多是纯文本的情况。
|
|
64
|
+
- `allowModels` 非空(白名单模式):只有列出的模型运行引擎,其他所有已识别的模型一律拒绝。适合 2026 年的实际格局,纯文本模型才是那份短名单。deny 模式仍然优先于 allow 匹配,所以宽泛的 allow 可以把视觉变体剔出去,正如上面的示例:`glm-5.*` 放行文本系列,`glm-*v*` 抓住 `glm-5v-turbo`。allow 模式要锚定得紧一些(写 `deepseek-v4-*` 而不是 `deepseek*`),这样厂商下一代多模态型号会自动掉出名单,等你检查过再上场。
|
|
65
|
+
- 按真正抵达模型的内容来列名单,而不是按它本来能看到什么:多模态模型如果躲在一个剥离图片的网关后面,照样需要 modlens,而你的会话记录里存的是网关上报的模型名。`modlens doctor` 的 Guard 一节会显示规则和一条实时判定,方便核对结果。
|
|
66
|
+
- `denyWhenUnknown`(默认 `false`)决定在两种模式下,当没有任何信号能识别当前模型时怎么办:`false` 放行,`true` 拒绝。当前模型的检测来源从强到弱依次是:`MODLENS_MODEL` 环境变量(`none` 表示「按未知处理」)、harness 的会话存储、`--model` 自报。
|
|
67
|
+
- 以下绑定上,环境变量会覆盖配置文件:`GEMINI_API_KEY`、`OPENAI_API_KEY`、`OPENAI_BASE_URL`、`ANTHROPIC_API_KEY`、`ANTHROPIC_BASE_URL`。除此之外,modlens 还读取 `MODLENS_HARNESS`(粘贴恢复和 guard 的作用范围)、`MODLENS_MODEL`(guard 覆盖,见 `guards`),以及各 harness 自己注入的指纹,它们把 guard 的存储查询钉在当前 session 上:`CLAUDE_CODE_SESSION_ID`、`CODEX_THREAD_ID`,加上 harness 检测依赖的存在性标记(`CLAUDECODE`、`PI_CODING_AGENT`、`CODEX_SANDBOX`)。
|
|
68
|
+
- `reuse.<claude|codex|opencode|pi|grok>`:按 harness 记录的授权,决定能否花费本机其他登录态,由引导对话(`references/onboard.md`)写入。`true` 允许读图时复用该 harness(pi 的凭据加入 inline 区且所有 guard 照常生效,已登录的 Codex、OpenCode 的视觉模型或直接驱动的 pi 加入 agent 区,排在 `claude-cli` 之前),`false` 记下一次拒绝,用户不会被再次询问,缺失表示从未问过,什么都不会运行。`claude` 缺失视为已授权:`claude-cli` 作为内置 provider 早于这套模型存在,`reuse.claude false` 会把它移出链条(`-p claude-cli` 仍可钉死)。复用来的引擎不比用户自己的优先:分区只按速度档次排序。每个复用得来的答案都会在 `meta.warnings` 里加一行,说明花的是谁的额度,`modlens doctor` 的 Reuse 一节会显示每个 harness 的决定和探测发现的结果(探测结果在 `~/.modlens/auto-cache.json` 里缓存 6 小时,doctor 每次都重新探测)。用 `modlens config set reuse.codex true` 设置(传空恢复为从未问过)。
|
|
69
|
+
- 未知的顶层键和未知的 provider 名会被忽略而不是报错,所以敲错字会无声失败:手工编辑后跑一下 `modlens doctor`,它会显示哪些文件值和环境变量真正生效。
|
|
70
|
+
|
|
71
|
+
手工编辑没问题(保持文件是合法 JSON,权限 0600)。`modlens config set` 做的是同一件事,只是多了护栏。
|
|
72
|
+
|
|
73
|
+
## 各 provider 配置步骤
|
|
74
|
+
|
|
75
|
+
### antigravity-cli(默认,免费,无需 key)
|
|
76
|
+
|
|
77
|
+
需要装好 Antigravity CLI 并完成登录:
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
curl -fsSL https://antigravity.google/cli/install.sh | bash
|
|
81
|
+
agy # 用户需自己在浏览器完成登录,然后退出
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
任何免费 Google 账号都行,不需要 Google AI Pro。登录无法自动化,请让用户自己跑一次 `agy`。
|
|
85
|
+
|
|
86
|
+
### gemini-api(免费 key,最快的免费通道,5-10 秒)
|
|
87
|
+
|
|
88
|
+
1. 用户到 https://aistudio.google.com 创建一个 key(约三分钟,无需信用卡,免费额度不过期)。
|
|
89
|
+
2. 两种方式任选其一保存:
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
modlens config set gemini-api.apiKey <key>
|
|
93
|
+
# 或走环境变量:export GEMINI_API_KEY=<key>
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
默认模型 `gemini-3.6-flash` 在免费档就有视觉能力(约每分钟 10-15 次请求,每天 1500 次)。免费档的数据可能被 Google 用于改进产品,用户要处理敏感图片时请提醒这一点。
|
|
97
|
+
|
|
98
|
+
### openai(任意 OpenAI 兼容的多模态端点)
|
|
99
|
+
|
|
100
|
+
需要三个值。以 DashScope 的 qwen 为例:
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
modlens config set openai.baseUrl https://dashscope.aliyuncs.com/compatible-mode/v1
|
|
104
|
+
modlens config set openai.apiKey <sk-key>
|
|
105
|
+
modlens config set openai.model qwen3.6-27b
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
官方 OpenAI 的写法:baseUrl 用 `https://api.openai.com/v1`,配一个具备视觉能力的模型。对应的环境变量:`OPENAI_BASE_URL`、`OPENAI_API_KEY`。模型必须是多模态的,纯文本模型会失败或产生幻觉。这条路线没有服务端 schema 约束,偶发的结构错误会以明确报错的形式暴露出来,重试或换 provider 即可。
|
|
109
|
+
|
|
110
|
+
### anthropic(Claude API key)
|
|
111
|
+
|
|
112
|
+
```bash
|
|
113
|
+
modlens config set anthropic.apiKey <sk-ant-key>
|
|
114
|
+
# 或:export ANTHROPIC_API_KEY=<key>
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
默认模型是 Claude Haiku(`claude-haiku-4-5-20251001`)。schema 通过强制工具调用来约束。
|
|
118
|
+
|
|
119
|
+
**`ANTHROPIC_BASE_URL` 陷阱。**modlens 把 `ANTHROPIC_BASE_URL` 绑定到 `anthropic.baseUrl`,所以这个变量指向哪它就继承哪。如果用户在 shell 里设过它,用来把 Claude Code 路由到某个纯文本网关(在 Claude Code 界面下跑非 Claude 模型的常见做法),那么 `-p anthropic` 也会把视觉请求无声地发到那个网关,要么失败,要么返回的结果像没看过图,而且没有任何端点被换掉的提示。anthropic 的视觉表现异常时,先 `echo $ANTHROPIC_BASE_URL` 查一下。解法:给 modlens 调用临时取消这个变量,或用 `modlens config set anthropic.baseUrl https://api.anthropic.com` 钉死真实端点,或改用 `-p gemini-api`。
|
|
120
|
+
|
|
121
|
+
### claude-cli(Claude Code 登录态,无需 key)
|
|
122
|
+
|
|
123
|
+
借用已有的 `claude` 登录态,花的是用户的 Claude 订阅额度,不产生单独的 API 账单。需要装好并登录 Claude Code(用 `claude --version` 检查)。运行时只带 `--allowedTools Read`。只支持本地图片文件,远程 URL 请改用 gemini-api。默认模型别名 `haiku`。
|
|
124
|
+
|
|
125
|
+
```bash
|
|
126
|
+
modlens config set provider claude-cli # 用户愿意的话把它设为默认
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
## 关闭思考
|
|
130
|
+
|
|
131
|
+
推理模型答题前要先花掉思考预算。从图片里读文字用不上这些,所以在默认思考的模型上,一次识别白白变得又慢又贵。每家厂商给这个开关起的名字都不一样,也没有通用写法,所以 modlens 只负责把你放进 `extraBody` 的内容原样发出去,名字怎么写去查厂商自己的文档。
|
|
132
|
+
|
|
133
|
+
```bash
|
|
134
|
+
modlens config set openai.extraBody '{"thinking":{"type":"disabled"}}' # 持久保存
|
|
135
|
+
modlens -i shot.png --extra-body '{"thinking":{"type":"disabled"}}' # 仅本次运行
|
|
136
|
+
modlens config set openai.extraBody '' # 清除
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
`--extra-body` 在该次运行中整体替换已存储的对象,而不是合并进去。
|
|
140
|
+
|
|
141
|
+
已知写法,截至 2026 年 8 月:
|
|
142
|
+
|
|
143
|
+
| 端点 | 要发送的字段 |
|
|
144
|
+
| :-- | :-- |
|
|
145
|
+
| MiMo 官方 API(`api.xiaomimimo.com/v1`) | `{"thinking":{"type":"disabled"}}` |
|
|
146
|
+
| MiMo Responses 格式路由 | `{"reasoning":{"effort":"none"}}` |
|
|
147
|
+
| Qwen、GLM、MiMo 等自建在 vLLM 或 SGLang 上 | `{"chat_template_kwargs":{"enable_thinking":false}}` |
|
|
148
|
+
| 接受 effort 档位的 OpenAI 风格网关 | `{"reasoning_effort":"low"}` |
|
|
149
|
+
| `gemini-api`,Gemini 3 系列 | `{"generationConfig":{"thinkingConfig":{"thinkingLevel":"LOW"}}}` |
|
|
150
|
+
| `gemini-api`,Gemini 2.5 Flash 与 Flash Lite | `{"generationConfig":{"thinkingConfig":{"thinkingBudget":0}}}` |
|
|
151
|
+
| `anthropic` | 什么都不用做,不主动要求就不思考 |
|
|
152
|
+
|
|
153
|
+
三个会咬人的地方:
|
|
154
|
+
|
|
155
|
+
- 不是每个模型都能关。Gemini 3 Pro 和 Gemini 2.5 Pro 没有关闭开关,只能调低档位。有些模型完全无视 effort 字段,照样思考。
|
|
156
|
+
- 严格的云(Groq 和 Cerebras 都在内)遇到不认识的字段会直接返回 400。以前能跑的请求现在报 400 并点名你的字段,说明那个网关要的是另一种写法,不是这一种。
|
|
157
|
+
- 另一些则会接受未知字段然后悄悄忽略,所以要验证它是否生效,别想当然。把 `meta.durationSeconds` 和 `meta.usage` 里的 token 数与不带 `extraBody` 的一次运行对比,两者都没变,就是字段没起作用。
|
|
158
|
+
- 较弱的模型可能得靠思考才能填满 schema。在同一张流程图上实测:`gemini-3.6-flash` 在 `thinkingLevel: LOW` 下从 12 秒缩到 5.7 秒,区块和转录内容不变,但 DashScope 上的 `qwen3.6-27b` 设了 `enable_thinking: false` 后开始漏掉版面区块必填的 `type`,modlens 会拒绝这种结果而不是当作证据放行。刚关掉思考就出现结构错误,说明这就是代价,给那个模型把思考打开,或换到有服务端 schema 约束的路线。
|
|
159
|
+
|
|
160
|
+
## 替用户选 provider
|
|
161
|
+
|
|
162
|
+
- 想零配置且免费:`antigravity-cli`(需要 agy 登录,每张图 15-40 秒,密集或困难的图可试 `-m gemini-3.1-pro-high`)。
|
|
163
|
+
- 想又快又免费:`gemini-api`(三分钟领 key,5-10 秒)。
|
|
164
|
+
- 已经在给 Claude 付费:`claude-cli`(无需额外 key,agent 循环 20-45 秒)或 `anthropic`(API 计费)。
|
|
165
|
+
- 有偏好的多模态端点(qwen、GLM 等):`openai`。
|
|
166
|
+
|
|
167
|
+
每个配好的 provider 也互为后备:一次运行按固定顺序尝试它们(5-10 秒的 inline API provider 先上,然后是 agent 类,对远程 URL 来说这个顺序同时也是一道安全边界),遇到报错、超时或违反 schema 的结果就故障转移。`config set provider <name>` 把某个 provider 提到它所在允许分区的最前面,`-p <name>` 钉死唯一一个,不做回退。`doctor` 会打印这些故障转移链,结果里的 `meta.attempts` 显示一次运行实际试了什么。
|
|
168
|
+
|
|
169
|
+
## 故障排查
|
|
170
|
+
|
|
171
|
+
- 报错点名了缺失的环境变量或某条 `config set` 命令:照着运行即可。
|
|
172
|
+
- `Provider CLI not found: agy`:安装 Antigravity CLI 或换 provider。
|
|
173
|
+
- `Claude CLI reported ...` 或结果为空:检查 `claude` 的登录状态。
|
|
174
|
+
- openai 路线报 `does not match the vision schema`:重试一次,仍不行就换 gemini-api 或 anthropic。
|
|
175
|
+
- `extraBody cannot override "<field>"`:该字段承载图片、提示词或 schema。把它从对象里去掉,留下厂商开关即可。
|
|
176
|
+
- 400 报错点名了你在 `extraBody` 里设的字段:那个网关不认识它。其他写法见上文关闭思考一节。
|
|
177
|
+
- `config init` 拒绝执行:文件已存在。先用 `modlens config show` 查看,只有用户同意覆盖时才加 `--force`。
|
|
@@ -24,7 +24,7 @@ $ErrorActionPreference = 'Stop'
|
|
|
24
24
|
# package.json version, and the release script rewrites it on every bump.
|
|
25
25
|
$Package = '@liustack/modlens'
|
|
26
26
|
$Bin = 'modlens'
|
|
27
|
-
$Pinned = '3.
|
|
27
|
+
$Pinned = '3.16.0'
|
|
28
28
|
# -------------------------------------------------------------------------------
|
|
29
29
|
|
|
30
30
|
$NativeNote = 'no native artifact is published for this tool yet; phase A ships npm launch paths only'
|
|
@@ -22,7 +22,7 @@ set -eu
|
|
|
22
22
|
# package.json version, and the release script rewrites it on every bump.
|
|
23
23
|
PKG="@liustack/modlens"
|
|
24
24
|
BIN="modlens"
|
|
25
|
-
PINNED="3.
|
|
25
|
+
PINNED="3.16.0"
|
|
26
26
|
# -------------------------------------------------------------------------------
|
|
27
27
|
|
|
28
28
|
NATIVE_NOTE="no native artifact is published for this tool yet; phase A ships npm launch paths only"
|