magpie-ima-local-auth 0.1.0 → 0.1.1

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 CHANGED
@@ -1,10 +1,16 @@
1
- # 更新记录
2
-
3
- ## 0.1.0 — 2026-10-28
4
-
5
- - 首个版本:从本机 ima.copilot 客户端导入登录态(Windows DPAPI / 种子文件),
6
- 把账号的免费知识库模型(DeepSeek V3.2 / Tencent HY 2.0,含 Think 档)接进 magpie。
7
- - 流式 `MESSAGE` 与思考 `THINKING` 转 OpenAI Chat Completions;支持非流式。
8
- - 多轮 session(30 分钟 TTL、60 轮兜底)、`auth.refresh` 续期、算力余额展示。
9
- - 不列 Copilot:ima 的 Copilot 是云端 agent,本机 2.6.15 对它的问答返回「当前版本暂不支持」。
10
- - 不依赖 cookie 粘贴、不开 CDP;`IMA-IUA` 缺失会让 ima 把请求当匿名,插件默认补最小 IUA。
1
+ # 更新记录
2
+
3
+ ## 0.1.1 — 2026-10-28
4
+
5
+ - 兼容 ima 客户端 UI 新版的 `STRUCTURED_BLOCK` 流事件(`Data.text_message` 正文 / `Data.thinking_message` 思考),与旧版 `MESSAGE` / `THINKING` 同时支持。
6
+ - 新增 `scripts/import-cdp.mjs`:从带调试端口的 ima.copilot 走 CDP + native bridge 导入登录态。
7
+ - 补充 `docs/evaluation.md`:UI 的 V4.1-Flash 标签在测试账号实际发 `official_3` / `official_1`,账号目录对应 V3.2 / V3.2 Think。
8
+
9
+ ## 0.1.0 — 2026-10-28
10
+
11
+ - 首个版本:从本机 ima.copilot 客户端导入登录态(Windows DPAPI / 种子文件),
12
+ 把账号的免费知识库模型(DeepSeek V3.2 / Tencent HY 2.0,含 Think 档)接进 magpie。
13
+ - 流式 `MESSAGE` 与思考 `THINKING` 转 OpenAI Chat Completions;支持非流式。
14
+ - 多轮 session(30 分钟 TTL、60 轮兜底)、`auth.refresh` 续期、算力余额展示。
15
+ - 不列 Copilot:ima 的 Copilot 是云端 agent,本机 2.6.15 对它的问答返回「当前版本暂不支持」。
16
+ - 不依赖 cookie 粘贴、不开 CDP;`IMA-IUA` 缺失会让 ima 把请求当匿名,插件默认补最小 IUA。
@@ -1,92 +1,123 @@
1
- # ima.copilot 反代价值评估
2
-
3
- > 评估对象:`E:\ima.copilot\ima.copilot.exe`(本机 2.6.15.5280 / Chromium 150.0.7871.5469)
4
- > 评估时间:2026-10-28。所有数字都是本机实测,不是查资料估的。
5
-
6
- ## 结论
7
-
8
- | 反代对象 | 价值 | 判定 |
9
- |---|---|---|
10
- | **免费知识库模型**(DeepSeek V3.2 / Tencent HY 2.0,含 Think 档) | **高** | 4 个模型可用、不扣算力、支持流式与思考、单问 session 能多轮;适合做 magpie 供应商 |
11
- | **积分模型(Copilot)** | **0(在“不能是云端 agent”约束下)** | 本机 2.6.15 对 Copilot 问答直接返回 `{"Code":1,"Msg":"当前版本暂不支持"}`;即使别的版本支持,它也是 ima 自己的云端 agent(`robot_type=15`),正是 today 式结果的来源 |
12
- | 知识库文件 / 文档管理 | 低(本次不做) | 是 ima 的知识库业务,不是模型;对 magpie 供应商没有直接价值 |
13
- | 图片生成 / 播客等 | 低(本次不做) | 与 magpie 的 chat 供应商无关;且需要单独的计费与权限 |
14
-
15
- **一句话:这个软件的反代价值全部集中在“免费模型”上;积分模型不是模型通道,是云端 agent,不值得为它牺牲模型级体验。**
16
-
17
- ## 实测证据
18
-
19
- ### 免费模型目录(`POST /cgi-bin/model_manage/get_models`,body `{}`)
20
-
21
- | model_type | model_id | 显示名 | 倍率字段 |
22
- |---|---|---|---|
23
- | 3 | official_3 | DeepSeek V3.2 | 空 |
24
- | 1 | official_1 | DeepSeek V3.2 Think | 空 |
25
- | 0 | official_0 | Tencent HY 2.0 | 空 |
26
- | 2 | official_2 | Tencent HY 2.0 Think | 空 |
27
-
28
- `model_token_copywriting` 为空 = 知识库问答不扣算力。连续多次 `assistant/qa` 后
29
- `token_manager/get_balance` 仍为 500,说明免费不是“暂时没扣”。
30
-
31
- ### 问答
32
-
33
- ```
34
- POST /cgi-bin/session_logic/init_session
35
- {"env_info":{"interact_type":2,"robot_type":10000},"name":"…","msgs_limit":20}
36
- → {"code":0,"session_id":"…"}
37
-
38
- POST /cgi-bin/assistant/qa (SSE)
39
- {"session_id":"…","robot_type":10000,"question":"…","question_type":2,
40
- "command_info":{"question_info":{}},"model_info":{"model_type":3,"model_id":"official_3"}}
41
- → MESSAGE {"Text":"DSH-IMA-OK"} … COMPLETED {"Code":0}
42
- ```
43
-
44
- - 多轮:同一 session 第一问“记住 7391”、第二问“刚才的数字”返回 7391。
45
- - 长回答:9 个 `MESSAGE` 增量拼出完整 1..20。
46
- - 思考模型:`THINKING {"Message":"…","Status":1}` 增量;最后一条 `Status:2` 是结束标记。
47
- - `SUGGEST_QUESTION` 是建议列表,不是答案。
48
-
49
- ### 登录态
50
-
51
- ima 的 token 有两份:运行中客户端的内存(native bridge),以及客户端正常退出时写进
52
- profile 的 `tencent.wxlogin.account_secret_encrypted`(DPAPI)。插件读后者,不读内存、
53
- 不开 CDP、不要求粘贴 cookie。读到的 `token` 约 2 小时,`refresh_token` 约一年;
54
- `/auth_login/refresh` 实测可换新 token(返回相对 7200 秒)。
55
-
56
- ### IUA 的必要性
57
-
58
- `x-ima-cookie` 里少了 `IMA-IUA`,服务端不报错,但会把请求当匿名:
59
- 模型目录退回默认的 DeepSeek-V4.1-Flash / Hy3 / Hy4 / GLM,`assistant/qa` 返回 200
60
- 却没有正文。补一个最小 IUA
61
- (`PR=IMA&PP=com.tencent.imawin&PPVN=<版本>&PL=WIN&COVC=<Chromium 版本>&EV=`)
62
- 就按账号目录回答。所以插件永远补 IUA。
63
-
64
- ## 与现有实现的关系
65
-
66
- | 实现 | 路径 | 问题 |
67
- |---|---|---|
68
- | `magpie-ima-auth`(npm) | 浏览器 cookie → 云端 `assistant/qa` | 登录要手工复制 `x-ima-cookie`;本质是把 ima 的云端 agent 会话包装成 chat(单问、无工具、system prompt 受限) |
69
- | `opencli-plugin-ima` | 直接 API + WebContents/UI | 主要面向知识库问答;Windows 直接 API 遇到 600001;需要客户端/UI 自动化 |
70
- | 本插件 | 本机客户端 profile → DPAPI 登录态 → 伪装请求头 | 不粘贴 cookie、运行时不需要 CDP;只走 `robot_type=10000` 的普通问答;模型目录/流式/思考/续期都按模型供应商做 |
71
-
72
- ## 限制(如实写)
73
-
74
- - **单问 session**:ima 的 `assistant/qa` 一次只收一个问题,没有 messages 数组;插件用
75
- session 保持多轮,但 system prompt 只在 session 第一问里发。
76
- - **没有工具调用**:ima 的问答接口没有 tool 通道;模型条目如实声明 `toolcall: false`。
77
- - **没有 token 计数**:ima 不返回 usage;插件不按字符数编,返回 0。
78
- - **没有上下文窗口**:模型目录不下发;`limit.context` 留 0,交给 magpie 的模型库。
79
- - **私有接口**:随时可能变;ima 客户端升级后 IUA/字段可能需要跟着调。
80
- - **登录导入平台**:DPAPI 解密目前只做 Windows;macOS 用种子文件 / `IMA_COPILOT_LOGIN_FILE`。
81
- - **Copilot 不可用**:本机版本直接“暂不支持”,且它是 agent;插件默认不列。
82
-
83
- ## 已完成的验收
84
-
85
- - `node scripts/check.mjs`:通过 29 · 警告 0 · 失败 0
86
- - `node --test`:10/10
87
- - magpie 0.1.1814 安装后 `ima (ima, 4 models) signed in as 001ab…`
88
- - 网关:`POST /v1/chat/completions`(`ima/deepseek-v3.2`)返回 `GATEWAY-OK`;
89
- 流式返回 role/content/`finish_reason:"stop"`;`ima/deepseek-v3.2-think` 返回
90
- `reasoning_content`。
91
- - DSH headless(`dsh --profile headless` + patch,模型 `ima/tencent-hy-2.0`)返回
92
- `DSH-IMA-OK`。
1
+ # ima.copilot 反代价值评估
2
+
3
+ > 评估对象:`E:\ima.copilot\ima.copilot.exe`(本机 2.6.15.5280 / Chromium 150.0.7871.5469)
4
+ > 评估时间:2026-10-28。所有数字都是本机实测,不是查资料估的。
5
+
6
+ ## 结论
7
+
8
+ | 反代对象 | 价值 | 判定 |
9
+ |---|---|---|
10
+ | **免费知识库模型**(DeepSeek V3.2 / Tencent HY 2.0,含 Think 档) | **中(有其它免费源时低)** | 4 个模型可用、不扣算力、支持流式与思考;本机账号没有 HY3/HY4/GLM-5.3,面对 CB 免费 HY3 只剩“免费备胎”价值 |
11
+ | **积分模型(Copilot)** | **0(在“不能是云端 agent”约束下)** | 本机 2.6.15 对 Copilot 问答直接返回 `{"Code":1,"Msg":"当前版本暂不支持"}`;即使别的版本支持,它也是 ima 自己的云端 agent(`robot_type=15`),正是 today 式结果的来源 |
12
+ | 知识库文件 / 文档管理 | 低(本次不做) | 是 ima 的知识库业务,不是模型;对 magpie 供应商没有直接价值 |
13
+ | 图片生成 / 播客等 | 低(本次不做) | 与 magpie 的 chat 供应商无关;且需要单独的计费与权限 |
14
+
15
+ **一句话:这个软件的反代价值只在“免费模型”上,而且只是“多一个免费备胎”;积分模型不是模型通道,是云端 agent,不值得为它牺牲模型级体验。若已有 CB 免费 HY3,本插件的边际价值很低。**
16
+
17
+ ## 实测证据
18
+
19
+ ### 免费模型目录(`POST /cgi-bin/model_manage/get_models`,body `{}`)
20
+
21
+ | model_type | model_id | 显示名 | 倍率字段 |
22
+ |---|---|---|---|
23
+ | 3 | official_3 | DeepSeek V3.2 | 空 |
24
+ | 1 | official_1 | DeepSeek V3.2 Think | 空 |
25
+ | 0 | official_0 | Tencent HY 2.0 | 空 |
26
+ | 2 | official_2 | Tencent HY 2.0 Think | 空 |
27
+
28
+ `model_token_copywriting` 为空 = 知识库问答不扣算力。连续多次 `assistant/qa` 后
29
+ `token_manager/get_balance` 仍为 500,说明免费不是“暂时没扣”。
30
+
31
+ ### 问答
32
+
33
+ ```
34
+ POST /cgi-bin/session_logic/init_session
35
+ {"env_info":{"interact_type":2,"robot_type":10000},"name":"…","msgs_limit":20}
36
+ → {"code":0,"session_id":"…"}
37
+
38
+ POST /cgi-bin/assistant/qa (SSE)
39
+ {"session_id":"…","robot_type":10000,"question":"…","question_type":2,
40
+ "command_info":{"question_info":{}},"model_info":{"model_type":3,"model_id":"official_3"}}
41
+ → MESSAGE {"Text":"DSH-IMA-OK"} … COMPLETED {"Code":0}
42
+ ```
43
+
44
+ - 多轮:同一 session 第一问“记住 7391”、第二问“刚才的数字”返回 7391。
45
+ - 长回答:9 个 `MESSAGE` 增量拼出完整 1..20。
46
+ - 思考模型:`THINKING {"Message":"…","Status":1}` 增量;最后一条 `Status:2` 是结束标记。
47
+ - `SUGGEST_QUESTION` 是建议列表,不是答案。
48
+
49
+ ### 登录态
50
+
51
+ ima 的 token 有两份:运行中客户端的内存(native bridge),以及客户端正常退出时写进
52
+ profile 的 `tencent.wxlogin.account_secret_encrypted`(DPAPI)。插件读后者,不读内存、
53
+ 不开 CDP、不要求粘贴 cookie。读到的 `token` 约 2 小时,`refresh_token` 约一年;
54
+ `/auth_login/refresh` 实测可换新 token(返回相对 7200 秒)。
55
+
56
+ ### IUA 的必要性
57
+
58
+ `x-ima-cookie` 里少了 `IMA-IUA`,服务端不报错,但会把请求当匿名:
59
+ 模型目录退回默认的 DeepSeek-V4.1-Flash / Hy3 / Hy4 / GLM,`assistant/qa` 返回 200
60
+ 却没有正文。补一个最小 IUA
61
+ (`PR=IMA&PP=com.tencent.imawin&PPVN=<版本>&PL=WIN&COVC=<Chromium 版本>&EV=`)
62
+ 就按账号目录回答。所以插件永远补 IUA。
63
+
64
+ ## UI 标签 vs 账号目录(2026-10-28 抓包)
65
+
66
+ 在 ima 2.6.15 客户端里选中 **DeepSeek-V4.1-Flash**(选项带 `_selected`),抓到的
67
+ `POST /cgi-bin/assistant/qa` 请求是:
68
+
69
+ | UI 模式 | 请求 `model_info` |
70
+ |---|---|
71
+ | 快速 | `{"model_type":3,"model_id":"official_3","enable_enhancement":true}` |
72
+ | 深度 | `{"model_type":1,"model_id":"official_1","enable_enhancement":true}` |
73
+
74
+ 同一账号的 `/model_manage/get_models` 把 `official_3` 标成 **DeepSeek V3.2**,把
75
+ `official_1` 标成 **DeepSeek V3.2 Think**。直接发 `official_3` 时 `QA_START` 自报
76
+ `"model_name":"DeepSeek V3.2"`。
77
+
78
+ **结论:这个账号的 UI 标签 “DeepSeek-V4.1-Flash” 实际落在 V3.2 的槽位上;UI 的默认模型
79
+ 列表和账号目录不一致。** 不同账号 / 客户端版本可能不同,不能拿 UI 标签当模型身份。
80
+
81
+ ## 与 CodeBuddy / 其它免费源的对比
82
+
83
+ 腾讯 CodeBuddy(CB)已经免费提供 HY3;本机 ima 账号的免费目录只有 DeepSeek V3.2 / Tencent HY 2.0,
84
+ 档位明显更旧。把两者放在一起:
85
+
86
+ | 免费源 | 档位 | 接入成本 | 结论 |
87
+ |---|---|---|---|
88
+ | CodeBuddy 免费 HY3 | HY3(更新) | 现成插件/账号 | 优先 |
89
+ | 本机 ima 账号 | DeepSeek V3.2 / HY 2.0 | 本插件 + 本机客户端 | 备胎 |
90
+ | 其它 ima 账号(可能) | V4.1-Flash / Hy4 / GLM-5.3 | 同一插件动态目录 | 取决于账号 |
91
+
92
+ **所以“免费”本身不是护城河。** 只有当某个 ima 账号的目录里有别人没有的模型,
93
+ 或者需要一个独立于 CB 的备用账号时,这个插件才有超出“技术演示”的价值。
94
+
95
+ ## 与现有实现的关系
96
+
97
+ | 实现 | 路径 | 问题 |
98
+ |---|---|---|
99
+ | `magpie-ima-auth`(npm) | 浏览器 cookie → 云端 `assistant/qa` | 登录要手工复制 `x-ima-cookie`;本质是把 ima 的云端 agent 会话包装成 chat(单问、无工具、system prompt 受限) |
100
+ | `opencli-plugin-ima` | 直接 API + WebContents/UI | 主要面向知识库问答;Windows 直接 API 遇到 600001;需要客户端/UI 自动化 |
101
+ | 本插件 | 本机客户端 profile → DPAPI 登录态 → 伪装请求头 | 不粘贴 cookie、运行时不需要 CDP;只走 `robot_type=10000` 的普通问答;模型目录/流式/思考/续期都按模型供应商做 |
102
+
103
+ ## 限制(如实写)
104
+
105
+ - **单问 session**:ima 的 `assistant/qa` 一次只收一个问题,没有 messages 数组;插件用
106
+ session 保持多轮,但 system prompt 只在 session 第一问里发。
107
+ - **没有工具调用**:ima 的问答接口没有 tool 通道;模型条目如实声明 `toolcall: false`。
108
+ - **没有 token 计数**:ima 不返回 usage;插件不按字符数编,返回 0。
109
+ - **没有上下文窗口**:模型目录不下发;`limit.context` 留 0,交给 magpie 的模型库。
110
+ - **私有接口**:随时可能变;ima 客户端升级后 IUA/字段可能需要跟着调。
111
+ - **登录导入平台**:DPAPI 解密目前只做 Windows;macOS 用种子文件 / `IMA_COPILOT_LOGIN_FILE`。
112
+ - **Copilot 不可用**:本机版本直接“暂不支持”,且它是 agent;插件默认不列。
113
+
114
+ ## 已完成的验收
115
+
116
+ - `node scripts/check.mjs`:通过 29 · 警告 0 · 失败 0
117
+ - `node --test`:10/10
118
+ - magpie 0.1.1814 安装后 `ima (ima, 4 models) signed in as 001ab…`
119
+ - 网关:`POST /v1/chat/completions`(`ima/deepseek-v3.2`)返回 `GATEWAY-OK`;
120
+ 流式返回 role/content/`finish_reason:"stop"`;`ima/deepseek-v3.2-think` 返回
121
+ `reasoning_content`。
122
+ - DSH headless(`dsh --profile headless` + patch,模型 `ima/tencent-hy-2.0`)返回
123
+ `DSH-IMA-OK`。
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "magpie-ima-local-auth",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "magpie / OpenCode provider plugin for the ima.copilot desktop app: its free DeepSeek and Tencent HY models, imported from the client already signed in on this machine, without pasting cookies.",
5
5
  "type": "module",
