dsh-codex-subscription 1.7.4 → 1.9.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/AGENTS.md +4 -4
- package/DIRECTORY.md +1 -1
- package/README.md +18 -18
- package/README.zh-CN.md +16 -16
- package/lib/client.js +271 -26
- package/lib/index.js +363 -72
- package/package.json +1 -1
package/AGENTS.md
CHANGED
|
@@ -6,7 +6,7 @@ Use this guide when a user asks an Agent to install, update, verify, or remove
|
|
|
6
6
|
## Safety
|
|
7
7
|
|
|
8
8
|
- Confirm the target DSH installation and profile. Use `web` only when it is the user's target.
|
|
9
|
-
- Use the exact `1.
|
|
9
|
+
- Use the exact `1.9.0` package below; do not install a moving branch.
|
|
10
10
|
- Never print OAuth credentials, account IDs, authorization callbacks, or credential-store contents.
|
|
11
11
|
- Preserve the DSH profile, unrelated plugins, sessions, and saved sign-in.
|
|
12
12
|
- Do not start, stop, or restart DSH without explicit permission.
|
|
@@ -34,13 +34,13 @@ For an official DSH installation run through npm, keep the complete `npx` prefix
|
|
|
34
34
|
run command does not create a global `dsh` command:
|
|
35
35
|
|
|
36
36
|
```sh
|
|
37
|
-
npx -y @deepseek-ai/dsh@0.1.1-rc.2 plugin --profile web add dsh-codex-subscription@1.
|
|
37
|
+
npx -y @deepseek-ai/dsh@0.1.1-rc.2 plugin --profile web add dsh-codex-subscription@1.9.0
|
|
38
38
|
```
|
|
39
39
|
|
|
40
40
|
With an existing global `dsh` command:
|
|
41
41
|
|
|
42
42
|
```sh
|
|
43
|
-
dsh plugin --profile web add dsh-codex-subscription@1.
|
|
43
|
+
dsh plugin --profile web add dsh-codex-subscription@1.9.0
|
|
44
44
|
```
|
|
45
45
|
|
|
46
46
|
Use the same `add` command to update or repair. This is the complete package-changing operation.
|
|
@@ -58,7 +58,7 @@ dsh --profile web --dump-config
|
|
|
58
58
|
|
|
59
59
|
For the official npm route, run the same checks with `npx -y @deepseek-ai/dsh@0.1.1-rc.2` in place of `dsh`.
|
|
60
60
|
|
|
61
|
-
1. `dsh-codex-subscription` version `1.
|
|
61
|
+
1. `dsh-codex-subscription` version `1.9.0` appears exactly once.
|
|
62
62
|
2. `codex-subscription` appears exactly once in the composed config.
|
|
63
63
|
3. No unrelated plugin or profile was changed and DSH was not restarted.
|
|
64
64
|
|
package/DIRECTORY.md
CHANGED
|
@@ -18,7 +18,7 @@ Use a ChatGPT subscription in DeepSeek Harness through independent OAuth sign-in
|
|
|
18
18
|
- Codex CLI required: no
|
|
19
19
|
- OpenAI API key required: no
|
|
20
20
|
- Platforms: official DSH plus DSH-Portable product forms for Windows, macOS, and Linux
|
|
21
|
-
- Main capabilities: Codex models, quota and expiring resets, web search, Beta image generation/editing with explicit references and native preview/download, optional composer quota, Fast mode, secret-free support diagnostics and direct feedback
|
|
21
|
+
- Main capabilities: Codex models, model-aware context windows, quota and expiring resets, web search, Beta image generation/editing with explicit references and native preview/download, optional composer quota, Fast mode, existing-proxy adaptation, secret-free actionable support diagnostics, and direct feedback
|
|
22
22
|
- Safety boundary: subscription failures remain visible and never silently fall back to another paid provider
|
|
23
23
|
|
|
24
24
|
## Install
|
package/README.md
CHANGED
|
@@ -48,30 +48,26 @@ DSH-Portable exposes the same standard plugin command, so the command above also
|
|
|
48
48
|
| **Visible quota** | Keep backend-provided standard Codex, Spark, and other limits separate |
|
|
49
49
|
| **Composer quota** | Choose a compact percentage, progress bar, or no inline quota display |
|
|
50
50
|
| **Safe quota reset** | See the next expiry and deliberately try a reset with a cooldown and acknowledgement |
|
|
51
|
-
| **Subscription search** | Explicitly
|
|
51
|
+
| **Subscription search** | Explicitly route search globally through DSH default search or the signed-in Codex subscription |
|
|
52
52
|
| **Codex image generation and editing (Beta)** | Generate without references, or explicitly edit one selected image; preview, zoom, annotate regions, download the original, and continue in the same composer |
|
|
53
53
|
| **Fast mode** | Switch between Standard and Fast directly in the composer |
|
|
54
|
+
| **Model-aware context** | Keep catalog defaults, use each model's supported extended window, or enter a full numeric token limit for each model |
|
|
54
55
|
|
|
55
56
|
These capabilities reuse the same local ChatGPT sign-in. Subscription routing failures stay visible and never silently switch to another paid route.
|
|
56
57
|
|
|
57
58
|
## Product screen
|
|
58
59
|
|
|
59
60
|
<p align="center">
|
|
60
|
-
<img src="https://raw.githubusercontent.com/WSL043/dsh-codex-subscription/main/docs/assets/settings-
|
|
61
|
+
<img src="https://raw.githubusercontent.com/WSL043/dsh-codex-subscription/main/docs/assets/context-settings-en.png" width="820" alt="Current Codex subscription settings in DeepSeek Harness with search, model-aware context, composer quota, and support diagnostics">
|
|
61
62
|
</p>
|
|
62
63
|
|
|
63
|
-
|
|
64
|
-
<summary>View the complete settings screen</summary>
|
|
65
|
-
|
|
66
|
-

