dsh-codex-subscription 2.4.0 → 2.4.2
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/README.en.md +18 -20
- package/README.md +28 -20
- package/lib/client.js +215 -9
- package/lib/index.js +108 -4
- package/package.json +1 -1
package/README.en.md
CHANGED
|
@@ -16,27 +16,12 @@ No OpenAI API key or Codex CLI. Models, search, quota, and image generation stay
|
|
|
16
16
|
[](LICENSE)
|
|
17
17
|
[](https://github.com/WSL043/dsh-codex-subscription/stargazers)
|
|
18
18
|
|
|
19
|
-
[
|
|
19
|
+
[Features](#feature-overview) · [Install](#install) · [Daily use](#inside-the-plugin) · [Examples](#from-sketch-to-image) · [User guide](docs/GUIDE.en.md) · [Update and uninstall](#update-and-uninstall)
|
|
20
20
|
|
|
21
21
|
</div>
|
|
22
22
|
|
|
23
23
|
<p align="center"><img src="docs/assets/product-account-demo-en.png" width="1100" alt="Codex subscription account and quota interface with model choices, quota windows and alerts; demonstration data"></p>
|
|
24
24
|
|
|
25
|
-
## What's new in 2.4.0
|
|
26
|
-
|
|
27
|
-
- **Stronger agent drawing (Beta).** A new SVG drawing command lets the model draw a whole layer in the notation it knows best; the result is still editable, undoable and exportable native strokes. Approximations such as gradients or clamped points are reported, and unsupported elements are refused by name.
|
|
28
|
-
- **New showcase.** GPT-6.1-Sol at Xhigh and GPT-6-Astra at Low compared side by side on a mechanical cutaway and a blue-green landscape, run on the official desktop app; see [From sketch to image](#from-sketch-to-image).
|
|
29
|
-
- **Desktop app fixes.** On the official desktop app the Codex subtask component now detects the host version and installs; support diagnostics report the real DSH version; a failed image request says whether it timed out or the connection dropped.
|
|
30
|
-
|
|
31
|
-
### 2.3.0
|
|
32
|
-
|
|
33
|
-
- **The official desktop app works.** The official DeepSeek Harness desktop app (0.2.0-rc.2) passed a hands-on acceptance run: plugin install, sign-in, model list, hiding models, a chat with a tool call, and image generation. See [Install](#install).
|
|
34
|
-
- **Models come only from your account.** The model list is read entirely from the account catalog; before sign-in or when the read fails no model is shown, and there is no built-in fallback. Under Models & runtime you can show or hide each model in the composer.
|
|
35
|
-
- **Settings reorganised.** Models and search are separate cards, switches use DSH's own control, and dead buttons no longer appear while signed out.
|
|
36
|
-
- **Ultrafast speed tier (Beta).** The new tier from OpenAI's developer event. It appears in the model menu only when your account catalog lists it for that model (today Pro 500 with GPT-6 Astra); other accounts never see it and it is never silently swapped for another tier. It is Beta because it has not been run on a Pro 500 account yet.
|
|
37
|
-
- **Shorter support diagnostics.** "Copy report" now copies the conclusions, recent failures and per-feature status (about 1 KB); the full report can still be copied separately from the details.
|
|
38
|
-
- **Subtasks and stability.** Codex subtasks now really take effect on 0.2.0 and no longer expose the apps connected to your account; image generation being rejected by the host on the desktop app is fixed (2.2.11).
|
|
39
|
-
|
|
40
25
|
## Feature overview
|
|
41
26
|
|
|
42
27
|
Subscription access, model controls, quota management, and image creation in one DSH workflow. Each capability is listed below; model access and quota depend on your account.
|
|
@@ -48,6 +33,7 @@ Subscription access, model controls, quota management, and image creation in one
|
|
|
48
33
|
| **Subscription sign-in** | Sign in to ChatGPT and use Codex subscription models without an API key | Normal chat needs no Codex CLI |
|
|
49
34
|
| **Model catalog sync** | Read available models and reasoning levels from your account, with manual refresh; models marked for retirement show their retirement date next to the model name, without automatically switching your selection | New models appear when your account offers them; the account catalog is the only source, so signed out or when it cannot be read no models are shown and no bundled list stands in |
|
|
50
35
|
| **Model list** | Show or hide individual models in the composer picker under Models & runtime | Display only; selected models and requests still work |
|
|
36
|
+
| **Default model** | Choose the model a new conversation opens with under Models & runtime → Models | Writes the DSH default model setting, the same one a model switch inside a chat writes; unset it to follow the DSH default |
|
|
51
37
|
| **Reasoning levels** | Choose supported reasoning effort in the composer | Levels vary by model |
|
|
52
38
|
| **Speed tiers** | Switch supported models between Standard and Fast; Ultrafast (Beta) too when the account catalog offers it, with a lightning indicator | Standard by default; Fast and Ultrafast increase usage, and Ultrafast is Pro 500 only today |
|
|
53
39
|
| **Response verbosity** | Request short, medium, or detailed responses | Follows the model default unless changed |
|
|
@@ -119,7 +105,7 @@ This plugin supports the latest DeepSeek Harness release recorded in its package
|
|
|
119
105
|
2. Paste this package name, with its version, into the **Package name or address** field:
|
|
120
106
|
|
|
121
107
|
```text
|
|
122
|
-
dsh-codex-subscription@2.4.
|
|
108
|
+
dsh-codex-subscription@2.4.2
|
|
123
109
|
```
|
|
124
110
|
|
|
125
111
|
3. Click **Install** and wait for completion. Follow the page instructions; save your work before restarting if requested.
|
|
@@ -198,9 +184,9 @@ Draw by hand with the canvas button, or ask the agent with `@sketch` and your dr
|
|
|
198
184
|
The prompt (sent in Chinese): draw "Lighthouse and Homecoming" on a 4:3 canvas — a red-and-white lighthouse on a rocky cape casting a fan of light, an orange-sailed fishing boat heading home with a V-shaped wake, a half-risen sun, three cloud bands, three gulls and surf around the rocks, in six named layers; then turn the sketch into a warm watercolor travel poster with no text, keeping the composition.
|
|
199
185
|
|
|
200
186
|
<details>
|
|
201
|
-
<summary>Advanced examples · Mechanical cutaway
|
|
187
|
+
<summary>Advanced examples · Mechanical cutaway, blue-green landscape and a reference-copy challenge</summary>
|
|
202
188
|
|
|
203
|
-
|
|
189
|
+
The first two subjects were chosen to expose quality differences: a mechanical cutaway tests structure and detail (meshing gears, pendulum, chains, tiny figures on a staircase), and a Song-dynasty blue-green landscape tests composition and taste (the "three distances", empty space, texture strokes and mineral color). The same prompt went to **GPT-6.1-Sol · Xhigh** and **GPT-6-Astra · Low**, one run each, on the official desktop app, with GPT Image 2 (quality: high).
|
|
204
190
|
|
|
205
191
|
**Clock Tower Cutaway**
|
|
206
192
|
|
|
@@ -222,7 +208,19 @@ Sol first computed tooth counts (48, 38, 27, 46, 36, 24, 34, 30, 22) and pitch c
|
|
|
222
208
|
|
|
223
209
|
Sol Xhigh took about 28 minutes and Astra Low about 5. Both kept the main peak, waterfall, plank path and river in place; Sol's receding ranges and mist bands are more complete.
|
|
224
210
|
|
|
225
|
-
|
|
211
|
+
**"DeepSeek-chan" · copy a reference image (draw only, no image generation)**
|
|
212
|
+
|
|
213
|
+
Here the reference image is attached to the message and the model copies it on the canvas, which tests proportions, gradient long hair, lace trim, hand lettering and small motifs. The reference is a community sticker of the DeepSeek mascot girl. Each cell is one run on the official desktop app with no image generation; the native-stroke runs had "return preview when finished" enabled, and the SVG runs added one sentence to the same prompt asking for the svg command on every layer.
|
|
214
|
+
|
|
215
|
+
<table>
|
|
216
|
+
<tr><th width="20%">Reference</th><th width="40%">Native strokes</th><th width="40%">SVG</th></tr>
|
|
217
|
+
<tr><td rowspan="2"><img src="docs/assets/sketch-niang-reference.webp" alt="DeepSeek-chan sticker reference" width="220"></td><td><img src="docs/assets/sketch-niang-sol-native.webp" alt="Sol native strokes" width="330"><br><sub><b>Sol Xhigh</b> · 40 min 50 s · 526 strokes</sub></td><td><img src="docs/assets/sketch-niang-sol-svg.webp" alt="Sol SVG" width="330"><br><sub><b>Sol Xhigh</b> · 31 min 48 s · 463 strokes</sub></td></tr>
|
|
218
|
+
<tr><td><img src="docs/assets/sketch-niang-astra-native.webp" alt="Astra native strokes" width="330"><br><sub><b>Astra Medium</b> · about 7 min · 332 strokes</sub></td><td><img src="docs/assets/sketch-niang-astra-svg.webp" alt="Astra SVG" width="330"><br><sub><b>Astra Medium</b> · 10 min 5 s</sub></td></tr>
|
|
219
|
+
</table>
|
|
220
|
+
|
|
221
|
+
The SVG runs have finer hair highlights, lace trim and lettering, and Sol was almost 9 minutes faster with SVG than stroke by stroke; Astra spent about 3 extra minutes on SVG for clearly richer detail. Neither model got the face shape right (too long and flat) or the small whale motif on the apron, though Sol's whale looks more like a whale.
|
|
222
|
+
|
|
223
|
+
The full Chinese prompts for all three subjects are in the [Chinese README](README.md#从草图到作品).
|
|
226
224
|
|
|
227
225
|
Each example is a single run, not a measure of consistent quality. Sol Xhigh is much slower; Astra or a lower reasoning level is enough for everyday sketches.
|
|
228
226
|
|
package/README.md
CHANGED
|
@@ -16,27 +16,12 @@
|
|
|
16
16
|
[](LICENSE)
|
|
17
17
|
[](https://github.com/WSL043/dsh-codex-subscription/stargazers)
|
|
18
18
|
|
|
19
|
-
[
|
|
19
|
+
[功能](#功能一览) · [安装](#安装) · [日常使用](#界面一览) · [作品案例](#从草图到作品) · [使用指南](docs/GUIDE.zh-CN.md) · [更新与卸载](#更新与卸载)
|
|
20
20
|
|
|
21
21
|
</div>
|
|
22
22
|
|
|
23
23
|
<p align="center"><img src="docs/assets/product-account-demo.png" width="1100" alt="Codex 订阅账号与额度界面:模型选择、双周期额度与提醒;使用演示数据"></p>
|
|
24
24
|
|
|
25
|
-
## 2.4.0 更新亮点
|
|
26
|
-
|
|
27
|
-
- **Agent 绘图更强(Beta)**:新增 SVG 绘图命令,模型可用最擅长的 SVG 一次画完一整层,导入后仍是可编辑、可撤销、可导出的原生笔画;渐变、越界等近似处理会明确回报,不支持的元素会点名拒绝。
|
|
28
|
-
- **全新作品案例**:在官方桌面版上用 GPT-6.1-Sol · Xhigh 与 GPT-6-Astra · Low 实测,机械剖面与青绿山水两道题并排对照,见[从草图到作品](#从草图到作品)。
|
|
29
|
-
- **桌面版修复**:官方桌面版上 Codex 子任务组件现在能正确识别宿主版本并安装;支持诊断会报告真实的 DSH 版本;图片请求网络失败时会说明是超时还是连接中断。
|
|
30
|
-
|
|
31
|
-
### 2.3.0
|
|
32
|
-
|
|
33
|
-
- **官方桌面端可用**:DeepSeek Harness 官方桌面版(0.2.0-rc.2)已完成实机验收——安装插件、登录、模型列表、隐藏模型、带工具调用的对话、图片生成均通过;安装方式见[安装](#安装)。
|
|
34
|
-
- **模型只来自你的账号**:模型列表完全读取账号目录,登录前或读取失败时不显示任何模型,也没有内置兜底;“模型与运行”里可逐个显示 / 隐藏输入框中的模型。
|
|
35
|
-
- **设置页重新整理**:模型与搜索分成两个卡片,开关统一使用 DSH 自带控件,未登录时不再出现无效按钮。
|
|
36
|
-
- **极速档 Ultrafast(Beta)**:OpenAI 发布会新增的速度档。只有账号模型目录明确给出该档位(目前为 Pro 500 的 GPT-6 Astra)才会在模型菜单里出现,其他账号不显示,也不会被悄悄降级到别的档位;由于暂无 Pro 500 账号做实机验证,标为 Beta。
|
|
37
|
-
- **更短的支持诊断**:“复制诊断”现在只复制结论、近期失败和各能力状态(约 1 KB),完整报告仍可在详情里单独复制。
|
|
38
|
-
- **子任务与稳定性**:Codex 子任务在 0.2.0 上真正生效,并且不再暴露账号里连接的应用;修复了图片生成在桌面版上被宿主拒绝的问题(2.2.11)。
|
|
39
|
-
|
|
40
25
|
## 功能一览
|
|
41
26
|
|
|
42
27
|
把订阅接入、模型控制、额度管理和图片创作放在同一个 DSH 工作流里。下面逐项列出插件提供的能力;模型权限和额度以账号实际返回为准。
|
|
@@ -48,6 +33,7 @@
|
|
|
48
33
|
| **订阅登录** | 直接登录 ChatGPT,使用 Codex 订阅模型,无需 API Key | 普通聊天无需 Codex CLI |
|
|
49
34
|
| **模型目录同步** | 自动读取账号可用模型与推理档位,支持手动刷新;目录标注退役的模型会在模型名称旁显示退役日期,不会自动切换你的选择 | 新型号以账号目录开放情况为准;模型只来自账号目录,未登录或读取失败时不显示任何模型,也不使用内置列表 |
|
|
50
35
|
| **模型列表** | 在“模型与运行”中逐个显示或隐藏输入框中的模型 | 仅影响列表显示;已选模型和请求不受影响 |
|
|
36
|
+
| **默认模型** | 在“模型与运行 → 模型”里选择每次新建会话默认使用的模型 | 写入 DSH 的默认模型设置,与在对话里切换模型是同一处;未设置时跟随 DSH 默认 |
|
|
51
37
|
| **推理等级** | 在输入框选择模型支持的推理档位 | 档位随模型变化 |
|
|
52
38
|
| **速度档位** | 在支持的模型上切换标准 / Fast;账号目录提供时还有 Ultrafast(Beta),输入框显示闪电标识 | 默认标准;Fast 和 Ultrafast 会增加用量消耗,Ultrafast 目前仅 Pro 500 |
|
|
53
39
|
| **输出详略** | 选择简短、适中或详细的回答偏好 | 默认跟随模型 |
|
|
@@ -119,7 +105,7 @@
|
|
|
119
105
|
2. 在 **包名或地址** 输入框中粘贴下面的包名(已带版本号):
|
|
120
106
|
|
|
121
107
|
```text
|
|
122
|
-
dsh-codex-subscription@2.4.
|
|
108
|
+
dsh-codex-subscription@2.4.2
|
|
123
109
|
```
|
|
124
110
|
|
|
125
111
|
3. 点击 **安装**,等待安装完成;按页面提示操作,需要重启时先保存工作。
|
|
@@ -200,9 +186,9 @@ dsh --profile headless "只回复:ok"
|
|
|
200
186
|
```
|
|
201
187
|
|
|
202
188
|
<details>
|
|
203
|
-
<summary>进阶展示 ·
|
|
189
|
+
<summary>进阶展示 · 机械剖面、青绿山水与 DeepSeek 娘临摹</summary>
|
|
204
190
|
|
|
205
|
-
|
|
191
|
+
前两道题都选了容易暴露差距的题材:机械剖面考结构与细节(齿轮咬合、摆锤、链条、楼梯上的人物),青绿山水考构图与审美(三远法、留白、皴法与设色)。同一条提示词分别交给 **GPT-6.1-Sol · Xhigh** 和 **GPT-6-Astra · Low**,各跑一次,均在官方桌面版上完成,生图统一为 GPT Image 2(质量:高)。
|
|
206
192
|
|
|
207
193
|
**《钟塔剖面图》**
|
|
208
194
|
|
|
@@ -224,8 +210,20 @@ Sol 先用脚本算出 9 个齿轮的齿数(48、38、27、46、36、24、34
|
|
|
224
210
|
|
|
225
211
|
Sol Xhigh 约 28 分钟,Astra Low 约 5 分钟。两者都保留了主峰、瀑布、栈道与江面的位置;Sol 的远山层次和雾带留白更完整。
|
|
226
212
|
|
|
213
|
+
**《DeepSeek 娘》· 照着参考图临摹(只画不生图)**
|
|
214
|
+
|
|
215
|
+
这道题把一张参考图作为附件发给模型,让它在画板上临摹,考的是比例、渐变长发、蕾丝褶边、手写字和小图案能不能对得上。参考图是社区流传的 DeepSeek 娘表情包。每格都在官方桌面版上跑一次,没有调用生图;原生笔画版开启了“完成后返回预览”,SVG 版在同一条提示词后加了一句“每层用 svg 命令”。
|
|
216
|
+
|
|
217
|
+
<table>
|
|
218
|
+
<tr><th width="20%">参考图</th><th width="40%">原生笔画</th><th width="40%">SVG</th></tr>
|
|
219
|
+
<tr><td rowspan="2"><img src="docs/assets/sketch-niang-reference.webp" alt="DeepSeek 娘表情包参考图" width="220"></td><td><img src="docs/assets/sketch-niang-sol-native.webp" alt="Sol 原生笔画版" width="330"><br><sub><b>Sol Xhigh</b> · 40 分 50 秒 · 526 笔</sub></td><td><img src="docs/assets/sketch-niang-sol-svg.webp" alt="Sol SVG 版" width="330"><br><sub><b>Sol Xhigh</b> · 31 分 48 秒 · 463 笔</sub></td></tr>
|
|
220
|
+
<tr><td><img src="docs/assets/sketch-niang-astra-native.webp" alt="Astra 原生笔画版" width="330"><br><sub><b>Astra Medium</b> · 约 7 分钟 · 332 笔</sub></td><td><img src="docs/assets/sketch-niang-astra-svg.webp" alt="Astra SVG 版" width="330"><br><sub><b>Astra Medium</b> · 10 分 5 秒</sub></td></tr>
|
|
221
|
+
</table>
|
|
222
|
+
|
|
223
|
+
SVG 版的发丝高光、蕾丝褶边和手写字更精细,Sol 用 SVG 还比逐笔绘制快了近 9 分钟;Astra 用 SVG 多花约 3 分钟,换来明显更丰富的细节。两个模型都没能画准脸型(偏长偏平)和围裙上的小鲸鱼图案,Sol 的鲸鱼更像鲸。
|
|
224
|
+
|
|
227
225
|
<details>
|
|
228
|
-
<summary
|
|
226
|
+
<summary>展开三道题的完整提示词</summary>
|
|
229
227
|
|
|
230
228
|
```text
|
|
231
229
|
@sketch 用 3:4 竖版画板绘制《钟塔剖面图》:蒸汽朋克风格的钟塔纵向剖面技术插图。最上方是圆形大钟面(十二个刻度、两根指针)和一口铜钟;钟面下一层是齿轮机房:至少 9 个大小不同、齿数正确、彼此咬合的齿轮(相邻齿轮转向相反,齿廓要画出锯齿),另有一个锚形擒纵机构;中段是一根贯穿的长摆杆,末端为铜制圆盘摆锤,旁边两条挂着配重铁块的链条;塔壁一侧是沿墙盘旋而上的螺旋楼梯,梯上有三个微小的工匠人物;底部是石砌地基与拱门。剖面用厚实的暗色砖石墙体框出,内部露出黄铜与铁质结构,加入铆钉、管道,以及从小窗透进来的光柱。按背景砖墙、结构框架、齿轮组、摆锤与链条、楼梯与人物、光影与细节分层绘制。画完后,把这张草图作为唯一参考图,调用订阅图片工具一次生成成品:保持每个部件的位置、比例与咬合关系不变,做成精密的蒸汽朋克剖面图插画——黄铜与旧钢的金属质感、细致的机械倒影和铆钉、羊皮纸底色配墨线渲染、暖色灯光,不添加文字。
|
|
@@ -235,6 +233,16 @@ Sol Xhigh 约 28 分钟,Astra Low 约 5 分钟。两者都保留了主峰、
|
|
|
235
233
|
@sketch 用 3:4 竖版画板绘制《千峰翠色》:宋代青绿山水的构图,严格运用「三远法」。高远:右侧一座主峰拔地而起,占画面上半部,山体用层叠的块面表现,山腰有横向的云雾留白;深远:主峰后方还有两重淡青色远山,越远越淡,之间隔着大片留白的雾带;平远:下方是舒展的江面,一叶渔舟和两只飞鸟。左侧一挂瀑布从中段峭壁倾泻而下,落入山涧,涧边有三株松树,松针成簇;山腰有一座小亭和一条曲折栈道,栈道上有两个极小的行者;前景是坡石与芦苇,用勾勒加披麻皴式的笔触表现。色彩层次为石青、石绿、赭石,远山用淡青。按远山与天空、雾带留白、主峰、瀑布与松树、亭台栈道与行者、江面舟鸟与前景分层绘制。画完后,把这张草图作为唯一参考图,调用订阅图片工具一次生成成品:保持山体、瀑布、栈道、江面的位置和三远法的层次不变,做成宋代青绿山水绢本设色——石青石绿矿物颜料的沉着厚重、细腻的皴擦与勾勒、绢面纹理与微微泛黄的古意、云雾留白,不添加文字或印章。
|
|
236
234
|
```
|
|
237
235
|
|
|
236
|
+
```text
|
|
237
|
+
@sketch 用 1:1 方形画板,尽可能忠实地临摹我附上的这张参考图(一张 Q 版二次元表情包)。画面:白色底;Q 版二头身的蓝发鲸鱼娘跪坐在画面右侧偏中,蓝色渐变长发披肩(发根深蓝、发梢浅蓝),头顶一根呆毛,戴白色蕾丝女仆头饰和蓝色蝴蝶结,头两侧是深蓝色带白色内里的鲸鱼耳鳍,蓝色大眼睛带高光,猫嘴嘟嘴的“ω”表情,脸颊泛红,双手叉腰;穿深蓝色女仆装,白色蕾丝围裙(围裙上有一只蓝色小鲸鱼图案),黑色领结,袖口和裙摆有白色蕾丝褶边;身后露出一条深蓝色的鲸鱼尾巴。左上方是白色对话气泡(黑色描边,尖角指向她),气泡里用黑色粗体写“你这吃白饭的蓝色大肥鱼。”;左侧从画面外伸进来一只黑袖子的手,食指指向她;她的左下方用蓝色描边字写“没吃饱喵!”;她脚边的地上放着一只空的白瓷饭碗,碗内壁印着一只蓝色小鲸鱼。请分层绘制:白色背景、头发与鲸鱼耳鳍与尾巴、身体与服装、脸部五官、饭碗、手臂与对话气泡文字,保留原生可编辑笔画,并特别注意角色比例、头发的渐变与发丝走向、蕾丝褶边和脸部表情的细节。这次只在草图画布上画,不要调用任何生图或图片编辑工具;画完后检查一遍与参考图的差异并修正,最后保存并完成。
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
SVG 版在“这次只在草图画布上画”之前多加了一句:
|
|
241
|
+
|
|
242
|
+
```text
|
|
243
|
+
作画方式:每个图层都用 svg 命令整层写成 SVG(路径用贝塞尔曲线,配色手动分层做出渐变感),不要逐点使用原生笔画命令。
|
|
244
|
+
```
|
|
245
|
+
|
|
238
246
|
</details>
|
|
239
247
|
|
|
240
248
|
每个例子只跑一次,不代表稳定水平;Sol Xhigh 耗时明显更长,日常草图用 Astra 或较低推理档即可。
|
package/lib/client.js
CHANGED
|
@@ -886,6 +886,8 @@ window.__ModuleLoader__.load({
|
|
|
886
886
|
"preferences/status",
|
|
887
887
|
"preferences/models",
|
|
888
888
|
"preferences/update",
|
|
889
|
+
"default-model/status",
|
|
890
|
+
"default-model/select",
|
|
889
891
|
"runtime/status",
|
|
890
892
|
"runtime/install",
|
|
891
893
|
"runtime/remove",
|
|
@@ -3111,6 +3113,9 @@ window.__ModuleLoader__.load({
|
|
|
3111
3113
|
if (report && clamped) report.clampedPoints = (report.clampedPoints ?? 0) + clamped;
|
|
3112
3114
|
return out;
|
|
3113
3115
|
}
|
|
3116
|
+
//#endregion
|
|
3117
|
+
//#region src/sketch-commands.js
|
|
3118
|
+
const MAX_SKETCH_POINTS = 2e5;
|
|
3114
3119
|
const SKETCH_COMMAND_HELP = {
|
|
3115
3120
|
coordinates: "Assign short meaningful stroke id values for later edits. Text uses two opposite box corners and text content; width is font size in pixels, automatic fitting within the box. Arrow uses two endpoints. Normalized x/y in [0,1]; width is canvas pixels. Read documentId and revision before editing.",
|
|
3116
3121
|
shapes: "line: exactly two endpoints; rectangle/circle (ellipse alias accepted): exactly two opposite bounding-box corners (circle draws an ellipse within that box); polygon: three or more vertices, closed automatically; pen: ordered path points. bezier: start point, then groups of control1/control2/end; use 4 points for one cubic curve, max 64 segments. Prefer bezier for smooth designed curves instead of many pen samples. fill:true closes and fills the curve. fill:true fills rectangle/circle/polygon. Layers and strokes paint in list order, later ones on top. All commands needed for drawing are described here; no source-code search is required.",
|
|
@@ -3126,7 +3131,7 @@ window.__ModuleLoader__.load({
|
|
|
3126
3131
|
limits: {
|
|
3127
3132
|
strokes: MAX_SKETCH_STROKES,
|
|
3128
3133
|
pointsPerStroke: MAX_STROKE_POINTS,
|
|
3129
|
-
pointsTotal:
|
|
3134
|
+
pointsTotal: MAX_SKETCH_POINTS,
|
|
3130
3135
|
commandsPerBatch: 256,
|
|
3131
3136
|
svgCharacters: MAX_SVG_CHARACTERS
|
|
3132
3137
|
}
|
|
@@ -3294,7 +3299,9 @@ window.__ModuleLoader__.load({
|
|
|
3294
3299
|
} : item)
|
|
3295
3300
|
};
|
|
3296
3301
|
}
|
|
3297
|
-
|
|
3302
|
+
const strokes = strokeCount(doc), points = doc.layers.reduce((n, l) => n + l.strokes.reduce((m, s) => m + s.points.length, 0), 0);
|
|
3303
|
+
if (strokes > 2e3) throw Error(`Sketch would hold ${strokes} strokes; the limit is ${MAX_SKETCH_STROKES}. Merge shapes or drop small details, then send this batch again`);
|
|
3304
|
+
if (points > 2e5) throw Error(`Sketch would hold ${points} points; the limit is ${MAX_SKETCH_POINTS}. Use fewer or simpler paths, then send this batch again`);
|
|
3298
3305
|
return doc;
|
|
3299
3306
|
}
|
|
3300
3307
|
function createSketchCommandSession(adapter) {
|
|
@@ -5536,6 +5543,14 @@ window.__ModuleLoader__.load({
|
|
|
5536
5543
|
advancedModelSearch: "模型与搜索",
|
|
5537
5544
|
modelsSectionTitle: "模型",
|
|
5538
5545
|
searchSectionTitle: "搜索",
|
|
5546
|
+
defaultModelTitle: "默认模型",
|
|
5547
|
+
defaultModelHint: "新建会话时默认使用的模型,与在对话里切换模型写的是同一处 DSH 默认模型设置。",
|
|
5548
|
+
defaultModelFollow: "跟随 DSH 默认",
|
|
5549
|
+
defaultModelFollowHint: "当前跟随 DSH 默认模型:{value}。选择一个 Codex 模型,之后每次新建会话都用它。",
|
|
5550
|
+
defaultModelUnknown: "未知",
|
|
5551
|
+
defaultModelUnavailable: "当前 DSH 版本没有提供默认模型服务,无法在这里设置。",
|
|
5552
|
+
defaultModelNoCatalog: "登录并加载模型后即可选择默认模型。",
|
|
5553
|
+
defaultModelFailed: "默认模型读取或保存失败,请重试,或改在对话中切换模型。",
|
|
5539
5554
|
inputImageDetail: "输入图片精度",
|
|
5540
5555
|
inputImageDetailHint: "控制发送给模型的图片精度,精度越高输入 token 用量越大。",
|
|
5541
5556
|
inputImageDetail_auto: "自动",
|
|
@@ -6094,6 +6109,14 @@ window.__ModuleLoader__.load({
|
|
|
6094
6109
|
advancedModelSearch: "Models and search",
|
|
6095
6110
|
modelsSectionTitle: "Models",
|
|
6096
6111
|
searchSectionTitle: "Search",
|
|
6112
|
+
defaultModelTitle: "Default model",
|
|
6113
|
+
defaultModelHint: "The model a new conversation opens with. This writes the same DSH default model setting as switching the model inside a chat.",
|
|
6114
|
+
defaultModelFollow: "Follow DSH default",
|
|
6115
|
+
defaultModelFollowHint: "Following the DSH default: {value}. Pick a Codex model to make every new conversation start with it.",
|
|
6116
|
+
defaultModelUnknown: "unknown",
|
|
6117
|
+
defaultModelUnavailable: "This DSH version provides no default-model service, so it cannot be set here.",
|
|
6118
|
+
defaultModelNoCatalog: "Sign in and load models to choose a default model.",
|
|
6119
|
+
defaultModelFailed: "Reading or saving the default model failed. Retry, or switch the model inside a chat.",
|
|
6097
6120
|
inputImageDetail: "Input image detail",
|
|
6098
6121
|
inputImageDetailHint: "Controls the detail level of images sent to the model. Higher detail uses more input tokens.",
|
|
6099
6122
|
inputImageDetail_auto: "Auto",
|
|
@@ -8083,7 +8106,6 @@ window.__ModuleLoader__.load({
|
|
|
8083
8106
|
verbosityModels = Array.isArray(value?.verbosityModels) ? value.verbosityModels : [];
|
|
8084
8107
|
fastModels = Array.isArray(value?.fastModels) ? value.fastModels : void 0;
|
|
8085
8108
|
ultrafastModels = Array.isArray(value?.ultrafastModels) ? value.ultrafastModels : [];
|
|
8086
|
-
ultrafastModels = Array.isArray(value?.ultrafastModels) ? value.ultrafastModels : [];
|
|
8087
8109
|
catalogStatus = value?.catalogStatus;
|
|
8088
8110
|
}
|
|
8089
8111
|
} else acceptFallback(value);
|
|
@@ -8133,6 +8155,21 @@ window.__ModuleLoader__.load({
|
|
|
8133
8155
|
}
|
|
8134
8156
|
}
|
|
8135
8157
|
};
|
|
8158
|
+
const accepted = (entries, wait = 1500) => new Promise((resolve) => {
|
|
8159
|
+
const matches = () => entries.every(([field, value]) => JSON.stringify(nativeSnapshot().value?.[field]) === JSON.stringify(value));
|
|
8160
|
+
if (matches()) return resolve(true);
|
|
8161
|
+
let timer;
|
|
8162
|
+
const stop = scope.subscribe(() => {
|
|
8163
|
+
if (!matches()) return;
|
|
8164
|
+
clearTimeout(timer);
|
|
8165
|
+
stop();
|
|
8166
|
+
resolve(true);
|
|
8167
|
+
});
|
|
8168
|
+
timer = setTimeout(() => {
|
|
8169
|
+
stop();
|
|
8170
|
+
resolve(matches());
|
|
8171
|
+
}, wait);
|
|
8172
|
+
});
|
|
8136
8173
|
const set = async (patch) => {
|
|
8137
8174
|
if (disposed || snapshot.status !== "ready" || snapshot.writable !== true) return;
|
|
8138
8175
|
const current = ++generation;
|
|
@@ -8149,8 +8186,7 @@ window.__ModuleLoader__.load({
|
|
|
8149
8186
|
await scope.set(field, value);
|
|
8150
8187
|
}
|
|
8151
8188
|
if (current !== generation) return;
|
|
8152
|
-
|
|
8153
|
-
error = entries.some(([field, value]) => JSON.stringify(accepted?.[field]) !== JSON.stringify(value));
|
|
8189
|
+
error = !await accepted(entries);
|
|
8154
8190
|
if (error) failedPatch = patch;
|
|
8155
8191
|
pendingPatch = void 0;
|
|
8156
8192
|
} else {
|
|
@@ -8191,6 +8227,97 @@ window.__ModuleLoader__.load({
|
|
|
8191
8227
|
};
|
|
8192
8228
|
}
|
|
8193
8229
|
//#endregion
|
|
8230
|
+
//#region src/default-model-controller.js
|
|
8231
|
+
const INITIAL = Object.freeze({
|
|
8232
|
+
status: "loading",
|
|
8233
|
+
available: false,
|
|
8234
|
+
managed: false,
|
|
8235
|
+
provider: void 0,
|
|
8236
|
+
model: void 0,
|
|
8237
|
+
reasoningEffort: void 0,
|
|
8238
|
+
saving: false,
|
|
8239
|
+
error: false
|
|
8240
|
+
});
|
|
8241
|
+
const adopt = (value) => ({
|
|
8242
|
+
status: "ready",
|
|
8243
|
+
error: false,
|
|
8244
|
+
available: value?.available === true,
|
|
8245
|
+
managed: value?.managed === true,
|
|
8246
|
+
provider: value?.provider,
|
|
8247
|
+
model: value?.model,
|
|
8248
|
+
reasoningEffort: value?.reasoningEffort
|
|
8249
|
+
});
|
|
8250
|
+
/**
|
|
8251
|
+
* Read and update the DSH default model behind one settings control. The Host
|
|
8252
|
+
* owns the value, so a load always replaces the local projection; a rejected
|
|
8253
|
+
* write keeps the last known value and only raises the error flag.
|
|
8254
|
+
*/
|
|
8255
|
+
function createDefaultModelController(rpc) {
|
|
8256
|
+
let snapshot = INITIAL;
|
|
8257
|
+
let disposed = false;
|
|
8258
|
+
let generation = 0;
|
|
8259
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
8260
|
+
const publish = (next) => {
|
|
8261
|
+
snapshot = Object.freeze({
|
|
8262
|
+
...snapshot,
|
|
8263
|
+
...next
|
|
8264
|
+
});
|
|
8265
|
+
for (const listener of listeners) listener();
|
|
8266
|
+
};
|
|
8267
|
+
const load = async () => {
|
|
8268
|
+
const current = ++generation;
|
|
8269
|
+
try {
|
|
8270
|
+
const value = unwrap(await rpc.call(CHANNEL, "default-model/status", {}));
|
|
8271
|
+
if (disposed || current !== generation) return;
|
|
8272
|
+
publish(adopt(value));
|
|
8273
|
+
} catch {
|
|
8274
|
+
if (disposed || current !== generation) return;
|
|
8275
|
+
publish({
|
|
8276
|
+
status: "error",
|
|
8277
|
+
error: true
|
|
8278
|
+
});
|
|
8279
|
+
}
|
|
8280
|
+
};
|
|
8281
|
+
const select = async (model) => {
|
|
8282
|
+
if (disposed) return false;
|
|
8283
|
+
const current = ++generation;
|
|
8284
|
+
publish({
|
|
8285
|
+
saving: true,
|
|
8286
|
+
error: false
|
|
8287
|
+
});
|
|
8288
|
+
try {
|
|
8289
|
+
const value = unwrap(await rpc.call(CHANNEL, "default-model/select", { model }));
|
|
8290
|
+
if (disposed || current !== generation) return false;
|
|
8291
|
+
publish({
|
|
8292
|
+
...adopt(value),
|
|
8293
|
+
saving: false
|
|
8294
|
+
});
|
|
8295
|
+
return true;
|
|
8296
|
+
} catch {
|
|
8297
|
+
if (disposed || current !== generation) return false;
|
|
8298
|
+
publish({
|
|
8299
|
+
saving: false,
|
|
8300
|
+
error: true
|
|
8301
|
+
});
|
|
8302
|
+
return false;
|
|
8303
|
+
}
|
|
8304
|
+
};
|
|
8305
|
+
return Object.freeze({
|
|
8306
|
+
getSnapshot: () => snapshot,
|
|
8307
|
+
subscribe: (listener) => {
|
|
8308
|
+
listeners.add(listener);
|
|
8309
|
+
return () => listeners.delete(listener);
|
|
8310
|
+
},
|
|
8311
|
+
load,
|
|
8312
|
+
select,
|
|
8313
|
+
dispose: () => {
|
|
8314
|
+
disposed = true;
|
|
8315
|
+
generation += 1;
|
|
8316
|
+
listeners.clear();
|
|
8317
|
+
}
|
|
8318
|
+
});
|
|
8319
|
+
}
|
|
8320
|
+
//#endregion
|
|
8194
8321
|
//#region src/account-status-controller.js
|
|
8195
8322
|
const DEFAULT_TIMEOUT_MS = 1e4;
|
|
8196
8323
|
const STATUS_ERROR_CODES = /* @__PURE__ */ new Set([
|
|
@@ -8476,7 +8603,7 @@ window.__ModuleLoader__.load({
|
|
|
8476
8603
|
}
|
|
8477
8604
|
//#endregion
|
|
8478
8605
|
//#region src/version.js
|
|
8479
|
-
const PACKAGE_VERSION = "2.4.
|
|
8606
|
+
const PACKAGE_VERSION = "2.4.2";
|
|
8480
8607
|
//#endregion
|
|
8481
8608
|
//#region src/client-recovery.js
|
|
8482
8609
|
async function recoveryCall(rpc, endpoint, payload = {}, timeoutMs = 1e4) {
|
|
@@ -9378,6 +9505,76 @@ window.__ModuleLoader__.load({
|
|
|
9378
9505
|
] });
|
|
9379
9506
|
}
|
|
9380
9507
|
//#endregion
|
|
9508
|
+
//#region src/default-model-preferences.jsx
|
|
9509
|
+
/**
|
|
9510
|
+
* Choose the model a new conversation opens with. DSH owns that selection, so
|
|
9511
|
+
* the control always shows the live value, including a model chosen in a chat
|
|
9512
|
+
* and any non-subscription default the user set elsewhere.
|
|
9513
|
+
*/
|
|
9514
|
+
function DefaultModelPreference({ preference, defaultModel, t }) {
|
|
9515
|
+
const snapshot = (0, react.useSyncExternalStore)(defaultModel.subscribe, defaultModel.getSnapshot);
|
|
9516
|
+
const models = usePreferenceSnapshot(preference).availableModels;
|
|
9517
|
+
const [open, setOpen] = (0, react.useState)(false);
|
|
9518
|
+
(0, react.useEffect)(() => {
|
|
9519
|
+
defaultModel.load();
|
|
9520
|
+
}, [defaultModel]);
|
|
9521
|
+
const selected = models.find((model) => model.id === snapshot.model);
|
|
9522
|
+
const label = snapshot.managed ? selected?.name ?? snapshot.model : t("defaultModelFollow");
|
|
9523
|
+
const current = snapshot.provider === void 0 ? t("defaultModelUnknown") : `${snapshot.provider} / ${snapshot.model ?? t("defaultModelUnknown")}`;
|
|
9524
|
+
const hint = snapshot.status === "error" ? t("defaultModelFailed") : snapshot.available !== true ? t("defaultModelUnavailable") : models.length === 0 ? t("defaultModelNoCatalog") : snapshot.managed ? t("defaultModelHint") : fill(t("defaultModelFollowHint"), { value: current });
|
|
9525
|
+
const items = models.map((model) => ({
|
|
9526
|
+
id: model.id,
|
|
9527
|
+
label: model.name
|
|
9528
|
+
}));
|
|
9529
|
+
const disabled = snapshot.saving || snapshot.available !== true || models.length === 0;
|
|
9530
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
9531
|
+
className: "codexSubscriptionPreference",
|
|
9532
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
9533
|
+
className: "codexSubscriptionPreferenceCopy",
|
|
9534
|
+
children: [
|
|
9535
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
9536
|
+
className: "codexSubscriptionPreferenceLabel",
|
|
9537
|
+
children: t("defaultModelTitle")
|
|
9538
|
+
}),
|
|
9539
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
9540
|
+
className: "codexSubscriptionPreferenceHint",
|
|
9541
|
+
children: hint
|
|
9542
|
+
}),
|
|
9543
|
+
snapshot.error ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
9544
|
+
className: "codexSubscriptionError",
|
|
9545
|
+
role: "alert",
|
|
9546
|
+
children: t("defaultModelFailed")
|
|
9547
|
+
}) : null
|
|
9548
|
+
]
|
|
9549
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Menu, {
|
|
9550
|
+
open,
|
|
9551
|
+
items,
|
|
9552
|
+
selectedId: snapshot.managed ? snapshot.model : void 0,
|
|
9553
|
+
onSelect: (value) => {
|
|
9554
|
+
setOpen(false);
|
|
9555
|
+
defaultModel.select(value);
|
|
9556
|
+
},
|
|
9557
|
+
onClose: () => setOpen(false),
|
|
9558
|
+
align: "end",
|
|
9559
|
+
side: "bottom",
|
|
9560
|
+
portal: true,
|
|
9561
|
+
compact: true,
|
|
9562
|
+
anchor: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
9563
|
+
className: "codexSubscriptionContextTrigger",
|
|
9564
|
+
type: "button",
|
|
9565
|
+
"aria-label": t("defaultModelTitle"),
|
|
9566
|
+
"aria-haspopup": "menu",
|
|
9567
|
+
"aria-expanded": open,
|
|
9568
|
+
"aria-busy": snapshot.saving || void 0,
|
|
9569
|
+
title: label,
|
|
9570
|
+
disabled,
|
|
9571
|
+
onClick: () => setOpen((value) => !value),
|
|
9572
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: label }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(IconChevronDownOutline14, {})]
|
|
9573
|
+
})
|
|
9574
|
+
})]
|
|
9575
|
+
});
|
|
9576
|
+
}
|
|
9577
|
+
//#endregion
|
|
9381
9578
|
//#region src/client-runtime-management.jsx
|
|
9382
9579
|
function RuntimeManagement({ rpc, preference, t }) {
|
|
9383
9580
|
const [state, setState] = (0, react.useState)();
|
|
@@ -9990,7 +10187,7 @@ window.__ModuleLoader__.load({
|
|
|
9990
10187
|
}) : null]
|
|
9991
10188
|
});
|
|
9992
10189
|
}
|
|
9993
|
-
function PreferencesCard({ preference, rpc, t, section = "display" }) {
|
|
10190
|
+
function PreferencesCard({ preference, rpc, t, defaultModel, section = "display" }) {
|
|
9994
10191
|
const snapshot = usePreferenceSnapshot(preference);
|
|
9995
10192
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
9996
10193
|
className: section === "advanced" ? "codexSubscriptionAdvancedPreferences" : "codexSubscriptionCard codexSubscriptionPreferencesCard",
|
|
@@ -10000,6 +10197,11 @@ window.__ModuleLoader__.load({
|
|
|
10000
10197
|
"aria-label": t("modelsSectionTitle"),
|
|
10001
10198
|
children: [
|
|
10002
10199
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", { children: t("modelsSectionTitle") }),
|
|
10200
|
+
defaultModel === void 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(DefaultModelPreference, {
|
|
10201
|
+
preference,
|
|
10202
|
+
defaultModel,
|
|
10203
|
+
t
|
|
10204
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { className: "codexSubscriptionDivider" })] }),
|
|
10003
10205
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ModelCatalogStatus, {
|
|
10004
10206
|
preference,
|
|
10005
10207
|
t
|
|
@@ -11432,7 +11634,7 @@ window.__ModuleLoader__.load({
|
|
|
11432
11634
|
}
|
|
11433
11635
|
//#endregion
|
|
11434
11636
|
//#region src/client-section.jsx
|
|
11435
|
-
function CodexSection({ preference, rpc, accountStatus, t, diagnostics }) {
|
|
11637
|
+
function CodexSection({ preference, rpc, accountStatus, t, diagnostics, defaultModel }) {
|
|
11436
11638
|
const [tab, setTab] = (0, react.useState)("account");
|
|
11437
11639
|
const id = (0, react.useId)();
|
|
11438
11640
|
const tabs = [
|
|
@@ -11524,6 +11726,7 @@ window.__ModuleLoader__.load({
|
|
|
11524
11726
|
rpc,
|
|
11525
11727
|
preference,
|
|
11526
11728
|
t,
|
|
11729
|
+
defaultModel,
|
|
11527
11730
|
section: "advanced"
|
|
11528
11731
|
})
|
|
11529
11732
|
}),
|
|
@@ -11744,6 +11947,7 @@ window.__ModuleLoader__.load({
|
|
|
11744
11947
|
getSnapshot: () => ({ status: "unavailable" }),
|
|
11745
11948
|
subscribe: () => () => {}
|
|
11746
11949
|
}, rpc);
|
|
11950
|
+
const defaultModel = createDefaultModelController(rpc);
|
|
11747
11951
|
ctx.effect(() => {
|
|
11748
11952
|
let previous = JSON.stringify(preference.getSnapshot(), (key, value) => key.startsWith("image") || key === "" ? value : void 0);
|
|
11749
11953
|
return preference.subscribe(() => {
|
|
@@ -11764,6 +11968,7 @@ window.__ModuleLoader__.load({
|
|
|
11764
11968
|
return () => {
|
|
11765
11969
|
disposeReset?.();
|
|
11766
11970
|
preference.dispose();
|
|
11971
|
+
defaultModel.dispose();
|
|
11767
11972
|
accountStatus.dispose();
|
|
11768
11973
|
};
|
|
11769
11974
|
}, "codex-subscription: preferences and account status");
|
|
@@ -11788,7 +11993,8 @@ window.__ModuleLoader__.load({
|
|
|
11788
11993
|
rpc,
|
|
11789
11994
|
accountStatus,
|
|
11790
11995
|
t,
|
|
11791
|
-
diagnostics
|
|
11996
|
+
diagnostics,
|
|
11997
|
+
defaultModel
|
|
11792
11998
|
})
|
|
11793
11999
|
}, CodexSection));
|
|
11794
12000
|
const sessions = ctx.get("sessions");
|
package/lib/index.js
CHANGED
|
@@ -40,6 +40,90 @@ function createSettingsAdapter(ctx, schema, config, namespace) {
|
|
|
40
40
|
};
|
|
41
41
|
}
|
|
42
42
|
//#endregion
|
|
43
|
+
//#region src/default-model.js
|
|
44
|
+
/**
|
|
45
|
+
* DSH owns the model a freshly created agent starts on. This module is the
|
|
46
|
+
* subscription plugin's read/write surface over that service: the settings
|
|
47
|
+
* surface edits the single live selection instead of keeping a second copy, so
|
|
48
|
+
* what the user sees is exactly what the next conversation will use.
|
|
49
|
+
*/
|
|
50
|
+
const DEFAULT_MODEL_PROVIDER = "openai-codex";
|
|
51
|
+
const MODEL_ID = /^[a-zA-Z0-9][a-zA-Z0-9._:-]{0,127}$/u;
|
|
52
|
+
const EFFORT_ID = /^[a-z][a-z0-9_-]{0,31}$/u;
|
|
53
|
+
/** A rejected default-model request carrying its stable public reason. */
|
|
54
|
+
var DefaultModelError = class extends Error {
|
|
55
|
+
constructor(code, message) {
|
|
56
|
+
super(message);
|
|
57
|
+
this.name = "DefaultModelError";
|
|
58
|
+
this.code = code;
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
const validDefaultModelId = (value) => typeof value === "string" && MODEL_ID.test(value);
|
|
62
|
+
/** Project a live selection onto the settings-safe shape; unknown values drop out. */
|
|
63
|
+
function normalizeDefaultSelection(value) {
|
|
64
|
+
return {
|
|
65
|
+
provider: typeof value?.provider === "string" && value.provider.length > 0 && value.provider.length <= 128 ? value.provider : void 0,
|
|
66
|
+
model: validDefaultModelId(value?.model) ? value.model : void 0,
|
|
67
|
+
reasoningEffort: typeof value?.reasoningEffort === "string" && EFFORT_ID.test(value.reasoningEffort) ? value.reasoningEffort : void 0
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Sample the default-model service per call: the service can mount after this
|
|
72
|
+
* plugin. A write verifies its own read-back, because a deployment without a
|
|
73
|
+
* configuration editor ignores `saveSelection`; the user must see that instead
|
|
74
|
+
* of a selection that will never apply.
|
|
75
|
+
* @param resolveService - reads the optional DSH `agentDefaultModel` service.
|
|
76
|
+
* @param listModels - optional account catalog used to reject unknown models.
|
|
77
|
+
*/
|
|
78
|
+
function createDefaultModelController({ resolveService, listModels } = {}) {
|
|
79
|
+
const service = () => {
|
|
80
|
+
try {
|
|
81
|
+
return resolveService?.();
|
|
82
|
+
} catch {
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
const read = () => {
|
|
87
|
+
const current = service();
|
|
88
|
+
if (current === void 0 || typeof current.currentSelection !== "function") return void 0;
|
|
89
|
+
try {
|
|
90
|
+
return normalizeDefaultSelection(current.currentSelection());
|
|
91
|
+
} catch {
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
const status = () => {
|
|
96
|
+
const selection = read();
|
|
97
|
+
return {
|
|
98
|
+
available: selection !== void 0,
|
|
99
|
+
managed: selection?.provider === "openai-codex" && selection.model !== void 0,
|
|
100
|
+
...selection
|
|
101
|
+
};
|
|
102
|
+
};
|
|
103
|
+
const select = async (request) => {
|
|
104
|
+
const model = request?.model;
|
|
105
|
+
if (!validDefaultModelId(model)) throw new DefaultModelError("invalid-model", "Invalid default model");
|
|
106
|
+
const catalog = typeof listModels === "function" ? listModels() : void 0;
|
|
107
|
+
if (Array.isArray(catalog) && catalog.length > 0 && !catalog.includes(model)) throw new DefaultModelError("invalid-model", "Invalid default model");
|
|
108
|
+
const current = service();
|
|
109
|
+
if (current === void 0 || typeof current.saveSelection !== "function") throw new DefaultModelError("unavailable", "This DSH deployment cannot save a default model");
|
|
110
|
+
const previous = read();
|
|
111
|
+
const reasoningEffort = previous?.provider === "openai-codex" && previous.model === model ? previous.reasoningEffort : void 0;
|
|
112
|
+
await current.saveSelection({
|
|
113
|
+
provider: DEFAULT_MODEL_PROVIDER,
|
|
114
|
+
model,
|
|
115
|
+
...reasoningEffort === void 0 ? {} : { reasoningEffort }
|
|
116
|
+
});
|
|
117
|
+
const applied = read();
|
|
118
|
+
if (applied?.provider !== "openai-codex" || applied.model !== model) throw new DefaultModelError("unavailable", "The default model could not be saved");
|
|
119
|
+
return status();
|
|
120
|
+
};
|
|
121
|
+
return Object.freeze({
|
|
122
|
+
status,
|
|
123
|
+
select
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
//#endregion
|
|
43
127
|
//#region src/image-models.js
|
|
44
128
|
const DEFAULT_IMAGE_MODEL = "gpt-image-2";
|
|
45
129
|
const IMAGE_MODELS = Object.freeze({
|
|
@@ -1014,6 +1098,8 @@ const RPC_ENDPOINTS = Object.freeze([
|
|
|
1014
1098
|
"preferences/status",
|
|
1015
1099
|
"preferences/models",
|
|
1016
1100
|
"preferences/update",
|
|
1101
|
+
"default-model/status",
|
|
1102
|
+
"default-model/select",
|
|
1017
1103
|
"runtime/status",
|
|
1018
1104
|
"runtime/install",
|
|
1019
1105
|
"runtime/remove",
|
|
@@ -1898,7 +1984,7 @@ const sketchCommandArray = {
|
|
|
1898
1984
|
function createSketchAgentTool(bridge, attachments) {
|
|
1899
1985
|
return defineTool({
|
|
1900
1986
|
name: "codex_sketch",
|
|
1901
|
-
description: "Edit the sketch board in this session using native editable strokes and layers. Use for @sketch requests and explicit follow-up edits to that drawing. The toolbar pen button is for manual drawing; do not require the user to open it. Start with inspect for the runId, documentId, revision and command reference. Draw with the svg op whenever possible: one SVG document per stage (paths, shapes, groups, transforms; see the reference from inspect) is far faster and richer than hand-placed strokes, and still becomes native editable strokes.
|
|
1987
|
+
description: "Edit the sketch board in this session using native editable strokes and layers. Use for @sketch requests and explicit follow-up edits to that drawing. The toolbar pen button is for manual drawing; do not require the user to open it. Start with inspect for the runId, documentId, revision and command reference. Draw with the svg op whenever possible: one SVG document per stage (paths, shapes, groups, transforms; see the reference from inspect) is far faster and richer than hand-placed strokes, and still becomes native editable strokes. Draw the shapes, hair, clothing and lettering outlines of every layer with svg; use stroke commands only for small corrections and native text. Apply atomic batches, preview between stages, and call finish to save the finished draft and release the editing lock. save is only a checkpoint. finish returns an image only when the user enables experimental preview feedback. Closing the board does not stop drawing. If the user stops drawing, do not retry. Never generates AI images, sends messages or attaches images automatically. Inspect automatically opens the board in the currently viewed session. Do not ask the user to open it first. If the session is not visible in DSH, ask them to switch to it. On timeout inspect before retrying; reuse the exact requestId only for the same request.",
|
|
1902
1988
|
parameters: {
|
|
1903
1989
|
action: {
|
|
1904
1990
|
type: "string",
|
|
@@ -3068,7 +3154,7 @@ async function readSubscriptionCredentials(getAuth, readCredential, signal) {
|
|
|
3068
3154
|
}
|
|
3069
3155
|
//#endregion
|
|
3070
3156
|
//#region src/version.js
|
|
3071
|
-
const PACKAGE_VERSION = "2.4.
|
|
3157
|
+
const PACKAGE_VERSION = "2.4.2";
|
|
3072
3158
|
const USER_AGENT = `dsh-codex-subscription/${PACKAGE_VERSION}`;
|
|
3073
3159
|
//#endregion
|
|
3074
3160
|
//#region src/model-catalog.js
|
|
@@ -5795,8 +5881,21 @@ const publicError = (code, message) => ({
|
|
|
5795
5881
|
details: { issues: [] }
|
|
5796
5882
|
}
|
|
5797
5883
|
});
|
|
5798
|
-
function createSubscriptionRpcHandler({ authHandler, usageReader, resetCreditService, preferences, runtimeManagement, diagnosticsReader, modelCatalog, originalImages, resolveInheritedOriginal, closeConnections, onAccountChanged, onCleanupFailure }) {
|
|
5884
|
+
function createSubscriptionRpcHandler({ authHandler, usageReader, resetCreditService, preferences, defaultModel, runtimeManagement, diagnosticsReader, modelCatalog, originalImages, resolveInheritedOriginal, closeConnections, onAccountChanged, onCleanupFailure }) {
|
|
5799
5885
|
return async (endpoint, payload, signal) => {
|
|
5886
|
+
if (endpoint === "default-model/status" || endpoint === "default-model/select") try {
|
|
5887
|
+
signal.throwIfAborted();
|
|
5888
|
+
if (!defaultModel) return publicError("unavailable", "The default model is unavailable");
|
|
5889
|
+
return {
|
|
5890
|
+
ok: true,
|
|
5891
|
+
value: endpoint === "default-model/status" ? defaultModel.status() : await defaultModel.select({ model: payload?.model })
|
|
5892
|
+
};
|
|
5893
|
+
} catch (error) {
|
|
5894
|
+
if (signal.aborted) throw error;
|
|
5895
|
+
if (error?.code === "invalid-model") return publicError("invalid-input", "Invalid default model");
|
|
5896
|
+
if (error?.code === "unavailable") return publicError("unavailable", endpoint === "default-model/status" ? "The default model is unavailable" : "Could not save the default model");
|
|
5897
|
+
return publicError("internal", endpoint === "default-model/status" ? "Could not read the default model" : "Could not save the default model");
|
|
5898
|
+
}
|
|
5800
5899
|
if (endpoint === "storage/status" || endpoint === "storage/clear-forecast") try {
|
|
5801
5900
|
signal.throwIfAborted();
|
|
5802
5901
|
if (endpoint === "storage/clear-forecast") await usageReader.clear();
|
|
@@ -6085,6 +6184,10 @@ function apply(ctx, config = {}) {
|
|
|
6085
6184
|
fetch: (input, init) => network.fetch("catalog", input, init)
|
|
6086
6185
|
});
|
|
6087
6186
|
const connection = createSubscriptionConnection({ resolveMode: () => settings.get().connectionMode });
|
|
6187
|
+
const defaultModel = createDefaultModelController({
|
|
6188
|
+
resolveService: () => ctx.get?.("agentDefaultModel"),
|
|
6189
|
+
listModels: () => modelCatalog.getModels().map((model) => model.id)
|
|
6190
|
+
});
|
|
6088
6191
|
const compaction = createCompactionBridge({
|
|
6089
6192
|
enabled: () => settings.get().compactionMode === "cloud",
|
|
6090
6193
|
accountScope: async () => {
|
|
@@ -6395,6 +6498,7 @@ function apply(ctx, config = {}) {
|
|
|
6395
6498
|
usageReader,
|
|
6396
6499
|
resetCreditService,
|
|
6397
6500
|
preferences,
|
|
6501
|
+
defaultModel,
|
|
6398
6502
|
runtimeManagement,
|
|
6399
6503
|
onAccountChanged: quotaRetryHandler.notifyAccountChanged,
|
|
6400
6504
|
diagnosticsReader: () => createSubscriptionDiagnostics({
|
|
@@ -6436,4 +6540,4 @@ function apply(ctx, config = {}) {
|
|
|
6436
6540
|
}, "codex-subscription: DSH-trusted account RPC"));
|
|
6437
6541
|
}
|
|
6438
6542
|
//#endregion
|
|
6439
|
-
export { CODEX_IMAGE_GENERATION_URL, CODEX_IMAGE_TOOL_NAME, CODEX_RESET_CONSUME_URL, CODEX_RESET_CREDITS_URL, CODEX_USAGE_URL, CodexLoginCoordinator, Config, DshOAuthCredentialStore, apply, assertCodexAuthUrl, commandForCodexAuthUrl, createCodexAuthService, createCodexImageTool, createCodexResetCreditService, createCodexRpcHandler, createCodexUsageReader, createSearchProviderSwitcher, createSubscriptionDiagnostics, createSubscriptionRpcHandler, decodeCodexPng, inject, name, normalizeContextMode, normalizeCustomContextWindow, openCodexAuthUrl, parseCodexUsage };
|
|
6543
|
+
export { CODEX_IMAGE_GENERATION_URL, CODEX_IMAGE_TOOL_NAME, CODEX_RESET_CONSUME_URL, CODEX_RESET_CREDITS_URL, CODEX_USAGE_URL, CodexLoginCoordinator, Config, DEFAULT_MODEL_PROVIDER, DshOAuthCredentialStore, apply, assertCodexAuthUrl, commandForCodexAuthUrl, createCodexAuthService, createCodexImageTool, createCodexResetCreditService, createCodexRpcHandler, createCodexUsageReader, createDefaultModelController, createSearchProviderSwitcher, createSubscriptionDiagnostics, createSubscriptionRpcHandler, decodeCodexPng, inject, name, normalizeContextMode, normalizeCustomContextWindow, openCodexAuthUrl, parseCodexUsage };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-codex-subscription",
|
|
3
|
-
"version": "2.4.
|
|
3
|
+
"version": "2.4.2",
|
|
4
4
|
"description": "Use ChatGPT and Codex subscriptions in DeepSeek Harness with OAuth, quota, safe resets, web search, images, and Fast mode",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./lib/index.js",
|