6
6
  "main": "./index.mjs",
package/src/chat.mjs CHANGED
@@ -244,16 +244,17 @@ export function streamOpenAI(res, modelId) {
244
244
  if (closed) return
245
245
  const bad = eventError(name, raw)
246
246
  if (bad) return fail(new Error(bad.message))
247
- if (name === "THINKING") {
247
+ // 旧版/知识库模式是 MESSAGE/THINKING;客户端 UI 的新版是 STRUCTURED_BLOCK
248
+ // 包着 Data.text_message / Data.thinking_message。两种都要认。
249
+ if (name === "THINKING" || name === "STRUCTURED_BLOCK") {
248
250
  const t = eventThinking(raw)
249
251
  if (t) delta({ reasoning_content: t })
250
- return
251
252
  }
252
- if (name === "MESSAGE") {
253
+ if (name === "MESSAGE" || name === "STRUCTURED_BLOCK") {
253
254
  const t = eventText(raw)
254
255
  if (t) delta({ content: t })
255
- return
256
256
  }
257
+ if (name === "THINKING" || name === "MESSAGE" || name === "STRUCTURED_BLOCK") return
257
258
  if (CONTROL.has(name)) finish()
258
259
  }).then(finish, fail)
259
260
  },
@@ -280,8 +281,8 @@ export async function aggregateOpenAI(res, modelId) {
280
281
  failed = new Error(bad.message)
281
282
  return
282
283
  }
283
- if (name === "THINKING") thinking += eventThinking(raw)
284
- else if (name === "MESSAGE") text += eventText(raw)
284
+ if (name === "THINKING" || name === "STRUCTURED_BLOCK") thinking += eventThinking(raw)
285
+ if (name === "MESSAGE" || name === "STRUCTURED_BLOCK") text += eventText(raw)
285
286
  })
286
287
  if (failed) throw failed
287
288
  return {