|
|
67
|
-
|
|
68
|
-
</details>
|
|
64
|
+
Captured from the installed official DeepSeek Harness `0.1.1-rc.2` product with the current plugin build.
|
|
69
65
|
|
|
70
66
|
## Prepare DSH
|
|
71
67
|
|
|
72
68
|
This plugin is currently compatible through DeepSeek Harness `0.1.1-rc.2` and requires a ChatGPT account that currently has Codex access.
|
|
73
69
|
|
|
74
|
-
- Do not want to configure Node.js? Use [DSH-Portable](https://github.com/WSL043/DSH-Portable), a community desktop distribution
|
|
70
|
+
- Do not want to configure Node.js? Use [DSH-Portable](https://github.com/WSL043/DSH-Portable), a community portable desktop distribution for Windows, macOS, and Linux.
|
|
75
71
|
- Prefer the official route? Follow the [DeepSeek Harness run guide](https://github.com/deepseek-ai/deepseek-harness#run).
|
|
76
72
|
|
|
77
73
|
## Install
|
|
@@ -96,12 +92,13 @@ Open PowerShell and paste this one line:
|
|
|
96
92
|
irm 'https://github.com/WSL043/dsh-codex-subscription/releases/latest/download/dsh-codex-setup.ps1' | iex
|
|
97
93
|
```
|
|
98
94
|
|
|
99
|
-
The lightweight setup checks the current folder, the system command, common locations, and
|
|
100
|
-
[DSH-Portable](https://github.com/WSL043/DSH-Portable)
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
95
|
+
The lightweight setup checks the current folder, the system command, common locations, and running official DSH or
|
|
96
|
+
[DSH-Portable](https://github.com/WSL043/DSH-Portable). It asks before choosing when more than one target is available.
|
|
97
|
+
Portable keeps using its public launcher. For official DSH, setup uses the selected profile home and a checksum-verified
|
|
98
|
+
pnpm helper pinned to the accepted DSH release; the helper is cached under the current Windows user when no working pnpm
|
|
99
|
+
command is available. It does not recursively scan disks, create a resident command, snapshot a profile, require
|
|
100
|
+
administrator access, or restart DSH. A recognized release-age rejection may retry the same pinned add once for that
|
|
101
|
+
command only.
|
|
105
102
|
|
|
106
103
|
<details>
|
|
107
104
|
<summary>Official npm route (Node.js installed)</summary>
|
|
@@ -140,15 +137,18 @@ Restart DSH manually after installation, then:
|
|
|
140
137
|
|
|
141
138
|
- ChatGPT OAuth sign-in with credentials kept on the host;
|
|
142
139
|
- Codex models and Beta image generation/editing directly inside DSH conversations;
|
|
143
|
-
- A clear choice between DSH default search and Codex subscription search;
|
|
140
|
+
- A clear global choice between DSH default search and Codex subscription search; it applies to every model and session rather than following the selected model;
|
|
144
141
|
- Actual backend-provided quota, reset time, and freshness;
|
|
145
142
|
- Separate standard Codex, Codex-Spark, Credits, and other independent limits;
|
|
146
143
|
- Visible quota-reset count and earliest expiry, with deliberate early redemption, layered confirmation, and no automatic retry;
|
|
147
144
|
- Optional percentage or progress bar for the selected Codex model (off by default);
|
|
148
145
|
- Standard or Fast mode for supported Codex models directly in the composer;
|
|
149
|
-
-
|
|
146
|
+
- Standard, Extended, and per-model Custom context windows; Custom accepts a full numeric token count, stays within each audited model capacity, and feeds DSH's native agent compaction policy;
|
|
147
|
+
- A copyable support report and direct feedback link in Settings; the report includes bounded request stages, HTTP/transport classes, elapsed ranges, and route source types while excluding OAuth credentials, account identifiers, proxy addresses, and authorization timestamps;
|
|
150
148
|
- Visible errors when subscription routing is unavailable, with no silent paid fallback.
|
|
151
149
|
|
|
150
|
+
The plugin can follow an existing HTTPS proxy from the process environment or operating-system proxy settings for official OpenAI and ChatGPT requests. It does not provide a proxy, relay, node list, or system-proxy configuration.
|
|
151
|
+
|
|
152
152
|
### Composer quota
|
|
153
153
|
|
|
154
154
|
<p align="center">
|
|
@@ -214,7 +214,7 @@ dsh plugin --profile web remove dsh-codex-subscription
|
|
|
214
214
|
- **`dsh` is not recognized:** the official npm route does not create a global `dsh` command; use the complete `npx -y @deepseek-ai/dsh@0.1.1-rc.2 ...` command above;
|
|
215
215
|
- **More than one DSH exists:** run the standard command from the intended DSH environment. For an Agent, specify the target or pass `-DshPath` explicitly;
|
|
216
216
|
- **Setup still fails:** send the Agent guide above to an Agent. Do not delete the profile or change the system PATH to force an install.
|
|
217
|
-
- **Need to report a problem:** generate a **Support diagnostics** report at the bottom of Settings, then open the [bug report form](https://github.com/WSL043/dsh-codex-subscription/issues/new?template=install-problem.yml). The report includes the OS/runtime
|
|
217
|
+
- **Need to report a problem:** generate a **Support diagnostics** report at the bottom of Settings, then open the [bug report form](https://github.com/WSL043/dsh-codex-subscription/issues/new?template=install-problem.yml). The report includes the OS/runtime, bounded sign-in phase, and safe request-failure categories, but excludes credentials, account identifiers, proxy addresses, raw responses, and full logs. Paste it into the required diagnostics field; never attach sign-in URLs, authorization codes, or browser callback addresses.
|
|
218
218
|
|
|
219
219
|
The ChatGPT Codex backend and DSH can change independently. This community project is not affiliated with or endorsed by DeepSeek or OpenAI.
|
|
220
220
|
|
package/README.zh-CN.md
CHANGED
|
@@ -49,30 +49,26 @@ DSH-Portable 也提供相同的标准插件命令,因此同样使用上面的
|
|
|
49
49
|
| **额度可见** | 普通 Codex、Spark 等服务端实际返回的额度分开显示 |
|
|
50
50
|
| **输入框额度** | 可选择紧凑百分比、进度条或完全关闭输入框额度显示 |
|
|
51
51
|
| **安全额度重置** | 直接查看最早到期时间,并通过冷静期和知情确认主动尝试重置 |
|
|
52
|
-
| **订阅搜索** |
|
|
52
|
+
| **订阅搜索** | 可将全部模型的搜索明确路由到 DSH 默认搜索或已登录的 Codex 订阅 |
|
|
53
53
|
| **Codex 图片生成与编辑(Beta)** | 可无参考图全新生成,也可明确选择会话图片继续编辑;支持预览、缩放和下载原图 |
|
|
54
54
|
| **高速模式** | 直接在输入框切换标准或高速,无需离开当前会话 |
|
|
55
|
+
| **模型感知上下文** | 可保留目录默认值、按模型启用扩展窗口,或为每个模型填写完整数字 Token 上限 |
|
|
55
56
|
|
|
56
57
|
这些能力共用同一份本机 ChatGPT 登录。订阅路由失败时会明确报错,不会静默切换到其他付费路由。
|
|
57
58
|
|
|
58
59
|
## 实际界面
|
|
59
60
|
|
|
60
61
|
<p align="center">
|
|
61
|
-
<img src="https://raw.githubusercontent.com/WSL043/dsh-codex-subscription/main/docs/assets/settings
|
|
62
|
+
<img src="https://raw.githubusercontent.com/WSL043/dsh-codex-subscription/main/docs/assets/context-settings.png" width="820" alt="当前 DeepSeek Harness Codex 订阅设置,包含搜索来源、模型感知上下文、输入框额度和支持诊断">
|
|
62
63
|
</p>
|
|
63
64
|
|
|
64
|
-
|
|
65
|
-
<summary>查看完整设置界面</summary>
|
|
66
|
-
|
|
67
|
-

|
|
68
|
-
|
|
69
|
-
</details>
|
|
65
|
+
图片来自已安装的官方 DeepSeek Harness `0.1.1-rc.2` 与当前插件构建。
|
|
70
66
|
|
|
71
67
|
## 准备 DSH
|
|
72
68
|
|
|
73
69
|
本插件当前适配到 DeepSeek Harness `0.1.1-rc.2`,并需要一个当前具有 Codex 使用资格的 ChatGPT 账户。
|
|
74
70
|
|
|
75
|
-
- 不想配置 Node.js:使用 [DSH-Portable](https://github.com/WSL043/DSH-Portable)
|
|
71
|
+
- 不想配置 Node.js:使用 [DSH-Portable](https://github.com/WSL043/DSH-Portable)。这是面向 Windows、macOS 和 Linux 的社区便携桌面分发;
|
|
76
72
|
- 想按官方方式运行:查看 [DeepSeek Harness 官方说明](https://github.com/deepseek-ai/deepseek-harness#run)。
|
|
77
73
|
|
|
78
74
|
## 安装
|
|
@@ -98,10 +94,11 @@ irm 'https://github.com/WSL043/dsh-codex-subscription/releases/latest/download/d
|
|
|
98
94
|
```
|
|
99
95
|
|
|
100
96
|
这个轻量助手会检查当前目录、系统命令、常见位置以及正在运行的官方 DSH 或
|
|
101
|
-
[DSH-Portable](https://github.com/WSL043/DSH-Portable)
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
97
|
+
[DSH-Portable](https://github.com/WSL043/DSH-Portable);存在多个目标时会先让用户选择。
|
|
98
|
+
Portable 继续使用它的公开启动器。安装到官方 DSH 时,助手会使用选定的配置目录和固定到已验收
|
|
99
|
+
DSH 版本的 pnpm 助手;系统没有可用 pnpm 时,会在当前 Windows 用户目录下缓存经过校验的副本。
|
|
100
|
+
它不会递归扫盘、创建常驻命令、保存 profile 快照、要求管理员权限或擅自重启 DSH。只有识别到
|
|
101
|
+
发布时间策略拦截时,才会仅对同一个固定安装命令重试一次。
|
|
105
102
|
|
|
106
103
|
<details>
|
|
107
104
|
<summary>官方 npm 方式(已安装 Node.js)</summary>
|
|
@@ -140,15 +137,18 @@ dsh --profile web --dump-config
|
|
|
140
137
|
|
|
141
138
|
- ChatGPT OAuth 登录,凭据保留在本机;
|
|
142
139
|
- Codex 模型和 Beta 图片生成与编辑直接出现在 DSH 会话中;
|
|
143
|
-
- DSH 默认搜索与 Codex
|
|
140
|
+
- 搜索来源是全局设置,可在 DSH 默认搜索与 Codex 订阅搜索之间切换;它对所有模型和会话生效,不会随当前模型自动切换;
|
|
144
141
|
- 设置页显示服务端返回的额度、重置时间和更新时间;
|
|
145
142
|
- 普通 Codex、Codex-Spark、Credits 等独立额度分开显示;
|
|
146
143
|
- 显示重置卡数量与最早到期时间,也允许在额度未完全用尽时主动尝试,并经过分层确认且不会自动重试;
|
|
147
144
|
- 输入框可用百分比或进度条显示当前 Codex 模型的剩余额度(默认关闭);
|
|
148
145
|
- 输入框可为支持的 Codex 模型切换标准或高速模式;
|
|
149
|
-
-
|
|
146
|
+
- 上下文窗口提供标准、扩展和逐模型自定义;自定义直接填写完整 Token 数值,并在已审核的模型容量内交给 DSH 原生 Agent 压缩策略处理;
|
|
147
|
+
- 设置页可生成并复制无敏感信息的支持诊断,并直接打开反馈入口;报告包含有限的请求阶段、HTTP/网络分类、耗时区间和路由来源类型,但不包含 OAuth 凭据、账号标识、代理地址或授权时间;
|
|
150
148
|
- 订阅路由不可用时明确报错,不会静默切换到其他付费路由。
|
|
151
149
|
|
|
150
|
+
对于 OpenAI 与 ChatGPT 官方请求,插件可以沿用进程环境或操作系统中已有的 HTTPS 代理。插件本身不提供代理、转发服务、节点列表,也不会修改系统代理设置。
|
|
151
|
+
|
|
152
152
|
### 输入框额度
|
|
153
153
|
|
|
154
154
|
<p align="center">
|
|
@@ -210,7 +210,7 @@ dsh plugin --profile web remove dsh-codex-subscription
|
|
|
210
210
|
- **`dsh` 无法识别**:官方 npm 方式本来就不会创建全局 `dsh` 命令,请使用上面的完整 `npx -y @deepseek-ai/dsh@0.1.1-rc.2 ...` 命令;
|
|
211
211
|
- **电脑上有多个 DSH**:请在目标 DSH 环境中运行标准命令;交给 Agent 时明确目标,或传入 `-DshPath`;
|
|
212
212
|
- **安装仍然失败**:把上面的 Agent 文档链接发给 Agent,不要删除 profile 或随意修改系统 PATH。
|
|
213
|
-
- **需要提交问题**:在设置页底部生成“支持诊断”,然后打开[使用问题表单](https://github.com/WSL043/dsh-codex-subscription/issues/new?template=install-problem.yml)
|
|
213
|
+
- **需要提交问题**:在设置页底部生成“支持诊断”,然后打开[使用问题表单](https://github.com/WSL043/dsh-codex-subscription/issues/new?template=install-problem.yml)。报告包含系统/运行时、有限的登录阶段和安全的请求失败分类,但不含凭据、账号标识、代理地址、原始响应或完整日志;请粘贴到必填诊断栏,且不要附上登录链接、授权码或浏览器回调地址。
|
|
214
214
|
|
|
215
215
|
## 边界与支持
|
|
216
216
|
|
package/lib/client.js
CHANGED
|
@@ -49,6 +49,17 @@ window.__ModuleLoader__.load({
|
|
|
49
49
|
}
|
|
50
50
|
const ForwardRef = /*#__PURE__*/ react.forwardRef(BoltIcon);
|
|
51
51
|
//#endregion
|
|
52
|
+
//#region src/image-edit.js
|
|
53
|
+
function buildImageEditDraft({ prompt = "", annotations = [], translate }) {
|
|
54
|
+
if (typeof translate !== "function") throw new TypeError("translate must be a function");
|
|
55
|
+
const notes = annotations.map((annotation, index) => ({
|
|
56
|
+
number: index + 1,
|
|
57
|
+
note: typeof annotation?.note === "string" ? annotation.note.trim() : ""
|
|
58
|
+
})).filter((annotation) => annotation.note !== "").map((annotation) => String(annotation.number) + ". " + annotation.note);
|
|
59
|
+
const base = prompt.trim() === "" ? translate("imageEditDefault") : prompt.trim();
|
|
60
|
+
return notes.length === 0 ? base : base + "\n\n" + translate("imageRegionNotes") + "\n" + notes.join("\n");
|
|
61
|
+
}
|
|
62
|
+
//#endregion
|
|
52
63
|
//#region src/settings-contract.js
|
|
53
64
|
const SETTINGS_NAMESPACE = "codex-subscription";
|
|
54
65
|
const QUICK_QUOTA_MODE_FIELD = "quickQuotaMode";
|
|
@@ -60,8 +71,50 @@ window.__ModuleLoader__.load({
|
|
|
60
71
|
const SPEED_MODE_STANDARD = "standard";
|
|
61
72
|
const SPEED_MODE_FAST = "fast";
|
|
62
73
|
const DEFAULT_SPEED_MODE = SPEED_MODE_STANDARD;
|
|
74
|
+
const CONTEXT_MODE_FIELD = "contextMode";
|
|
75
|
+
const CONTEXT_MODE_STANDARD = "standard";
|
|
76
|
+
const CONTEXT_MODE_EXTENDED = "extended";
|
|
77
|
+
const CONTEXT_MODE_CUSTOM = "custom";
|
|
78
|
+
const DEFAULT_CONTEXT_MODE = CONTEXT_MODE_STANDARD;
|
|
79
|
+
const CUSTOM_CONTEXT_WINDOW_FIELD = "customContextWindow";
|
|
80
|
+
const DEFAULT_CUSTOM_CONTEXT_WINDOW = 272e3;
|
|
81
|
+
const MIN_CUSTOM_CONTEXT_WINDOW = 128e3;
|
|
82
|
+
const MAX_CUSTOM_CONTEXT_WINDOW = 1e6;
|
|
83
|
+
const CUSTOM_CONTEXT_MODEL_FIELDS = Object.freeze({
|
|
84
|
+
"gpt-5.4": "customContextGpt54",
|
|
85
|
+
"gpt-5.4-mini": "customContextGpt54Mini",
|
|
86
|
+
"gpt-5.5": "customContextGpt55",
|
|
87
|
+
"gpt-5.6": "customContextGpt56"
|
|
88
|
+
});
|
|
89
|
+
const CUSTOM_CONTEXT_MODEL_CAPS = Object.freeze({
|
|
90
|
+
"gpt-5.4": 1e6,
|
|
91
|
+
"gpt-5.4-mini": 4e5,
|
|
92
|
+
"gpt-5.5": 1e6,
|
|
93
|
+
"gpt-5.6": 1e6
|
|
94
|
+
});
|
|
95
|
+
const CUSTOM_CONTEXT_MODEL_DEFAULTS = Object.freeze({
|
|
96
|
+
"gpt-5.4": 272e3,
|
|
97
|
+
"gpt-5.4-mini": 272e3,
|
|
98
|
+
"gpt-5.5": 272e3,
|
|
99
|
+
"gpt-5.6": 272e3
|
|
100
|
+
});
|
|
63
101
|
const normalizeSearchProvider = (value) => ["dsh", "codex"].includes(value) ? value : "dsh";
|
|
64
102
|
const normalizeSpeedMode = (value) => ["standard", "fast"].includes(value) ? value : DEFAULT_SPEED_MODE;
|
|
103
|
+
const normalizeContextMode = (value) => [
|
|
104
|
+
"standard",
|
|
105
|
+
"extended",
|
|
106
|
+
"custom"
|
|
107
|
+
].includes(value) ? value : DEFAULT_CONTEXT_MODE;
|
|
108
|
+
const normalizeCustomContextWindow = (value, maximum = MAX_CUSTOM_CONTEXT_WINDOW) => {
|
|
109
|
+
if (!Number.isInteger(value)) return DEFAULT_CUSTOM_CONTEXT_WINDOW;
|
|
110
|
+
return Math.min(Math.max(value, MIN_CUSTOM_CONTEXT_WINDOW), maximum);
|
|
111
|
+
};
|
|
112
|
+
const formatContextWindow = (value) => value === 1e6 ? "1M" : `${Math.round(value / 1e3)}K`;
|
|
113
|
+
const parseContextWindow = (value) => {
|
|
114
|
+
const match = /^\s*(\d+)\s*$/u.exec(String(value));
|
|
115
|
+
if (match === null) return NaN;
|
|
116
|
+
return Number(match[1]);
|
|
117
|
+
};
|
|
65
118
|
const normalizeQuickQuotaMode = (value, legacyVisible = false) => [
|
|
66
119
|
"off",
|
|
67
120
|
"percent",
|
|
@@ -170,10 +223,11 @@ window.__ModuleLoader__.load({
|
|
|
170
223
|
diagnosticsFailed: "无法生成诊断信息。",
|
|
171
224
|
feedbackOpen: "反馈问题",
|
|
172
225
|
searchTitle: "搜索来源",
|
|
226
|
+
searchScope: "此设置对所有模型和会话生效,不会随当前模型自动切换。",
|
|
173
227
|
searchDsh: "DSH 默认",
|
|
174
|
-
searchDshHint: "当前搜索服务",
|
|
228
|
+
searchDshHint: "所有模型使用 DSH 当前搜索服务",
|
|
175
229
|
searchCodex: "Codex 订阅",
|
|
176
|
-
searchCodexHint: "ChatGPT 订阅搜索",
|
|
230
|
+
searchCodexHint: "所有模型通过已登录的 ChatGPT 订阅搜索",
|
|
177
231
|
preferenceFailed: "设置未保存。",
|
|
178
232
|
preferenceRetry: "重试",
|
|
179
233
|
usage: "订阅额度",
|
|
@@ -231,6 +285,16 @@ window.__ModuleLoader__.load({
|
|
|
231
285
|
quickQuotaOff: "关闭",
|
|
232
286
|
quickQuotaPercent: "百分比",
|
|
233
287
|
quickQuotaBar: "进度条",
|
|
288
|
+
contextTitle: "上下文窗口",
|
|
289
|
+
contextStandard: "标准",
|
|
290
|
+
contextStandardHint: "使用模型目录默认值;官方 Agent 预设会自动管理上下文。",
|
|
291
|
+
contextExtended: "扩展",
|
|
292
|
+
contextExtendedHint: "按模型使用 400K 或 1M;超过 272K 后可能消耗更多额度。",
|
|
293
|
+
contextCustom: "自定义",
|
|
294
|
+
contextCustomHint: "输入完整 Token 数值;较低数值会让官方 Agent 预设更早压缩上下文。",
|
|
295
|
+
contextTokens: "Token 上限",
|
|
296
|
+
contextFixed: "固定 {value}",
|
|
297
|
+
contextMaximum: "范围 128000–{value}",
|
|
234
298
|
quickQuotaStatus: "Codex 剩余额度 {value}%",
|
|
235
299
|
speedTitle: "速度",
|
|
236
300
|
speedStandard: "标准",
|
|
@@ -302,10 +366,11 @@ window.__ModuleLoader__.load({
|
|
|
302
366
|
diagnosticsFailed: "Could not create diagnostics.",
|
|
303
367
|
feedbackOpen: "Report a problem",
|
|
304
368
|
searchTitle: "Search source",
|
|
369
|
+
searchScope: "Applies to every model and session; it does not switch with the selected model.",
|
|
305
370
|
searchDsh: "DSH default",
|
|
306
|
-
searchDshHint: "
|
|
371
|
+
searchDshHint: "Use DSH's current search service for every model",
|
|
307
372
|
searchCodex: "Codex subscription",
|
|
308
|
-
searchCodexHint: "ChatGPT subscription
|
|
373
|
+
searchCodexHint: "Search through the signed-in ChatGPT subscription for every model",
|
|
309
374
|
preferenceFailed: "The setting was not saved.",
|
|
310
375
|
preferenceRetry: "Retry",
|
|
311
376
|
usage: "Subscription quota",
|
|
@@ -363,6 +428,16 @@ window.__ModuleLoader__.load({
|
|
|
363
428
|
quickQuotaOff: "Off",
|
|
364
429
|
quickQuotaPercent: "Percent",
|
|
365
430
|
quickQuotaBar: "Progress bar",
|
|
431
|
+
contextTitle: "Context window",
|
|
432
|
+
contextStandard: "Standard",
|
|
433
|
+
contextStandardHint: "Use the model catalog default; official agent presets manage context automatically.",
|
|
434
|
+
contextExtended: "Extended",
|
|
435
|
+
contextExtendedHint: "Uses 400K or 1M by model; usage above 272K may consume more quota.",
|
|
436
|
+
contextCustom: "Custom",
|
|
437
|
+
contextCustomHint: "Enter the full token count; lower values make official agent presets compact sooner.",
|
|
438
|
+
contextTokens: "Token limit",
|
|
439
|
+
contextFixed: "Fixed {value}",
|
|
440
|
+
contextMaximum: "128000–{value}",
|
|
366
441
|
quickQuotaStatus: "Codex quota: {value}% remaining",
|
|
367
442
|
speedTitle: "Speed",
|
|
368
443
|
speedStandard: "Standard",
|
|
@@ -409,6 +484,7 @@ window.__ModuleLoader__.load({
|
|
|
409
484
|
imageRemoveAnnotation: "Remove note"
|
|
410
485
|
};
|
|
411
486
|
const STYLE = `
|
|
487
|
+
.codexSubscriptionSearchHead{display:flex;flex-direction:column;gap:1px}.codexSubscriptionSearchScope{font-size:11px;line-height:17px;color:var(--dsw-alias-label-tertiary)}
|
|
412
488
|
.codexSubscription{display:flex;flex-direction:column;gap:10px;max-width:720px;color:var(--dsw-alias-label-primary);container-type:inline-size}
|
|
413
489
|
.codexSubscription h2,.codexSubscription h3,.codexSubscription p{margin:0}.codexSubscriptionHead{display:flex;align-items:center;gap:8px;flex-wrap:wrap}
|
|
414
490
|
.codexSubscription h2{font-size:16px;line-height:24px;font-weight:500}.codexSubscription h3{font-size:14px;line-height:22px;font-weight:500}
|
|
@@ -417,6 +493,7 @@ window.__ModuleLoader__.load({
|
|
|
417
493
|
.codexSubscriptionCard{border:1px solid var(--dsw-alias-border-l2);border-radius:12px;background:var(--dsw-alias-bg-layer-1);padding:14px 16px;display:flex;flex-direction:column;gap:12px}
|
|
418
494
|
.codexSubscriptionUsageCard{padding:12px 14px;gap:9px}.codexSubscriptionPreferencesCard{padding:12px 14px;gap:10px}.codexSubscriptionPreference{min-height:32px;box-sizing:border-box;display:flex;align-items:center;justify-content:space-between;gap:12px;color:var(--dsw-alias-label-primary);font-size:13px;line-height:20px}.codexSubscriptionPreferenceCopy{display:flex;min-width:0;flex-direction:column;gap:2px}.codexSubscriptionPreferenceLabel{display:flex;align-items:center;gap:6px}
|
|
419
495
|
.codexSubscriptionQuotaModes{display:flex;align-items:center;gap:3px;padding:2px;border-radius:9px;background:var(--dsw-alias-bg-module-platform)}.codexSubscriptionQuotaMode{position:relative;display:flex;align-items:center;justify-content:center;min-height:26px;padding:0 9px;border-radius:7px;color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:18px;cursor:pointer}.codexSubscriptionQuotaMode:has(input:checked){background:var(--dsw-alias-bg-layer-2);color:var(--dsw-alias-label-primary);box-shadow:0 0 0 1px var(--dsw-alias-border-l3)}.codexSubscriptionQuotaMode:has(input:focus-visible){outline:2px solid var(--dsw-alias-border-l3);outline-offset:1px}.codexSubscriptionQuotaMode:has(input:disabled){cursor:not-allowed;opacity:.5}.codexSubscriptionQuotaMode input{position:absolute;width:1px;height:1px;opacity:0;pointer-events:none}
|
|
496
|
+
.codexSubscriptionContext{display:flex;flex-direction:column;gap:8px}.codexSubscriptionContextHead{display:flex;align-items:flex-start;justify-content:space-between;gap:12px}.codexSubscriptionContextCopy{display:flex;min-width:0;flex:1;flex-direction:column;gap:2px}.codexSubscriptionContextHint{font-size:11px;line-height:17px;color:var(--dsw-alias-label-tertiary)}.codexSubscriptionContextTrigger{height:32px;min-width:108px;display:inline-flex;align-items:center;justify-content:space-between;gap:10px;padding:0 10px 0 12px;border:0;border-radius:999px;outline:0;background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-label-primary);font:inherit;font-size:12px;cursor:pointer}.codexSubscriptionContextTrigger:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.codexSubscriptionContextTrigger:focus-visible{box-shadow:0 0 0 2px var(--dsw-alias-border-l3)}.codexSubscriptionContextTrigger:disabled{color:var(--dsw-alias-label-dimmed);cursor:not-allowed}.codexSubscriptionContextTrigger svg{color:var(--dsw-alias-label-tertiary);transition:transform 120ms var(--ds-ease-in-out)}.codexSubscriptionContextTrigger[aria-expanded=true] svg{transform:rotate(180deg)}.codexSubscriptionContextModels{display:flex;flex-direction:column;border-top:1px solid var(--dsw-alias-border-l2)}.codexSubscriptionContextModel{min-height:42px;display:flex;align-items:center;justify-content:space-between;gap:12px;border-bottom:1px solid var(--dsw-alias-border-l2)}.codexSubscriptionContextModel:last-child{border-bottom:0}.codexSubscriptionContextModelCopy{display:flex;min-width:0;flex-direction:column}.codexSubscriptionContextModelCopy strong{font-size:12px;line-height:18px;font-weight:500}.codexSubscriptionContextModelCopy span{font-size:11px;line-height:16px;color:var(--dsw-alias-label-tertiary)}.codexSubscriptionContextInput{width:116px}
|
|
420
497
|
.codexSubscriptionSwitch{position:relative;flex:0 0 auto;width:32px;height:18px;padding:0;border:1px solid var(--dsw-alias-border-l3);border-radius:999px;background:var(--dsw-alias-bg-module-platform);cursor:pointer}.codexSubscriptionSwitch:disabled{cursor:not-allowed;opacity:.5}.codexSubscriptionSwitch[aria-checked=true]{background:var(--dsw-alias-label-secondary);border-color:var(--dsw-alias-label-secondary)}.codexSubscriptionSwitchKnob{position:absolute;top:2px;left:2px;width:12px;height:12px;border-radius:50%;background:var(--dsw-alias-bg-layer-1);transition:transform 120ms var(--ds-ease-in-out)}.codexSubscriptionSwitch[aria-checked=true] .codexSubscriptionSwitchKnob{transform:translateX(14px)}
|
|
421
498
|
.codexSubscriptionSearch{display:flex;flex-direction:column;gap:7px}.codexSubscriptionSearchChoices{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:6px}.codexSubscriptionSearchChoice{display:grid;grid-template-columns:14px minmax(0,1fr);align-items:center;column-gap:8px;min-width:0;border:1px solid var(--dsw-alias-border-l2);border-radius:10px;background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-label-primary);padding:9px 10px;text-align:left;cursor:pointer}.codexSubscriptionSearchChoice:has(input:disabled){cursor:not-allowed;opacity:.5}.codexSubscriptionSearchChoice:has(input:checked){border-color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-2)}.codexSubscriptionSearchChoice:has(input:focus-visible){outline:2px solid var(--dsw-alias-border-l3);outline-offset:2px}.codexSubscriptionSearchInput{width:14px;height:14px;margin:0;accent-color:var(--dsw-alias-label-primary);cursor:inherit}.codexSubscriptionSearchCopy{display:block;min-width:0;pointer-events:none}.codexSubscriptionSearchCopy strong,.codexSubscriptionSearchCopy span{display:block}.codexSubscriptionSearchCopy strong{font-size:12px;line-height:18px;font-weight:500;color:var(--dsw-alias-label-secondary)}.codexSubscriptionSearchChoice:has(input:checked) strong{color:var(--dsw-alias-label-primary)}.codexSubscriptionSearchCopy span{font-size:11px;line-height:16px;color:var(--dsw-alias-label-tertiary)}.codexSubscriptionDivider{height:1px;background:var(--dsw-alias-border-l2)}
|
|
422
499
|
.codexSubscriptionAccountRow,.codexSubscriptionSectionHead{display:flex;align-items:center;justify-content:space-between;gap:12px}.codexSubscriptionStatus{display:flex;align-items:center;gap:8px;font-size:14px;line-height:22px;font-weight:500}
|
|
@@ -489,15 +566,7 @@ window.__ModuleLoader__.load({
|
|
|
489
566
|
return cleaned.toLowerCase().endsWith(".png") ? cleaned : `${cleaned}.png`;
|
|
490
567
|
};
|
|
491
568
|
const imageByteSize = (bytes) => bytes < 1024 * 1024 ? `${Math.max(.1, bytes / 1024).toLocaleString(void 0, { maximumFractionDigits: 1 })} KB` : `${(bytes / 1024 / 1024).toLocaleString(void 0, { maximumFractionDigits: 1 })} MB`;
|
|
492
|
-
function
|
|
493
|
-
const notes = annotations.map((annotation, index) => ({
|
|
494
|
-
number: index + 1,
|
|
495
|
-
note: annotation.note.trim()
|
|
496
|
-
})).filter((annotation) => annotation.note !== "").map((annotation) => String(annotation.number) + ". " + annotation.note);
|
|
497
|
-
const base = prompt.trim() === "" ? t("imageEditDefault") : prompt.trim();
|
|
498
|
-
return notes.length === 0 ? base : base + "\n\n" + t("imageRegionNotes") + "\n" + notes.join("\n");
|
|
499
|
-
}
|
|
500
|
-
function CodexGeneratedImage({ attachment, loadImage, attachForEdit, t }) {
|
|
569
|
+
function CodexGeneratedImage({ attachment, loadImage, attachForEdit, getImageViewer, t }) {
|
|
501
570
|
const [attempt, setAttempt] = (0, react.useState)(0);
|
|
502
571
|
const [error, setError] = (0, react.useState)(false);
|
|
503
572
|
const [open, setOpen] = (0, react.useState)(false);
|
|
@@ -583,7 +652,11 @@ window.__ModuleLoader__.load({
|
|
|
583
652
|
setEditBusy(true);
|
|
584
653
|
setEditError(false);
|
|
585
654
|
try {
|
|
586
|
-
await attachForEdit(src, downloadName,
|
|
655
|
+
await attachForEdit(src, downloadName, buildImageEditDraft({
|
|
656
|
+
prompt,
|
|
657
|
+
annotations,
|
|
658
|
+
translate: t
|
|
659
|
+
}));
|
|
587
660
|
close();
|
|
588
661
|
} catch {
|
|
589
662
|
setEditError(true);
|
|
@@ -591,6 +664,35 @@ window.__ModuleLoader__.load({
|
|
|
591
664
|
setEditBusy(false);
|
|
592
665
|
}
|
|
593
666
|
};
|
|
667
|
+
const openImage = () => {
|
|
668
|
+
if (src === void 0) return;
|
|
669
|
+
if ((getImageViewer?.())?.open?.({
|
|
670
|
+
items: [{
|
|
671
|
+
id: attachment.attachmentId ?? downloadName,
|
|
672
|
+
src,
|
|
673
|
+
name: label,
|
|
674
|
+
width: attachment.width,
|
|
675
|
+
height: attachment.height,
|
|
676
|
+
bytes: attachment.bytes
|
|
677
|
+
}],
|
|
678
|
+
opener: triggerRef.current,
|
|
679
|
+
source: "codex-generated",
|
|
680
|
+
annotations: true,
|
|
681
|
+
editor: {
|
|
682
|
+
label: t("imageEdit"),
|
|
683
|
+
busyLabel: t("imageEditPreparing"),
|
|
684
|
+
errorLabel: t("imageEditFailed"),
|
|
685
|
+
placeholder: t("imageEditPrompt"),
|
|
686
|
+
onSubmit: ({ prompt: nextPrompt, annotations: nextAnnotations }) => attachForEdit(src, downloadName, buildImageEditDraft({
|
|
687
|
+
prompt: nextPrompt,
|
|
688
|
+
annotations: nextAnnotations,
|
|
689
|
+
translate: t
|
|
690
|
+
}))
|
|
691
|
+
}
|
|
692
|
+
}) === true) return;
|
|
693
|
+
setZoom(1);
|
|
694
|
+
setOpen(true);
|
|
695
|
+
};
|
|
594
696
|
if (error) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
595
697
|
type: "button",
|
|
596
698
|
className: "codexGeneratedImageRetry",
|
|
@@ -756,19 +858,14 @@ window.__ModuleLoader__.load({
|
|
|
756
858
|
className: "codexGeneratedImageFrame",
|
|
757
859
|
title: t("imageOpen"),
|
|
758
860
|
"aria-label": fill(t("imageOpenNamed"), { value: label }),
|
|
759
|
-
onClick:
|
|
760
|
-
if (src !== void 0) {
|
|
761
|
-
setZoom(1);
|
|
762
|
-
setOpen(true);
|
|
763
|
-
}
|
|
764
|
-
},
|
|
861
|
+
onClick: openImage,
|
|
765
862
|
children: src === void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("imageLoading") }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("img", {
|
|
766
863
|
src,
|
|
767
864
|
alt: label
|
|
768
865
|
})
|
|
769
866
|
}), lightbox] });
|
|
770
867
|
}
|
|
771
|
-
function CodexImageToolRow({ block, loadImage, attachForEdit, t }) {
|
|
868
|
+
function CodexImageToolRow({ block, loadImage, attachForEdit, getImageViewer, t }) {
|
|
772
869
|
const settled = block?.kind === "tool-result";
|
|
773
870
|
const image = settled ? block.content.find((item) => item?.type === "image" && item.attachment !== void 0) : void 0;
|
|
774
871
|
const failed = settled && block.isError === true;
|
|
@@ -806,6 +903,7 @@ window.__ModuleLoader__.load({
|
|
|
806
903
|
attachment: image.attachment,
|
|
807
904
|
loadImage,
|
|
808
905
|
attachForEdit,
|
|
906
|
+
getImageViewer,
|
|
809
907
|
t
|
|
810
908
|
})
|
|
811
909
|
}),
|
|
@@ -823,6 +921,7 @@ window.__ModuleLoader__.load({
|
|
|
823
921
|
let fallback;
|
|
824
922
|
let failedPatch;
|
|
825
923
|
let generation = 0;
|
|
924
|
+
let contextModels = [];
|
|
826
925
|
const nativeSnapshot = () => scope.getSnapshot();
|
|
827
926
|
const read = () => {
|
|
828
927
|
const native = nativeSnapshot();
|
|
@@ -832,6 +931,10 @@ window.__ModuleLoader__.load({
|
|
|
832
931
|
quickQuotaMode: normalizeQuickQuotaMode(current.value?.[QUICK_QUOTA_MODE_FIELD], current.value?.[LEGACY_QUICK_QUOTA_FIELD]),
|
|
833
932
|
searchProvider: normalizeSearchProvider(current.value?.[SEARCH_PROVIDER_FIELD]),
|
|
834
933
|
speedMode: normalizeSpeedMode(current.value?.[SPEED_MODE_FIELD]),
|
|
934
|
+
contextMode: normalizeContextMode(current.value?.[CONTEXT_MODE_FIELD]),
|
|
935
|
+
customContextWindow: normalizeCustomContextWindow(current.value?.[CUSTOM_CONTEXT_WINDOW_FIELD]),
|
|
936
|
+
customContextWindows: Object.fromEntries(Object.entries(CUSTOM_CONTEXT_MODEL_FIELDS).map(([modelKey, field]) => [modelKey, normalizeCustomContextWindow(current.value?.[field] ?? CUSTOM_CONTEXT_MODEL_DEFAULTS[modelKey], CUSTOM_CONTEXT_MODEL_CAPS[modelKey])])),
|
|
937
|
+
contextModels,
|
|
835
938
|
writable: !updating && current.status === "ready" && current.writable === true,
|
|
836
939
|
error
|
|
837
940
|
});
|
|
@@ -848,13 +951,17 @@ window.__ModuleLoader__.load({
|
|
|
848
951
|
publish();
|
|
849
952
|
});
|
|
850
953
|
const acceptFallback = (value) => {
|
|
954
|
+
contextModels = Array.isArray(value?.contextModels) ? value.contextModels : [];
|
|
851
955
|
fallbackStatus = "ready";
|
|
852
956
|
fallback = {
|
|
853
957
|
status: "ready",
|
|
854
958
|
value: {
|
|
855
959
|
[QUICK_QUOTA_MODE_FIELD]: normalizeQuickQuotaMode(value?.[QUICK_QUOTA_MODE_FIELD], value?.[LEGACY_QUICK_QUOTA_FIELD]),
|
|
856
960
|
[SEARCH_PROVIDER_FIELD]: normalizeSearchProvider(value?.[SEARCH_PROVIDER_FIELD]),
|
|
857
|
-
[SPEED_MODE_FIELD]: normalizeSpeedMode(value?.[SPEED_MODE_FIELD])
|
|
961
|
+
[SPEED_MODE_FIELD]: normalizeSpeedMode(value?.[SPEED_MODE_FIELD]),
|
|
962
|
+
[CONTEXT_MODE_FIELD]: normalizeContextMode(value?.[CONTEXT_MODE_FIELD]),
|
|
963
|
+
[CUSTOM_CONTEXT_WINDOW_FIELD]: normalizeCustomContextWindow(value?.[CUSTOM_CONTEXT_WINDOW_FIELD]),
|
|
964
|
+
...Object.fromEntries(Object.entries(CUSTOM_CONTEXT_MODEL_FIELDS).map(([modelKey, field]) => [field, normalizeCustomContextWindow(value?.[field] ?? CUSTOM_CONTEXT_MODEL_DEFAULTS[modelKey], CUSTOM_CONTEXT_MODEL_CAPS[modelKey])]))
|
|
858
965
|
},
|
|
859
966
|
writable: value?.writable === true
|
|
860
967
|
};
|
|
@@ -866,11 +973,12 @@ window.__ModuleLoader__.load({
|
|
|
866
973
|
fallback = void 0;
|
|
867
974
|
error = false;
|
|
868
975
|
publish();
|
|
869
|
-
|
|
976
|
+
nativeSnapshot();
|
|
870
977
|
try {
|
|
871
978
|
const value = unwrap(await rpc.call(CHANNEL, "preferences/status", {}));
|
|
872
|
-
if (current !== generation
|
|
873
|
-
|
|
979
|
+
if (current !== generation) return;
|
|
980
|
+
if (nativeSnapshot().status === "ready") contextModels = Array.isArray(value?.contextModels) ? value.contextModels : [];
|
|
981
|
+
else acceptFallback(value);
|
|
874
982
|
publish();
|
|
875
983
|
} catch {
|
|
876
984
|
if (current !== generation || nativeSnapshot().status === "ready") return;
|
|
@@ -1027,7 +1135,13 @@ window.__ModuleLoader__.load({
|
|
|
1027
1135
|
});
|
|
1028
1136
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1029
1137
|
className: "codexSubscriptionSearch",
|
|
1030
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.
|
|
1138
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1139
|
+
className: "codexSubscriptionSearchHead",
|
|
1140
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", { children: t("searchTitle") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1141
|
+
className: "codexSubscriptionSearchScope",
|
|
1142
|
+
children: t("searchScope")
|
|
1143
|
+
})]
|
|
1144
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1031
1145
|
className: "codexSubscriptionSearchChoices",
|
|
1032
1146
|
role: "radiogroup",
|
|
1033
1147
|
"aria-label": t("searchTitle"),
|
|
@@ -1035,6 +1149,125 @@ window.__ModuleLoader__.load({
|
|
|
1035
1149
|
})]
|
|
1036
1150
|
});
|
|
1037
1151
|
}
|
|
1152
|
+
function ContextWindowPreference({ preference, t }) {
|
|
1153
|
+
const snapshot = usePreferenceSnapshot(preference);
|
|
1154
|
+
const writable = snapshot.status === "ready" && snapshot.writable === true;
|
|
1155
|
+
const [menuOpen, setMenuOpen] = (0, react.useState)(false);
|
|
1156
|
+
const modelRows = snapshot.contextModels.filter((model) => model.fixed !== true);
|
|
1157
|
+
const fixedRows = snapshot.contextModels.filter((model) => model.fixed === true);
|
|
1158
|
+
const [drafts, setDrafts] = (0, react.useState)({});
|
|
1159
|
+
(0, react.useEffect)(() => setDrafts(Object.fromEntries(modelRows.map((model) => [model.key, String(snapshot.customContextWindows[model.key])]))), [snapshot.customContextWindows, snapshot.contextModels]);
|
|
1160
|
+
const hint = snapshot.contextMode === "extended" ? t("contextExtendedHint") : snapshot.contextMode === "custom" ? t("contextCustomHint") : t("contextStandardHint");
|
|
1161
|
+
const commit = (modelKey) => {
|
|
1162
|
+
const parsed = parseContextWindow(drafts[modelKey]);
|
|
1163
|
+
if (!Number.isInteger(parsed)) {
|
|
1164
|
+
setDrafts((current) => ({
|
|
1165
|
+
...current,
|
|
1166
|
+
[modelKey]: String(snapshot.customContextWindows[modelKey])
|
|
1167
|
+
}));
|
|
1168
|
+
return;
|
|
1169
|
+
}
|
|
1170
|
+
const value = normalizeCustomContextWindow(parsed, CUSTOM_CONTEXT_MODEL_CAPS[modelKey]);
|
|
1171
|
+
setDrafts((current) => ({
|
|
1172
|
+
...current,
|
|
1173
|
+
[modelKey]: String(value)
|
|
1174
|
+
}));
|
|
1175
|
+
if (value !== snapshot.customContextWindows[modelKey]) preference.set({ [CUSTOM_CONTEXT_MODEL_FIELDS[modelKey]]: value });
|
|
1176
|
+
};
|
|
1177
|
+
const contextModeItems = [
|
|
1178
|
+
{
|
|
1179
|
+
id: CONTEXT_MODE_STANDARD,
|
|
1180
|
+
label: t("contextStandard")
|
|
1181
|
+
},
|
|
1182
|
+
{
|
|
1183
|
+
id: CONTEXT_MODE_EXTENDED,
|
|
1184
|
+
label: t("contextExtended")
|
|
1185
|
+
},
|
|
1186
|
+
{
|
|
1187
|
+
id: CONTEXT_MODE_CUSTOM,
|
|
1188
|
+
label: t("contextCustom")
|
|
1189
|
+
}
|
|
1190
|
+
];
|
|
1191
|
+
const selectedMode = contextModeItems.find((item) => item.id === snapshot.contextMode)?.label ?? t("contextStandard");
|
|
1192
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1193
|
+
className: "codexSubscriptionContext",
|
|
1194
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1195
|
+
className: "codexSubscriptionContextHead",
|
|
1196
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1197
|
+
className: "codexSubscriptionContextCopy",
|
|
1198
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1199
|
+
className: "codexSubscriptionPreferenceLabel",
|
|
1200
|
+
children: t("contextTitle")
|
|
1201
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1202
|
+
className: "codexSubscriptionContextHint",
|
|
1203
|
+
children: hint
|
|
1204
|
+
})]
|
|
1205
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Menu, {
|
|
1206
|
+
open: menuOpen,
|
|
1207
|
+
items: contextModeItems,
|
|
1208
|
+
selectedId: snapshot.contextMode,
|
|
1209
|
+
onSelect: (value) => {
|
|
1210
|
+
setMenuOpen(false);
|
|
1211
|
+
preference.set({ [CONTEXT_MODE_FIELD]: value });
|
|
1212
|
+
},
|
|
1213
|
+
onClose: () => setMenuOpen(false),
|
|
1214
|
+
align: "end",
|
|
1215
|
+
side: "bottom",
|
|
1216
|
+
portal: true,
|
|
1217
|
+
compact: true,
|
|
1218
|
+
anchor: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
1219
|
+
className: "codexSubscriptionContextTrigger",
|
|
1220
|
+
type: "button",
|
|
1221
|
+
"aria-label": t("contextTitle"),
|
|
1222
|
+
"aria-haspopup": "menu",
|
|
1223
|
+
"aria-expanded": menuOpen,
|
|
1224
|
+
disabled: !writable,
|
|
1225
|
+
onClick: () => setMenuOpen((value) => !value),
|
|
1226
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: selectedMode }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronDownOutline14, {})]
|
|
1227
|
+
})
|
|
1228
|
+
})]
|
|
1229
|
+
}), snapshot.contextMode === "custom" ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1230
|
+
className: "codexSubscriptionContextModels",
|
|
1231
|
+
children: [modelRows.map((model) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1232
|
+
className: "codexSubscriptionContextModel",
|
|
1233
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
1234
|
+
className: "codexSubscriptionContextModelCopy",
|
|
1235
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: model.label }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: fill(t("contextMaximum"), { value: String(model.maximum) }) })]
|
|
1236
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Input, {
|
|
1237
|
+
"aria-label": `${model.label} ${t("contextTokens")}`,
|
|
1238
|
+
className: "codexSubscriptionContextInput",
|
|
1239
|
+
type: "number",
|
|
1240
|
+
inputMode: "numeric",
|
|
1241
|
+
min: MIN_CUSTOM_CONTEXT_WINDOW,
|
|
1242
|
+
max: model.maximum,
|
|
1243
|
+
step: 1,
|
|
1244
|
+
value: drafts[model.key] ?? "",
|
|
1245
|
+
disabled: !writable,
|
|
1246
|
+
onChange: (event) => {
|
|
1247
|
+
const nextValue = event.currentTarget.value;
|
|
1248
|
+
setDrafts((current) => ({
|
|
1249
|
+
...current,
|
|
1250
|
+
[model.key]: nextValue
|
|
1251
|
+
}));
|
|
1252
|
+
},
|
|
1253
|
+
onBlur: () => commit(model.key),
|
|
1254
|
+
onKeyDown: (event) => {
|
|
1255
|
+
if (event.key === "Enter") event.currentTarget.blur();
|
|
1256
|
+
}
|
|
1257
|
+
})]
|
|
1258
|
+
}, model.key)), fixedRows.map((model) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1259
|
+
className: "codexSubscriptionContextModel",
|
|
1260
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
1261
|
+
className: "codexSubscriptionContextModelCopy",
|
|
1262
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: model.label }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: fill(t("contextFixed"), { value: formatContextWindow(model.maximum) }) })]
|
|
1263
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1264
|
+
className: "codexSubscriptionContextHint",
|
|
1265
|
+
children: formatContextWindow(model.maximum)
|
|
1266
|
+
})]
|
|
1267
|
+
}, model.key))]
|
|
1268
|
+
}) : null]
|
|
1269
|
+
});
|
|
1270
|
+
}
|
|
1038
1271
|
function PreferencesCard({ preference, t }) {
|
|
1039
1272
|
const snapshot = usePreferenceSnapshot(preference);
|
|
1040
1273
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
@@ -1045,6 +1278,11 @@ window.__ModuleLoader__.load({
|
|
|
1045
1278
|
t
|
|
1046
1279
|
}),
|
|
1047
1280
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { className: "codexSubscriptionDivider" }),
|
|
1281
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ContextWindowPreference, {
|
|
1282
|
+
preference,
|
|
1283
|
+
t
|
|
1284
|
+
}),
|
|
1285
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { className: "codexSubscriptionDivider" }),
|
|
1048
1286
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(QuickQuotaPreference, {
|
|
1049
1287
|
preference,
|
|
1050
1288
|
t
|
|
@@ -2140,6 +2378,13 @@ window.__ModuleLoader__.load({
|
|
|
2140
2378
|
inject: (sessionId) => ({
|
|
2141
2379
|
t,
|
|
2142
2380
|
loadImage: (attachment) => conversation.resolveImage(sessionId, attachment),
|
|
2381
|
+
getImageViewer: () => {
|
|
2382
|
+
try {
|
|
2383
|
+
return ctx.get("nativeImageViewer");
|
|
2384
|
+
} catch {
|
|
2385
|
+
return;
|
|
2386
|
+
}
|
|
2387
|
+
},
|
|
2143
2388
|
attachForEdit: async (src, filename, draft) => {
|
|
2144
2389
|
const actx = sessions.scope(sessionId);
|
|
2145
2390
|
if (actx === void 0 || typeof conversation.createDraftImages !== "function" || conversation.input?.for === void 0) throw new Error("This DSH version does not provide the image composer bridge");
|
package/lib/index.js
CHANGED
|
@@ -5,6 +5,8 @@ import { settingsNamespace } from "@deepseek-ai/dsh-settings";
|
|
|
5
5
|
import z from "@deepseek-ai/schemastery";
|
|
6
6
|
import { execFile, spawn } from "node:child_process";
|
|
7
7
|
import { request } from "node:https";
|
|
8
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
9
|
+
import { Readable } from "node:stream";
|
|
8
10
|
import { promisify } from "node:util";
|
|
9
11
|
import { HttpsProxyAgent } from "https-proxy-agent";
|
|
10
12
|
import { openaiCodexProvider as createOpenAICodexProvider } from "@earendil-works/pi-ai/providers/openai-codex";
|
|
@@ -477,8 +479,11 @@ function createCodexRpcHandler(coordinator, options = {}) {
|
|
|
477
479
|
//#region src/oauth-network.js
|
|
478
480
|
const execFileAsync = promisify(execFile);
|
|
479
481
|
const CODEX_AUTH_HOST = "auth.openai.com";
|
|
480
|
-
const
|
|
481
|
-
|
|
482
|
+
const CODEX_HOSTS = /* @__PURE__ */ new Set([CODEX_AUTH_HOST, "chatgpt.com"]);
|
|
483
|
+
const networkScope = new AsyncLocalStorage();
|
|
484
|
+
let activeScopes = 0;
|
|
485
|
+
let baseFetch;
|
|
486
|
+
let scopedFetch;
|
|
482
487
|
function normalizeProxy(raw) {
|
|
483
488
|
if (typeof raw !== "string" || raw.trim() === "") return void 0;
|
|
484
489
|
const value = raw.trim().includes("://") ? raw.trim() : `http://${raw.trim()}`;
|
|
@@ -556,12 +561,27 @@ async function macSystemProxy(options = {}) {
|
|
|
556
561
|
return;
|
|
557
562
|
}
|
|
558
563
|
}
|
|
559
|
-
async function
|
|
560
|
-
const
|
|
561
|
-
|
|
564
|
+
async function resolveCodexProxy(options = {}) {
|
|
565
|
+
const target = options.target ?? new URL(`https://${CODEX_AUTH_HOST}/`);
|
|
566
|
+
const env = options.env ?? process.env;
|
|
567
|
+
if (bypassesProxy(target.hostname.toLowerCase(), target.port || "443", env.NO_PROXY ?? env.no_proxy)) return {
|
|
568
|
+
url: void 0,
|
|
569
|
+
source: "bypass"
|
|
570
|
+
};
|
|
571
|
+
const envProxy = proxyFromEnvironment(env, target);
|
|
572
|
+
if (envProxy) return {
|
|
573
|
+
url: envProxy,
|
|
574
|
+
source: "environment"
|
|
575
|
+
};
|
|
562
576
|
const platform = options.platform ?? process.platform;
|
|
563
|
-
|
|
564
|
-
|
|
577
|
+
const system = platform === "win32" ? await windowsSystemProxy(options) : platform === "darwin" ? await macSystemProxy(options) : void 0;
|
|
578
|
+
return system ? {
|
|
579
|
+
url: system,
|
|
580
|
+
source: "system"
|
|
581
|
+
} : {
|
|
582
|
+
url: void 0,
|
|
583
|
+
source: "direct"
|
|
584
|
+
};
|
|
565
585
|
}
|
|
566
586
|
function bodyBytes(body) {
|
|
567
587
|
if (body === void 0 || body === null) return void 0;
|
|
@@ -582,49 +602,123 @@ function fetchThroughProxy(input, init, proxyUrl) {
|
|
|
582
602
|
agent: new HttpsProxyAgent(proxyUrl),
|
|
583
603
|
signal: init?.signal
|
|
584
604
|
}, (response) => {
|
|
585
|
-
const
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
status: response.statusCode ?? 500,
|
|
605
|
+
const responseHeaders = new Headers();
|
|
606
|
+
for (const [name, value] of Object.entries(response.headers)) if (Array.isArray(value)) value.forEach((item) => responseHeaders.append(name, item));
|
|
607
|
+
else if (value !== void 0) responseHeaders.set(name, value);
|
|
608
|
+
const status = response.statusCode ?? 500;
|
|
609
|
+
const empty = init?.method === "HEAD" || [
|
|
610
|
+
204,
|
|
611
|
+
205,
|
|
612
|
+
304
|
|
613
|
+
].includes(status);
|
|
614
|
+
resolve(new Response(empty ? null : Readable.toWeb(response), {
|
|
615
|
+
status,
|
|
597
616
|
statusText: response.statusMessage,
|
|
598
|
-
headers:
|
|
599
|
-
}))
|
|
617
|
+
headers: responseHeaders
|
|
618
|
+
}));
|
|
600
619
|
});
|
|
601
620
|
request$1.on("error", reject);
|
|
602
621
|
if (body) request$1.write(body);
|
|
603
622
|
request$1.end();
|
|
604
623
|
});
|
|
605
624
|
}
|
|
606
|
-
async function
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
625
|
+
async function withCodexNetwork(run, options = {}) {
|
|
626
|
+
if (activeScopes === 0) {
|
|
627
|
+
baseFetch = globalThis.fetch;
|
|
628
|
+
scopedFetch = async (input, init) => {
|
|
629
|
+
const scope = networkScope.getStore();
|
|
630
|
+
if (scope === void 0) return baseFetch(input, init);
|
|
631
|
+
const { options: scopedOptions, allowedHosts, resolved } = scope;
|
|
632
|
+
const proxyFetch = scopedOptions.fetchThroughProxy ?? fetchThroughProxy;
|
|
633
|
+
const target = new URL(typeof input === "string" || input instanceof URL ? input : input.url);
|
|
634
|
+
if (target.protocol !== "https:" || !allowedHosts.has(target.hostname)) return baseFetch(input, init);
|
|
635
|
+
let proxy = resolved.get(target.hostname);
|
|
636
|
+
if (proxy === void 0) {
|
|
637
|
+
proxy = resolveCodexProxy({
|
|
638
|
+
...scopedOptions,
|
|
639
|
+
target
|
|
640
|
+
});
|
|
641
|
+
resolved.set(target.hostname, proxy);
|
|
642
|
+
}
|
|
643
|
+
const route = await proxy;
|
|
644
|
+
scopedOptions.onRoute?.(route.source);
|
|
645
|
+
return route.url === void 0 ? baseFetch(input, init) : proxyFetch(input, init, route.url);
|
|
646
|
+
};
|
|
647
|
+
globalThis.fetch = scopedFetch;
|
|
648
|
+
}
|
|
649
|
+
activeScopes += 1;
|
|
650
|
+
const scope = {
|
|
651
|
+
options,
|
|
652
|
+
allowedHosts: options.hosts ?? CODEX_HOSTS,
|
|
653
|
+
resolved: /* @__PURE__ */ new Map()
|
|
654
|
+
};
|
|
621
655
|
try {
|
|
622
|
-
return await run();
|
|
656
|
+
return await networkScope.run(scope, run);
|
|
623
657
|
} finally {
|
|
624
|
-
|
|
625
|
-
|
|
658
|
+
activeScopes -= 1;
|
|
659
|
+
if (activeScopes === 0) {
|
|
660
|
+
if (globalThis.fetch === scopedFetch) globalThis.fetch = baseFetch;
|
|
661
|
+
baseFetch = void 0;
|
|
662
|
+
scopedFetch = void 0;
|
|
663
|
+
}
|
|
626
664
|
}
|
|
627
665
|
}
|
|
666
|
+
function classifyTransportError(error) {
|
|
667
|
+
const name = error?.name;
|
|
668
|
+
const code = String(error?.code ?? error?.cause?.code ?? "");
|
|
669
|
+
if (name === "AbortError" || name === "TimeoutError" || /ETIMEDOUT|UND_ERR_CONNECT_TIMEOUT/u.test(code)) return "timeout";
|
|
670
|
+
if (/ENOTFOUND|EAI_AGAIN/u.test(code)) return "dns";
|
|
671
|
+
if (/CERT_|TLS|SSL/u.test(code)) return "tls";
|
|
672
|
+
if (/ECONN|EPIPE|UND_ERR_SOCKET/u.test(code)) return "connection";
|
|
673
|
+
return "network";
|
|
674
|
+
}
|
|
675
|
+
const elapsedBucket = (elapsed) => elapsed < 1e3 ? "under-1s" : elapsed < 5e3 ? "1-5s" : elapsed < 15e3 ? "5-15s" : "over-15s";
|
|
676
|
+
function createCodexNetworkTransport(options = {}) {
|
|
677
|
+
const attempts = /* @__PURE__ */ new Map();
|
|
678
|
+
const now = options.now ?? Date.now;
|
|
679
|
+
const run = async (area, operation) => {
|
|
680
|
+
const startedAt = now();
|
|
681
|
+
let route = attempts.get(area)?.route ?? "direct";
|
|
682
|
+
let routed = false;
|
|
683
|
+
try {
|
|
684
|
+
const value = await withCodexNetwork(operation, {
|
|
685
|
+
...options,
|
|
686
|
+
onRoute: (source) => {
|
|
687
|
+
route = source;
|
|
688
|
+
routed = true;
|
|
689
|
+
}
|
|
690
|
+
});
|
|
691
|
+
if (value instanceof Response && !value.ok) attempts.set(area, {
|
|
692
|
+
status: "failed",
|
|
693
|
+
stage: "http",
|
|
694
|
+
code: "http-error",
|
|
695
|
+
httpStatus: value.status,
|
|
696
|
+
route,
|
|
697
|
+
elapsed: elapsedBucket(now() - startedAt)
|
|
698
|
+
});
|
|
699
|
+
else if (routed || value instanceof Response) attempts.set(area, {
|
|
700
|
+
status: "ok",
|
|
701
|
+
route,
|
|
702
|
+
elapsed: elapsedBucket(now() - startedAt)
|
|
703
|
+
});
|
|
704
|
+
return value;
|
|
705
|
+
} catch (error) {
|
|
706
|
+
if (routed) attempts.set(area, {
|
|
707
|
+
status: "failed",
|
|
708
|
+
stage: "transport",
|
|
709
|
+
code: classifyTransportError(error),
|
|
710
|
+
route,
|
|
711
|
+
elapsed: elapsedBucket(now() - startedAt)
|
|
712
|
+
});
|
|
713
|
+
throw error;
|
|
714
|
+
}
|
|
715
|
+
};
|
|
716
|
+
return Object.freeze({
|
|
717
|
+
run,
|
|
718
|
+
fetch: (area, input, init) => run(area, () => globalThis.fetch(input, init)),
|
|
719
|
+
snapshot: () => Object.fromEntries([...attempts].map(([area, value]) => [area, { ...value }]))
|
|
720
|
+
});
|
|
721
|
+
}
|
|
628
722
|
//#endregion
|
|
629
723
|
//#region src/settings-contract.js
|
|
630
724
|
const SETTINGS_NAMESPACE = "codex-subscription";
|
|
@@ -637,6 +731,75 @@ const SPEED_MODE_FIELD = "speedMode";
|
|
|
637
731
|
const SPEED_MODE_STANDARD = "standard";
|
|
638
732
|
const SPEED_MODE_FAST = "fast";
|
|
639
733
|
const DEFAULT_SPEED_MODE = SPEED_MODE_STANDARD;
|
|
734
|
+
const CONTEXT_MODE_FIELD = "contextMode";
|
|
735
|
+
const CONTEXT_MODE_STANDARD = "standard";
|
|
736
|
+
const CONTEXT_MODE_EXTENDED = "extended";
|
|
737
|
+
const CONTEXT_MODE_CUSTOM = "custom";
|
|
738
|
+
const DEFAULT_CONTEXT_MODE = CONTEXT_MODE_STANDARD;
|
|
739
|
+
const CUSTOM_CONTEXT_WINDOW_FIELD = "customContextWindow";
|
|
740
|
+
const DEFAULT_CUSTOM_CONTEXT_WINDOW = 272e3;
|
|
741
|
+
const MIN_CUSTOM_CONTEXT_WINDOW = 128e3;
|
|
742
|
+
const MAX_CUSTOM_CONTEXT_WINDOW = 1e6;
|
|
743
|
+
const CUSTOM_CONTEXT_MODEL_FIELDS = Object.freeze({
|
|
744
|
+
"gpt-5.4": "customContextGpt54",
|
|
745
|
+
"gpt-5.4-mini": "customContextGpt54Mini",
|
|
746
|
+
"gpt-5.5": "customContextGpt55",
|
|
747
|
+
"gpt-5.6": "customContextGpt56"
|
|
748
|
+
});
|
|
749
|
+
const CUSTOM_CONTEXT_MODEL_CAPS = Object.freeze({
|
|
750
|
+
"gpt-5.4": 1e6,
|
|
751
|
+
"gpt-5.4-mini": 4e5,
|
|
752
|
+
"gpt-5.5": 1e6,
|
|
753
|
+
"gpt-5.6": 1e6
|
|
754
|
+
});
|
|
755
|
+
const CUSTOM_CONTEXT_MODEL_DEFAULTS = Object.freeze({
|
|
756
|
+
"gpt-5.4": 272e3,
|
|
757
|
+
"gpt-5.4-mini": 272e3,
|
|
758
|
+
"gpt-5.5": 272e3,
|
|
759
|
+
"gpt-5.6": 272e3
|
|
760
|
+
});
|
|
761
|
+
const normalizeContextMode = (value) => [
|
|
762
|
+
"standard",
|
|
763
|
+
"extended",
|
|
764
|
+
"custom"
|
|
765
|
+
].includes(value) ? value : DEFAULT_CONTEXT_MODE;
|
|
766
|
+
const normalizeCustomContextWindow = (value, maximum = MAX_CUSTOM_CONTEXT_WINDOW) => {
|
|
767
|
+
if (!Number.isInteger(value)) return DEFAULT_CUSTOM_CONTEXT_WINDOW;
|
|
768
|
+
return Math.min(Math.max(value, MIN_CUSTOM_CONTEXT_WINDOW), maximum);
|
|
769
|
+
};
|
|
770
|
+
const customContextModelKey = (modelId) => modelId?.startsWith("gpt-5.6-") ? "gpt-5.6" : modelId;
|
|
771
|
+
function contextModelGroups(models) {
|
|
772
|
+
const groups = /* @__PURE__ */ new Map();
|
|
773
|
+
for (const model of models ?? []) {
|
|
774
|
+
if (model?.id === "gpt-5.3-codex-spark") {
|
|
775
|
+
groups.set(model.id, {
|
|
776
|
+
key: model.id,
|
|
777
|
+
label: model.name ?? model.id,
|
|
778
|
+
maximum: 128e3,
|
|
779
|
+
fixed: true
|
|
780
|
+
});
|
|
781
|
+
continue;
|
|
782
|
+
}
|
|
783
|
+
const key = customContextModelKey(model?.id);
|
|
784
|
+
if (!Object.hasOwn(CUSTOM_CONTEXT_MODEL_FIELDS, key)) continue;
|
|
785
|
+
if (key !== "gpt-5.6") {
|
|
786
|
+
groups.set(key, {
|
|
787
|
+
key,
|
|
788
|
+
label: model.name ?? model.id,
|
|
789
|
+
maximum: CUSTOM_CONTEXT_MODEL_CAPS[key]
|
|
790
|
+
});
|
|
791
|
+
continue;
|
|
792
|
+
}
|
|
793
|
+
const variant = String(model.name ?? model.id).replace(/^GPT-5\.6[ -]/iu, "");
|
|
794
|
+
const current = groups.get(key);
|
|
795
|
+
groups.set(key, {
|
|
796
|
+
key,
|
|
797
|
+
label: `GPT-5.6 ${current === void 0 ? variant : `${current.label.replace(/^GPT-5\.6 /u, "")} / ${variant}`}`,
|
|
798
|
+
maximum: CUSTOM_CONTEXT_MODEL_CAPS[key]
|
|
799
|
+
});
|
|
800
|
+
}
|
|
801
|
+
return [...groups.values()];
|
|
802
|
+
}
|
|
640
803
|
const normalizeQuickQuotaMode = (value, legacyVisible = false) => [
|
|
641
804
|
"off",
|
|
642
805
|
"percent",
|
|
@@ -658,7 +821,15 @@ const FAST_SERVICE_TIER = "priority";
|
|
|
658
821
|
* persistence, headers, transport, and model behavior remain owned by the
|
|
659
822
|
* original provider.
|
|
660
823
|
*/
|
|
661
|
-
|
|
824
|
+
const EXTENDED_CONTEXT_WINDOWS = Object.freeze({
|
|
825
|
+
"gpt-5.4": 1e6,
|
|
826
|
+
"gpt-5.4-mini": 4e5,
|
|
827
|
+
"gpt-5.5": 1e6,
|
|
828
|
+
"gpt-5.6-luna": 1e6,
|
|
829
|
+
"gpt-5.6-sol": 1e6,
|
|
830
|
+
"gpt-5.6-terra": 1e6
|
|
831
|
+
});
|
|
832
|
+
function openaiCodexSubscriptionProvider({ resolveSpeedMode = () => void 0, resolveContextMode = () => void 0, resolveCustomContextWindow = () => void 0, runNetwork = (_area, operation) => operation() } = {}) {
|
|
662
833
|
const provider = createOpenAICodexProvider();
|
|
663
834
|
const requestToken = Object.freeze({
|
|
664
835
|
name: "DSH-managed Codex OAuth request token",
|
|
@@ -689,19 +860,49 @@ function openaiCodexSubscriptionProvider({ resolveSpeedMode = () => void 0 } = {
|
|
|
689
860
|
}
|
|
690
861
|
};
|
|
691
862
|
};
|
|
863
|
+
const getModels = () => provider.getModels().map((model) => {
|
|
864
|
+
const maximum = EXTENDED_CONTEXT_WINDOWS[model.id];
|
|
865
|
+
const mode = resolveContextMode();
|
|
866
|
+
if (maximum === void 0 || !["extended", "custom"].includes(mode)) return model;
|
|
867
|
+
if (mode === "extended") return {
|
|
868
|
+
...model,
|
|
869
|
+
contextWindow: Math.max(model.contextWindow, maximum)
|
|
870
|
+
};
|
|
871
|
+
const requested = normalizeCustomContextWindow(resolveCustomContextWindow(customContextModelKey(model.id)), maximum);
|
|
872
|
+
return {
|
|
873
|
+
...model,
|
|
874
|
+
contextWindow: requested
|
|
875
|
+
};
|
|
876
|
+
});
|
|
877
|
+
const networkIterable = (factory) => {
|
|
878
|
+
let iterator;
|
|
879
|
+
const getIterator = () => iterator ??= factory()[Symbol.asyncIterator]();
|
|
880
|
+
return {
|
|
881
|
+
[Symbol.asyncIterator]() {
|
|
882
|
+
return this;
|
|
883
|
+
},
|
|
884
|
+
next: (value) => runNetwork("model", () => getIterator().next(value)),
|
|
885
|
+
return: (value) => runNetwork("model", () => getIterator().return?.(value) ?? Promise.resolve({
|
|
886
|
+
done: true,
|
|
887
|
+
value
|
|
888
|
+
})),
|
|
889
|
+
throw: (error) => runNetwork("model", () => getIterator().throw?.(error) ?? Promise.reject(error))
|
|
890
|
+
};
|
|
891
|
+
};
|
|
692
892
|
return Object.freeze({
|
|
693
893
|
...provider,
|
|
694
894
|
auth: Object.freeze({
|
|
695
895
|
...provider.auth,
|
|
696
896
|
apiKey: requestToken
|
|
697
897
|
}),
|
|
698
|
-
|
|
699
|
-
|
|
898
|
+
getModels,
|
|
899
|
+
stream: (model, context, options) => networkIterable(() => provider.stream(model, context, withSpeed(model, options))),
|
|
900
|
+
streamSimple: (model, context, options) => networkIterable(() => provider.streamSimple(model, context, withSpeed(model, options)))
|
|
700
901
|
});
|
|
701
902
|
}
|
|
702
903
|
//#endregion
|
|
703
904
|
//#region src/version.js
|
|
704
|
-
const PACKAGE_VERSION = "1.
|
|
905
|
+
const PACKAGE_VERSION = "1.9.0";
|
|
705
906
|
const USER_AGENT = `dsh-codex-subscription/${PACKAGE_VERSION}`;
|
|
706
907
|
//#endregion
|
|
707
908
|
//#region src/codex-search.js
|
|
@@ -1094,8 +1295,55 @@ function createCodexImageTool(options) {
|
|
|
1094
1295
|
}
|
|
1095
1296
|
//#endregion
|
|
1096
1297
|
//#region src/diagnostics.js
|
|
1298
|
+
const requestAreas = /* @__PURE__ */ new Set([
|
|
1299
|
+
"login",
|
|
1300
|
+
"model",
|
|
1301
|
+
"quota",
|
|
1302
|
+
"quota-reset",
|
|
1303
|
+
"search",
|
|
1304
|
+
"image"
|
|
1305
|
+
]);
|
|
1306
|
+
const statuses = /* @__PURE__ */ new Set(["ok", "failed"]);
|
|
1307
|
+
const stages = /* @__PURE__ */ new Set(["transport", "http"]);
|
|
1308
|
+
const codes = /* @__PURE__ */ new Set([
|
|
1309
|
+
"timeout",
|
|
1310
|
+
"dns",
|
|
1311
|
+
"tls",
|
|
1312
|
+
"connection",
|
|
1313
|
+
"network",
|
|
1314
|
+
"http-error"
|
|
1315
|
+
]);
|
|
1316
|
+
const routes = /* @__PURE__ */ new Set([
|
|
1317
|
+
"direct",
|
|
1318
|
+
"environment",
|
|
1319
|
+
"system",
|
|
1320
|
+
"bypass"
|
|
1321
|
+
]);
|
|
1322
|
+
const elapsedBuckets = /* @__PURE__ */ new Set([
|
|
1323
|
+
"under-1s",
|
|
1324
|
+
"1-5s",
|
|
1325
|
+
"5-15s",
|
|
1326
|
+
"over-15s"
|
|
1327
|
+
]);
|
|
1328
|
+
function safeRequests(network) {
|
|
1329
|
+
const raw = network?.snapshot?.() ?? {};
|
|
1330
|
+
const result = {};
|
|
1331
|
+
for (const [area, value] of Object.entries(raw)) {
|
|
1332
|
+
if (!requestAreas.has(area) || value === null || typeof value !== "object") continue;
|
|
1333
|
+
if (!statuses.has(value.status) || !routes.has(value.route) || !elapsedBuckets.has(value.elapsed)) continue;
|
|
1334
|
+
result[area] = {
|
|
1335
|
+
status: value.status,
|
|
1336
|
+
...stages.has(value.stage) ? { stage: value.stage } : {},
|
|
1337
|
+
...codes.has(value.code) ? { code: value.code } : {},
|
|
1338
|
+
...Number.isInteger(value.httpStatus) && value.httpStatus >= 100 && value.httpStatus <= 599 ? { httpStatus: value.httpStatus } : {},
|
|
1339
|
+
route: value.route,
|
|
1340
|
+
elapsed: value.elapsed
|
|
1341
|
+
};
|
|
1342
|
+
}
|
|
1343
|
+
return result;
|
|
1344
|
+
}
|
|
1097
1345
|
/** Build a support report that deliberately excludes OAuth and account metadata. */
|
|
1098
|
-
async function createSubscriptionDiagnostics({ auth, preferences, login = { phase: "idle" } }) {
|
|
1346
|
+
async function createSubscriptionDiagnostics({ auth, preferences, login = { phase: "idle" }, network }) {
|
|
1099
1347
|
let account = { status: "unknown" };
|
|
1100
1348
|
const issues = [];
|
|
1101
1349
|
try {
|
|
@@ -1103,8 +1351,9 @@ async function createSubscriptionDiagnostics({ auth, preferences, login = { phas
|
|
|
1103
1351
|
} catch {
|
|
1104
1352
|
issues.push({ code: "account-status-unavailable" });
|
|
1105
1353
|
}
|
|
1354
|
+
const preference = preferences.status();
|
|
1106
1355
|
return {
|
|
1107
|
-
schemaVersion:
|
|
1356
|
+
schemaVersion: 3,
|
|
1108
1357
|
package: "dsh-codex-subscription",
|
|
1109
1358
|
version: PACKAGE_VERSION,
|
|
1110
1359
|
runtime: {
|
|
@@ -1114,23 +1363,14 @@ async function createSubscriptionDiagnostics({ auth, preferences, login = { phas
|
|
|
1114
1363
|
},
|
|
1115
1364
|
account,
|
|
1116
1365
|
login,
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
},
|
|
1125
|
-
capabilities: {
|
|
1126
|
-
models: true,
|
|
1127
|
-
quota: true,
|
|
1128
|
-
search: true,
|
|
1129
|
-
imageGeneration: true,
|
|
1130
|
-
composerQuota: true,
|
|
1131
|
-
speedMode: true
|
|
1366
|
+
requests: safeRequests(network),
|
|
1367
|
+
configuration: {
|
|
1368
|
+
contextMode: preference.contextMode,
|
|
1369
|
+
quickQuotaMode: preference.quickQuotaMode,
|
|
1370
|
+
searchProvider: preference.searchProvider,
|
|
1371
|
+
speedMode: preference.speedMode,
|
|
1372
|
+
writable: preference.writable === true
|
|
1132
1373
|
},
|
|
1133
|
-
configuration: preferences.status(),
|
|
1134
1374
|
issues
|
|
1135
1375
|
};
|
|
1136
1376
|
}
|
|
@@ -1575,6 +1815,23 @@ function createSubscriptionRpcHandler({ authHandler, usageReader, resetCreditSer
|
|
|
1575
1815
|
if (!["standard", "fast"].includes(payload["speedMode"])) return publicError("internal", "Invalid speed mode preference");
|
|
1576
1816
|
patch[SPEED_MODE_FIELD] = payload[SPEED_MODE_FIELD];
|
|
1577
1817
|
}
|
|
1818
|
+
if (Object.hasOwn(payload ?? {}, "contextMode")) {
|
|
1819
|
+
if (![
|
|
1820
|
+
"standard",
|
|
1821
|
+
"extended",
|
|
1822
|
+
"custom"
|
|
1823
|
+
].includes(payload["contextMode"])) return publicError("internal", "Invalid context mode preference");
|
|
1824
|
+
patch[CONTEXT_MODE_FIELD] = payload[CONTEXT_MODE_FIELD];
|
|
1825
|
+
}
|
|
1826
|
+
if (Object.hasOwn(payload ?? {}, "customContextWindow")) {
|
|
1827
|
+
if (normalizeCustomContextWindow(payload["customContextWindow"]) !== payload["customContextWindow"]) return publicError("internal", "Invalid custom context window");
|
|
1828
|
+
patch[CUSTOM_CONTEXT_WINDOW_FIELD] = payload[CUSTOM_CONTEXT_WINDOW_FIELD];
|
|
1829
|
+
}
|
|
1830
|
+
for (const [modelKey, field] of Object.entries(CUSTOM_CONTEXT_MODEL_FIELDS)) {
|
|
1831
|
+
if (!Object.hasOwn(payload ?? {}, field)) continue;
|
|
1832
|
+
if (normalizeCustomContextWindow(payload[field], CUSTOM_CONTEXT_MODEL_CAPS[modelKey]) !== payload[field]) return publicError("internal", "Invalid custom model context window");
|
|
1833
|
+
patch[field] = payload[field];
|
|
1834
|
+
}
|
|
1578
1835
|
if (Object.keys(patch).length === 0) return publicError("internal", "Invalid preference update");
|
|
1579
1836
|
await preferences.update(patch);
|
|
1580
1837
|
}
|
|
@@ -1663,20 +1920,40 @@ function apply(ctx) {
|
|
|
1663
1920
|
]),
|
|
1664
1921
|
[LEGACY_QUICK_QUOTA_FIELD]: z.boolean(),
|
|
1665
1922
|
[SEARCH_PROVIDER_FIELD]: z.union(["dsh", SEARCH_PROVIDER_CODEX]).default("dsh"),
|
|
1666
|
-
[SPEED_MODE_FIELD]: z.union([SPEED_MODE_STANDARD, SPEED_MODE_FAST]).default(DEFAULT_SPEED_MODE)
|
|
1923
|
+
[SPEED_MODE_FIELD]: z.union([SPEED_MODE_STANDARD, SPEED_MODE_FAST]).default(DEFAULT_SPEED_MODE),
|
|
1924
|
+
[CONTEXT_MODE_FIELD]: z.union([
|
|
1925
|
+
CONTEXT_MODE_STANDARD,
|
|
1926
|
+
CONTEXT_MODE_EXTENDED,
|
|
1927
|
+
CONTEXT_MODE_CUSTOM
|
|
1928
|
+
]).default(DEFAULT_CONTEXT_MODE),
|
|
1929
|
+
[CUSTOM_CONTEXT_WINDOW_FIELD]: z.number().step(1).min(128e3).max(1e6).default(DEFAULT_CUSTOM_CONTEXT_WINDOW),
|
|
1930
|
+
...Object.fromEntries(Object.entries(CUSTOM_CONTEXT_MODEL_FIELDS).map(([modelKey, field]) => [field, z.number().step(1).min(128e3).max(CUSTOM_CONTEXT_MODEL_CAPS[modelKey]).default(CUSTOM_CONTEXT_MODEL_DEFAULTS[modelKey])]))
|
|
1667
1931
|
}));
|
|
1668
1932
|
const searchProvider = createSearchProviderSwitcher(ctx.loader);
|
|
1933
|
+
const network = createCodexNetworkTransport();
|
|
1934
|
+
const provider = openaiCodexSubscriptionProvider({
|
|
1935
|
+
resolveSpeedMode: () => settings.get()[SPEED_MODE_FIELD],
|
|
1936
|
+
resolveContextMode: () => normalizeContextMode(settings.get()[CONTEXT_MODE_FIELD]),
|
|
1937
|
+
resolveCustomContextWindow: (modelKey) => {
|
|
1938
|
+
const field = CUSTOM_CONTEXT_MODEL_FIELDS[modelKey];
|
|
1939
|
+
return normalizeCustomContextWindow(settings.get()[field] ?? CUSTOM_CONTEXT_MODEL_DEFAULTS[modelKey], CUSTOM_CONTEXT_MODEL_CAPS[modelKey]);
|
|
1940
|
+
},
|
|
1941
|
+
runNetwork: network.run
|
|
1942
|
+
});
|
|
1669
1943
|
const preferences = {
|
|
1670
1944
|
status: () => ({
|
|
1671
1945
|
[QUICK_QUOTA_MODE_FIELD]: normalizeQuickQuotaMode(settings.get()[QUICK_QUOTA_MODE_FIELD], settings.get()[LEGACY_QUICK_QUOTA_FIELD]),
|
|
1672
1946
|
[SEARCH_PROVIDER_FIELD]: settings.get()[SEARCH_PROVIDER_FIELD],
|
|
1673
1947
|
[SPEED_MODE_FIELD]: settings.get()[SPEED_MODE_FIELD],
|
|
1948
|
+
[CONTEXT_MODE_FIELD]: normalizeContextMode(settings.get()[CONTEXT_MODE_FIELD]),
|
|
1949
|
+
[CUSTOM_CONTEXT_WINDOW_FIELD]: normalizeCustomContextWindow(settings.get()[CUSTOM_CONTEXT_WINDOW_FIELD]),
|
|
1950
|
+
...Object.fromEntries(Object.entries(CUSTOM_CONTEXT_MODEL_FIELDS).map(([modelKey, field]) => [field, normalizeCustomContextWindow(settings.get()[field] ?? CUSTOM_CONTEXT_MODEL_DEFAULTS[modelKey], CUSTOM_CONTEXT_MODEL_CAPS[modelKey])])),
|
|
1951
|
+
contextModels: contextModelGroups(provider.getModels()),
|
|
1674
1952
|
writable: ctx.settings.writable
|
|
1675
1953
|
}),
|
|
1676
1954
|
update: (patch) => settings.update(patch)
|
|
1677
1955
|
};
|
|
1678
1956
|
const store = new DshOAuthCredentialStore(ctx.credentials, CREDENTIAL_REF, [LEGACY_CREDENTIAL_REF]);
|
|
1679
|
-
const provider = openaiCodexSubscriptionProvider({ resolveSpeedMode: () => settings.get()[SPEED_MODE_FIELD] });
|
|
1680
1957
|
const authModels = createModels({ credentials: store });
|
|
1681
1958
|
authModels.setProvider(provider);
|
|
1682
1959
|
const profile = Object.freeze({
|
|
@@ -1691,7 +1968,16 @@ function apply(ctx) {
|
|
|
1691
1968
|
cacheRetention: "short",
|
|
1692
1969
|
transport: "sse"
|
|
1693
1970
|
});
|
|
1694
|
-
|
|
1971
|
+
let profileKey;
|
|
1972
|
+
let profileSnapshot;
|
|
1973
|
+
const profiles = () => {
|
|
1974
|
+
const key = [normalizeContextMode(settings.get()[CONTEXT_MODE_FIELD]), ...Object.values(CUSTOM_CONTEXT_MODEL_FIELDS).map((field) => settings.get()[field])].join(":");
|
|
1975
|
+
if (key !== profileKey) {
|
|
1976
|
+
profileKey = key;
|
|
1977
|
+
profileSnapshot = /* @__PURE__ */ new Map([[PROVIDER, profile]]);
|
|
1978
|
+
}
|
|
1979
|
+
return profileSnapshot;
|
|
1980
|
+
};
|
|
1695
1981
|
const resolveAuth = () => authModels.getAuth(PROVIDER);
|
|
1696
1982
|
const adapterAuth = Object.freeze({
|
|
1697
1983
|
credentials: store,
|
|
@@ -1703,10 +1989,11 @@ function apply(ctx) {
|
|
|
1703
1989
|
ctx.tools.register(createCodexImageTool({
|
|
1704
1990
|
getAuth: resolveAuth,
|
|
1705
1991
|
readCredential: (options) => store.read(PROVIDER, options),
|
|
1706
|
-
attachments: ctx.attachments
|
|
1992
|
+
attachments: ctx.attachments,
|
|
1993
|
+
fetch: (input, init) => network.fetch("image", input, init)
|
|
1707
1994
|
}));
|
|
1708
1995
|
const adapter = new PiAiAdapter({
|
|
1709
|
-
profiles
|
|
1996
|
+
profiles,
|
|
1710
1997
|
resolveApiKey: async () => {
|
|
1711
1998
|
let resolved;
|
|
1712
1999
|
try {
|
|
@@ -1729,7 +2016,8 @@ function apply(ctx) {
|
|
|
1729
2016
|
const request = currentAgent()?.session.requestContext?.();
|
|
1730
2017
|
return request?.provider === PROVIDER ? request.model : void 0;
|
|
1731
2018
|
},
|
|
1732
|
-
resolveSessionId: () => currentAgent()?.session.id
|
|
2019
|
+
resolveSessionId: () => currentAgent()?.session.id,
|
|
2020
|
+
fetch: (input, init) => network.fetch("search", input, init)
|
|
1733
2021
|
}));
|
|
1734
2022
|
ctx.effect(() => {
|
|
1735
2023
|
const select = async (value) => {
|
|
@@ -1742,16 +2030,18 @@ function apply(ctx) {
|
|
|
1742
2030
|
select(settings.get());
|
|
1743
2031
|
return settings.watch(select);
|
|
1744
2032
|
}, "codex-subscription: search provider selection");
|
|
1745
|
-
const auth = createCodexAuthService(authModels, store, { runLogin:
|
|
2033
|
+
const auth = createCodexAuthService(authModels, store, { runLogin: (operation) => network.run("login", operation) });
|
|
1746
2034
|
const coordinator = new CodexLoginCoordinator(auth);
|
|
1747
2035
|
const usageReader = createCodexUsageReader({
|
|
1748
2036
|
getAuth: resolveAuth,
|
|
1749
|
-
readCredential: (options) => store.read(PROVIDER, options)
|
|
2037
|
+
readCredential: (options) => store.read(PROVIDER, options),
|
|
2038
|
+
fetch: (input, init) => network.fetch("quota", input, init)
|
|
1750
2039
|
});
|
|
1751
2040
|
const resetCreditService = createCodexResetCreditService({
|
|
1752
2041
|
getAuth: resolveAuth,
|
|
1753
2042
|
readCredential: (options) => store.read(PROVIDER, options),
|
|
1754
|
-
usageReader
|
|
2043
|
+
usageReader,
|
|
2044
|
+
fetch: (input, init) => network.fetch("quota-reset", input, init)
|
|
1755
2045
|
});
|
|
1756
2046
|
const handler = createSubscriptionRpcHandler({
|
|
1757
2047
|
authHandler: createCodexRpcHandler(coordinator, { openExternal: openCodexAuthUrl }),
|
|
@@ -1761,10 +2051,11 @@ function apply(ctx) {
|
|
|
1761
2051
|
diagnosticsReader: () => createSubscriptionDiagnostics({
|
|
1762
2052
|
auth,
|
|
1763
2053
|
preferences,
|
|
1764
|
-
login: coordinator.supportState()
|
|
2054
|
+
login: coordinator.supportState(),
|
|
2055
|
+
network
|
|
1765
2056
|
})
|
|
1766
2057
|
});
|
|
1767
2058
|
ctx.effect(() => ctx.connection.rpc.handle(CHANNEL, handler, { authority: "loopback" }), "codex-subscription: loopback account RPC");
|
|
1768
2059
|
}
|
|
1769
2060
|
//#endregion
|
|
1770
|
-
export { CODEX_IMAGE_GENERATION_URL, CODEX_IMAGE_TOOL_NAME, CODEX_RESET_CONSUME_URL, CODEX_RESET_CREDITS_URL, CODEX_USAGE_URL, CodexLoginCoordinator, DshOAuthCredentialStore, apply, assertCodexAuthUrl, commandForCodexAuthUrl, createCodexAuthService, createCodexImageTool, createCodexResetCreditService, createCodexRpcHandler, createCodexUsageReader, createSearchProviderSwitcher, createSubscriptionDiagnostics, createSubscriptionRpcHandler, decodeCodexPng, inject, name, openCodexAuthUrl, parseCodexUsage };
|
|
2061
|
+
export { CODEX_IMAGE_GENERATION_URL, CODEX_IMAGE_TOOL_NAME, CODEX_RESET_CONSUME_URL, CODEX_RESET_CREDITS_URL, CODEX_USAGE_URL, CodexLoginCoordinator, DshOAuthCredentialStore, apply, assertCodexAuthUrl, commandForCodexAuthUrl, createCodexAuthService, createCodexImageTool, createCodexResetCreditService, createCodexRpcHandler, createCodexUsageReader, 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": "1.
|
|
3
|
+
"version": "1.9.0",
|
|
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",
|