dsh-codex-subscription 2.1.1-beta.1 → 2.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.en.md CHANGED
@@ -130,10 +130,9 @@ Restart DSH manually after installation, then:
130
130
  - Optional percentage, progress bar, or Beta runway estimate for the selected Codex model (off by default);
131
131
  - Standard or Fast mode for supported Codex models directly in the composer;
132
132
  - 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;
133
- - 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;
133
+ - 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, and authorization timestamps;
134
134
  - Visible errors when subscription routing is unavailable, with no silent paid fallback.
135
135
 
136
- 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.
137
136
 
138
137
  ### GPT-6 Astra context
139
138
 
@@ -249,8 +248,8 @@ see the [OpenAI Codex Speed documentation](https://learn.chatgpt.com/docs/agent-
249
248
 
250
249
  Opt in under **Advanced & diagnostics**. SSE and DSH subtasks remain the defaults:
251
250
 
252
- - **WebSocket** reuses connections and eligible context transfers through your existing proxy. Failed handshakes can fall back to SSE; interrupted responses surface an error without automatic replay. Applies to the next request, does not expand context limits, and is not guaranteed to be faster.
253
- - **Codex independent subtasks** reuse your subscription login and the official DSH Codex runtime, without a separate login or CLI setup. They follow the current subscription model and workspace permissions; other model sessions use Luna low. Shared-context subtasks remain with DSH.
251
+ - **WebSocket** reuses connections and eligible context transfers. Failed handshakes can fall back to SSE; interrupted responses surface an error without automatic replay. Applies to the next request, does not expand context limits, and is not guaranteed to be faster.
252
+ - **Codex independent subtasks** reuse your subscription login and the official DSH Codex runtime, without a separate login or CLI setup. They inherit the current subscription model and workspace permissions by default. Enable DSH subtask model selection, configure allowed models and start a new session to specify the child model and reasoning effort in chat. Non-subscription sessions must explicitly select a subscription model. Shared-context subtasks remain with DSH.
254
253
 
255
254
  ## Update and uninstall
256
255
 
@@ -296,7 +295,7 @@ npx -y @deepseek-ai/dsh@0.1.5-rc.1 plugin --profile web remove dsh-codex-subscri
296
295
  - **`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.5-rc.1 ...` command above;
297
296
  - **More than one DSH exists:** run the standard command from the intended DSH environment so that product selects the corresponding profile;
298
297
  - **Setup still fails:** confirm the command is running in the intended DSH environment. Do not delete the profile or change the system PATH to force an install.
299
- - **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.
298
+ - **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, raw responses, and full logs. Paste it into the required diagnostics field; never attach sign-in URLs, authorization codes, or browser callback addresses.
300
299
 
301
300
  The ChatGPT Codex backend and DSH can change independently. This community project is not affiliated with or endorsed by DeepSeek or OpenAI.
302
301
 
package/README.md CHANGED
@@ -131,10 +131,9 @@ dsh --profile web --dump-config
131
131
  - 输入框可用百分比、进度条或可选的 Beta 续航预测显示当前 Codex 模型的剩余额度(默认关闭);
132
132
  - 输入框可为支持的 Codex 模型切换标准或高速模式;
133
133
  - 上下文窗口提供标准、扩展和逐模型自定义;自定义直接填写完整 Token 数值,并在已审核的模型容量内交给 DSH 原生 Agent 压缩策略处理;
134
- - 设置页可生成并复制无敏感信息的支持诊断,并直接打开反馈入口;报告包含有限的请求阶段、HTTP/网络分类、耗时区间和路由来源类型,但不包含 OAuth 凭据、账号标识、代理地址或授权时间;
134
+ - 设置页可生成并复制无敏感信息的支持诊断,并直接打开反馈入口;报告包含有限的请求阶段、HTTP/网络分类、耗时区间和路由来源类型,但不包含 OAuth 凭据、账号标识或授权时间;
135
135
  - 订阅路由不可用时明确报错,不会静默切换到其他付费路由。
136
136
 
137
- 对于 OpenAI 与 ChatGPT 官方请求,插件可以沿用进程环境或操作系统中已有的 HTTPS 代理。插件本身不提供代理、转发服务、节点列表,也不会修改系统代理设置。
138
137
 
139
138
  ### GPT-6 Astra 上下文
140
139
 
@@ -248,8 +247,8 @@ ChatGPT 返回可用重置卡时,设置页会把每张卡分别显示为紧凑
248
247
 
249
248
  在 **高级与诊断** 中按需开启,默认仍使用 SSE 和 DSH 子任务:
250
249
 
251
- - **WebSocket**:复用连接和可复用的上下文传输,沿用现有代理;握手失败可回退 SSE,已开始的响应中断会报错,不自动重放。下次请求生效,不增加模型上下文容量,也不保证更快。
252
- - **Codex 独立子任务**:复用订阅登录和官方 DSH Codex 运行时,无需另行登录或配置 CLI。跟随当前订阅模型及工作区权限;其他模型会话使用 Luna low。共享上下文的子任务仍交给 DSH。
250
+ - **WebSocket**:复用连接和可复用的上下文传输;握手失败可回退 SSE,已开始的响应中断会报错,不自动重放。下次请求生效,不增加模型上下文容量,也不保证更快。
251
+ - **Codex 独立子任务**:复用订阅登录和官方 DSH Codex 运行时,无需另行登录或配置 CLI。默认继承当前订阅模型及工作区权限。开启 DSH 子任务模型选择、配置允许模型并新建会话后,可在聊天中指定子任务模型与推理档位;非订阅会话需明确选择订阅模型。共享上下文的子任务仍交给 DSH。
253
252
 
254
253
  ## 更新与卸载
255
254
 
@@ -295,7 +294,7 @@ npx -y @deepseek-ai/dsh@0.1.5-rc.1 plugin --profile web remove dsh-codex-subscri
295
294
  - **`dsh` 无法识别**:官方 npm 方式本来就不会创建全局 `dsh` 命令,请使用上面的完整 `npx -y @deepseek-ai/dsh@0.1.5-rc.1 ...` 命令;
296
295
  - **电脑上有多个 DSH**:请从目标 DSH 环境运行标准命令,由该产品自身选择对应 profile;
297
296
  - **安装仍然失败**:确认命令是在目标 DSH 环境中运行,不要删除 profile 或随意修改系统 PATH。
298
- - **需要提交问题**:在设置页底部生成“支持诊断”,然后打开[使用问题表单](https://github.com/WSL043/dsh-codex-subscription/issues/new?template=install-problem.yml)。报告包含系统/运行时、有限的登录阶段和安全的请求失败分类,但不含凭据、账号标识、代理地址、原始响应或完整日志;请粘贴到必填诊断栏,且不要附上登录链接、授权码或浏览器回调地址。
297
+ - **需要提交问题**:在设置页底部生成“支持诊断”,然后打开[使用问题表单](https://github.com/WSL043/dsh-codex-subscription/issues/new?template=install-problem.yml)。报告包含系统/运行时、有限的登录阶段和安全的请求失败分类,但不含凭据、账号标识、原始响应或完整日志;请粘贴到必填诊断栏,且不要附上登录链接、授权码或浏览器回调地址。
299
298
 
300
299
  ## 边界与支持
301
300
 
@@ -6,6 +6,7 @@
6
6
  ],
7
7
  "previews": [
8
8
  "0.1.5-alpha.1",
9
- "0.1.5-alpha.2"
9
+ "0.1.5-alpha.2",
10
+ "0.1.6-alpha.1"
10
11
  ]
11
12
  }
package/lib/client.js CHANGED
@@ -105,6 +105,65 @@ window.__ModuleLoader__.load({
105
105
  context.fillStyle = context.strokeStyle;
106
106
  }
107
107
  //#endregion
108
+ //#region src/sketch-text.js
109
+ const cache = /* @__PURE__ */ new WeakMap();
110
+ function layoutSketchText(stroke, context, width, height) {
111
+ const saved = cache.get(stroke);
112
+ if (saved?.width === width && saved?.height === height) return saved.layout;
113
+ const [a, b] = stroke.points;
114
+ const x = Math.min(a.x, b.x) * width, y = Math.min(a.y, b.y) * height;
115
+ const w = Math.abs(b.x - a.x) * width, h = Math.abs(b.y - a.y) * height;
116
+ const wrap = (size) => {
117
+ context.font = `${size}px system-ui, sans-serif`;
118
+ const lines = [];
119
+ for (const paragraph of stroke.text.split("\n")) {
120
+ let line = "";
121
+ for (const char of paragraph) {
122
+ if (line && context.measureText(line + char).width > w) {
123
+ lines.push(line);
124
+ line = "";
125
+ }
126
+ line += char;
127
+ }
128
+ lines.push(line);
129
+ }
130
+ return lines;
131
+ };
132
+ let size = stroke.width, lines = wrap(size);
133
+ if (lines.length * size * 1.2 > h || lines.some((line) => context.measureText(line).width > w)) {
134
+ let low = 0, high = size;
135
+ for (let i = 0; i < 14; i++) {
136
+ const mid = (low + high) / 2, candidate = wrap(mid);
137
+ if (candidate.length * mid * 1.2 <= h && candidate.every((line) => context.measureText(line).width <= w)) low = mid;
138
+ else high = mid;
139
+ }
140
+ size = low;
141
+ lines = wrap(size);
142
+ }
143
+ const layout = {
144
+ x,
145
+ y,
146
+ size,
147
+ lines
148
+ };
149
+ cache.set(stroke, {
150
+ width,
151
+ height,
152
+ layout
153
+ });
154
+ return layout;
155
+ }
156
+ function newTextBounds(point) {
157
+ const a = {
158
+ x: Math.min(point.x, .65),
159
+ y: Math.min(point.y, .85)
160
+ };
161
+ return [a, {
162
+ x: a.x + .35,
163
+ y: a.y + .15
164
+ }];
165
+ }
166
+ //#endregion
108
167
  //#region src/sketch-document.js
109
168
  const SKETCH_SIZE = 1024;
110
169
  const MAX_SKETCH_STROKES = 2e3;
@@ -134,11 +193,10 @@ window.__ModuleLoader__.load({
134
193
  context.beginPath();
135
194
  const last = stroke.points.at(-1);
136
195
  if (stroke.shape === "text") {
137
- const x = Math.min(first.x, last.x) * size, y = Math.min(first.y, last.y) * height, w = Math.abs(last.x - first.x) * size, h = Math.abs(last.y - first.y) * height;
138
- const lines = stroke.text.split("\n"), fontSize = Math.min(stroke.width, h / Math.max(1, lines.length) / 1.2);
196
+ const { x, y, lines, size: fontSize } = layoutSketchText(stroke, context, size, height);
139
197
  context.font = `${fontSize}px system-ui, sans-serif`;
140
198
  context.textBaseline = "top";
141
- lines.forEach((line, i) => context.fillText(line, x, y + i * fontSize * 1.2, w));
199
+ lines.forEach((line, i) => context.fillText(line, x, y + i * fontSize * 1.2));
142
200
  } else if (stroke.shape === "arrow") {
143
201
  const x = last.x * size, y = last.y * height, a = Math.atan2(y - first.y * height, x - first.x * size), head = Math.min(Math.hypot(x - first.x * size, y - first.y * height) * .4, Math.max(12, stroke.width * 3));
144
202
  context.moveTo(first.x * size, first.y * height);
@@ -1372,8 +1430,8 @@ window.__ModuleLoader__.load({
1372
1430
  scaleX: Math.max(.001, point.x - box.x) / Math.max(.001, box.width),
1373
1431
  scaleY: Math.max(.001, point.y - box.y) / Math.max(.001, box.height)
1374
1432
  }) : transformObject(gesture.object, {
1375
- dx: point.x - gesture.start.x,
1376
- dy: point.y - gesture.start.y
1433
+ dx: Math.max(-box.x, Math.min(1 - box.x - box.width, point.x - gesture.start.x)),
1434
+ dy: Math.max(-box.y, Math.min(1 - box.y - box.height, point.y - gesture.start.y))
1377
1435
  });
1378
1436
  doc = {
1379
1437
  ...doc,
@@ -1585,10 +1643,47 @@ window.__ModuleLoader__.load({
1585
1643
  bitmap.close();
1586
1644
  }
1587
1645
  }
1646
+ //#endregion
1647
+ //#region src/sketch-presets.js
1648
+ const SKETCH_PRESETS = [
1649
+ "triangle",
1650
+ "diamond",
1651
+ "star"
1652
+ ];
1653
+ function expandSketchPreset(command) {
1654
+ if (!SKETCH_PRESETS.includes(command.shape)) return command;
1655
+ const points = command.points;
1656
+ if (!Array.isArray(points) || points.length !== 2 || points.some((p) => !p || ![p.x, p.y].every((v) => Number.isFinite(v) && v >= 0 && v <= 1))) throw Error("Shape preset requires two normalized bounding-box corners");
1657
+ const [a, b] = points, x = Math.min(a.x, b.x), y = Math.min(a.y, b.y);
1658
+ const w = Math.abs(a.x - b.x), h = Math.abs(a.y - b.y);
1659
+ if (!w || !h) throw Error("Shape preset requires a non-empty box");
1660
+ const vertices = command.shape === "triangle" ? [
1661
+ [.5, 0],
1662
+ [1, 1],
1663
+ [0, 1]
1664
+ ] : command.shape === "diamond" ? [
1665
+ [.5, 0],
1666
+ [1, .5],
1667
+ [.5, 1],
1668
+ [0, .5]
1669
+ ] : Array.from({ length: 10 }, (_, i) => {
1670
+ const angle = i * Math.PI / 5 - Math.PI / 2, radius = i % 2 ? .22 : .5;
1671
+ return [.5 + Math.cos(angle) * radius, .5 + Math.sin(angle) * radius];
1672
+ });
1673
+ return {
1674
+ ...command,
1675
+ shape: "polygon",
1676
+ points: vertices.map(([u, v]) => ({
1677
+ x: x + u * w,
1678
+ y: y + v * h
1679
+ }))
1680
+ };
1681
+ }
1588
1682
  const SKETCH_COMMAND_HELP = {
1589
1683
  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.",
1590
1684
  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.",
1591
1685
  commands: {
1686
+ preset: "triangle/diamond/star: {op:\"stroke\",id:\"badge\",shape:\"star\",points:[{x:0.1,y:0.1},{x:0.3,y:0.3}],color:\"#ffcc00\",fill:true}. Two opposite box corners; stored as editable polygon. Inspect objectId for one object without repeating full help.",
1592
1687
  stroke: "{op:\"stroke\",layer:1,shape:\"pen|line|arrow|text|rectangle|circle|polygon|bezier\",color:\"#rrggbb\",width:2,opacity:1,fill:false,points:[{x:0.1,y:0.1},...]}",
1593
1688
  layer: "Add: {op:\"layer\",action:\"add\",value:\"name\"}; optional id is the NEW unique integer ID, otherwise allocated automatically. after is the existing insertion anchor, defaults to active layer. Other actions: {op:\"layer\",action:\"select|rename|visible|duplicate|up|down|delete|clear\",id:1,value:\"name\"}; id targets an existing layer.",
1594
1689
  curve: "Prefer {op:\"stroke\",shape:\"bezier\",start:{x:0,y:0},segments:[{control1:{x:0.2,y:0},control2:{x:0.8,y:1},end:{x:1,y:1}}],color:\"#123456\"}. Each segment has exactly two controls and an endpoint; no point counting required. Legacy points arrays still accepted. Do not provide both forms.",
@@ -1606,8 +1701,9 @@ window.__ModuleLoader__.load({
1606
1701
  function applySketchCommands(source, commands) {
1607
1702
  if (!Array.isArray(commands) || !commands.length || commands.length > 256) throw Error("Expected 1–256 commands");
1608
1703
  let doc = identifyObjects(source);
1609
- for (const command of commands) {
1704
+ for (let command of commands) {
1610
1705
  if (!command || typeof command !== "object") throw Error("Invalid command");
1706
+ if (command.op === "stroke") command = expandSketchPreset(command);
1611
1707
  if (command.op === "resize") {
1612
1708
  doc = resizeSketch(doc, command.ratio);
1613
1709
  continue;
@@ -1779,12 +1875,12 @@ window.__ModuleLoader__.load({
1779
1875
  return {
1780
1876
  ...current,
1781
1877
  protocolVersion: 2,
1782
- objects: objects.slice(offset, offset + 50),
1878
+ objects: request.objectId ? [] : objects.slice(offset, offset + 50),
1783
1879
  objectCount: objects.length,
1784
- ...offset + 50 < objects.length ? { nextOffset: offset + 50 } : {},
1880
+ ...!request.objectId && offset + 50 < objects.length ? { nextOffset: offset + 50 } : {},
1785
1881
  ...request.objectId ? { object: adapter.object?.(request.objectId, request.layer) } : {},
1786
1882
  recentRequests: [...completed.values()].slice(-8).map((entry) => entry.receipt),
1787
- help: SKETCH_COMMAND_HELP
1883
+ ...!request.objectId && offset === 0 ? { help: SKETCH_COMMAND_HELP } : {}
1788
1884
  };
1789
1885
  }
1790
1886
  if (request.documentId !== current.documentId) throw Error("Document changed; inspect again");
@@ -3735,6 +3831,12 @@ window.__ModuleLoader__.load({
3735
3831
  width: SKETCH_SIZE,
3736
3832
  height: SKETCH_SIZE,
3737
3833
  "aria-label": t("sketchTitle"),
3834
+ onDoubleClick: () => {
3835
+ if (!busy && !agentRun.current?.locked && tool === "select" && selected?.shape === "text") setTextEdit({
3836
+ selection,
3837
+ value: selected.text
3838
+ });
3839
+ },
3738
3840
  onPointerDown: (event) => {
3739
3841
  if (busy || !enabled || active.current) return;
3740
3842
  if (navigation.down(event)) return;
@@ -3928,10 +4030,7 @@ window.__ModuleLoader__.load({
3928
4030
  try {
3929
4031
  if (textEdit.selection) editObject({ text: textEdit.value });
3930
4032
  else {
3931
- const a = textEdit.point, b = {
3932
- x: Math.min(1, a.x + .35),
3933
- y: Math.min(1, a.y + .15)
3934
- }, id = crypto.randomUUID();
4033
+ const [a, b] = newTextBounds(textEdit.point), id = crypto.randomUUID();
3935
4034
  const next = applySketchCommands(doc.current, [{
3936
4035
  op: "stroke",
3937
4036
  id,
@@ -3960,6 +4059,18 @@ window.__ModuleLoader__.load({
3960
4059
  autoFocus: true,
3961
4060
  "aria-label": t("sketchText"),
3962
4061
  maxLength: 500,
4062
+ onKeyDown: (event) => {
4063
+ if (event.nativeEvent.isComposing) return;
4064
+ if (event.key === "Escape") {
4065
+ event.preventDefault();
4066
+ event.stopPropagation();
4067
+ setTextEdit(null);
4068
+ }
4069
+ if (event.key === "Enter" && (event.ctrlKey || event.metaKey)) {
4070
+ event.preventDefault();
4071
+ event.currentTarget.form.requestSubmit();
4072
+ }
4073
+ },
3963
4074
  value: textEdit.value,
3964
4075
  onChange: (e) => setTextEdit({
3965
4076
  ...textEdit,
@@ -4351,13 +4462,17 @@ window.__ModuleLoader__.load({
4351
4462
  //#endregion
4352
4463
  //#region src/client-locales.js
4353
4464
  const zh = {
4465
+ compactionTitle: "云端压缩",
4466
+ compaction_dsh: "关闭",
4467
+ compaction_cloud: "开启",
4468
+ compactionHint: "实验功能,默认关闭。长上下文由 Codex 压缩后继续请求,保留 DSH 历史与原生压缩。开启时该请求使用 SSE;历史改变后重新建立压缩状态。",
4354
4469
  advancedModelSearch: "模型与搜索",
4355
4470
  subagentBackendTitle: "独立子任务",
4356
4471
  subagentBackend_dsh: "DSH",
4357
4472
  subagentBackend_codex: "Codex",
4358
4473
  connectionTitle: "连接方式",
4359
- connectionHint: "默认 SSE。WebSocket 实验性复用连接与上下文传输,跟随现有代理;连接失败可回退 SSE。下次请求生效,不扩大上下文容量。",
4360
- subagentBackendHint: "Codex 复用订阅登录,跟随当前订阅模型和工作区权限;其他模型会话使用 Luna low。共享上下文子任务仍用 DSH。",
4474
+ connectionHint: "默认 SSE。WebSocket 实验性复用连接与上下文传输;连接失败可回退 SSE。下次请求生效,不扩大上下文容量。",
4475
+ subagentBackendHint: "Codex 复用订阅登录和工作区权限;默认继承当前订阅模型。开启 DSH 子任务模型选择并新建会话后,可在聊天中指定允许的订阅模型与推理档位;非订阅会话需指定。共享上下文子任务仍用 DSH。",
4361
4476
  subagentBackendUnavailable: "当前宿主缺少子代理服务,请更新 DSH。",
4362
4477
  sketchRecovered: "已恢复未保存草稿",
4363
4478
  sketchRecoveryFailed: "恢复检查点保存失败,请手动保存或导出草稿。",
@@ -4775,13 +4890,17 @@ window.__ModuleLoader__.load({
4775
4890
  imageRemoveAnnotation: "删除标注"
4776
4891
  };
4777
4892
  const en = {
4893
+ compactionTitle: "Cloud compaction",
4894
+ compaction_dsh: "Off",
4895
+ compaction_cloud: "On",
4896
+ compactionHint: "Experimental, off by default. Codex compacts long requests while DSH history and native compaction remain available. These requests use SSE; changed history invalidates previous checkpoints.",
4778
4897
  advancedModelSearch: "Models and search",
4779
4898
  subagentBackendTitle: "Independent subtasks",
4780
4899
  subagentBackend_dsh: "DSH",
4781
4900
  subagentBackend_codex: "Codex",
4782
4901
  connectionTitle: "Connection",
4783
- connectionHint: "SSE by default. Experimental WebSocket reuses connections and context transfers, follows your proxy, and can fall back to SSE on connection failure. Applies to the next request; context limits stay the same.",
4784
- subagentBackendHint: "Codex uses your subscription login, current subscription model and workspace permissions; other model sessions use Luna low. Shared-context subtasks stay in DSH.",
4902
+ connectionHint: "SSE by default. Experimental WebSocket reuses connections and context transfers and can fall back to SSE on connection failure. Applies to the next request; context limits stay the same.",
4903
+ subagentBackendHint: "Codex reuses subscription login and workspace permissions, inheriting the current subscription model by default. Enable DSH subtask model selection and start a new session to request an allowed subscription model and reasoning effort in chat; other model sessions require an explicit selection. Shared-context subtasks stay in DSH.",
4785
4904
  subagentBackendUnavailable: "Subagent services are unavailable. Update DSH to use this option.",
4786
4905
  sketchRecovered: "Unsaved sketch recovered",
4787
4906
  sketchRecoveryFailed: "Recovery checkpoint failed. Save or export your draft.",
@@ -6567,6 +6686,7 @@ window.__ModuleLoader__.load({
6567
6686
  status: current.status,
6568
6687
  ...capabilities,
6569
6688
  connectionMode: value?.connectionMode === "websocket" ? "websocket" : "sse",
6689
+ compactionMode: value?.compactionMode === "cloud" ? "cloud" : "dsh",
6570
6690
  subagentBackend: value?.subagentBackend === "codex" ? "codex" : "dsh",
6571
6691
  subagentBackendAvailable,
6572
6692
  quickQuotaMode: normalizeQuickQuotaMode(value?.[QUICK_QUOTA_MODE_FIELD], value?.[LEGACY_QUICK_QUOTA_FIELD]),
@@ -6614,6 +6734,7 @@ window.__ModuleLoader__.load({
6614
6734
  status: "ready",
6615
6735
  value: {
6616
6736
  connectionMode: value?.connectionMode === "websocket" ? "websocket" : "sse",
6737
+ compactionMode: value?.compactionMode === "cloud" ? "cloud" : "dsh",
6617
6738
  subagentBackend: value?.subagentBackend === "codex" ? "codex" : "dsh",
6618
6739
  ...readCapabilitySettings(value),
6619
6740
  [QUICK_QUOTA_MODE_FIELD]: normalizeQuickQuotaMode(value?.[QUICK_QUOTA_MODE_FIELD], value?.[LEGACY_QUICK_QUOTA_FIELD]),
@@ -7025,7 +7146,7 @@ window.__ModuleLoader__.load({
7025
7146
  }
7026
7147
  //#endregion
7027
7148
  //#region src/version.js
7028
- const PACKAGE_VERSION = "2.1.1-beta.1";
7149
+ const PACKAGE_VERSION = "2.1.1";
7029
7150
  //#endregion
7030
7151
  //#region src/client-recovery.js
7031
7152
  async function recoveryCall(rpc, endpoint, payload = {}, timeoutMs = 1e4) {
@@ -8212,6 +8333,44 @@ window.__ModuleLoader__.load({
8212
8333
  })]
8213
8334
  })
8214
8335
  }),
8336
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("section", {
8337
+ className: "codexSubscriptionCard codexSubscriptionPreferencesCard",
8338
+ "aria-label": t("compactionTitle"),
8339
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
8340
+ className: "codexSubscriptionPreference",
8341
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
8342
+ className: "codexSubscriptionPreferenceCopy",
8343
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
8344
+ className: "codexSubscriptionPreferenceLabel",
8345
+ children: [
8346
+ t("compactionTitle"),
8347
+ " ",
8348
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("small", { children: "Beta" })
8349
+ ]
8350
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
8351
+ className: "codexSubscriptionPreferenceHint",
8352
+ children: t("compactionHint")
8353
+ })]
8354
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
8355
+ className: "codexSubscriptionQuotaModes",
8356
+ role: "radiogroup",
8357
+ "aria-label": t("compactionTitle"),
8358
+ "aria-busy": snapshot.saving || void 0,
8359
+ children: ["dsh", "cloud"].map((value) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
8360
+ className: "codexSubscriptionQuotaMode",
8361
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
8362
+ type: "radio",
8363
+ name: "codex-compaction-mode",
8364
+ checked: snapshot.compactionMode === value,
8365
+ disabled: !snapshot.writable,
8366
+ onChange: () => {
8367
+ preference.set({ compactionMode: value });
8368
+ }
8369
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t(`compaction_${value}`) })]
8370
+ }, value))
8371
+ })]
8372
+ })
8373
+ }),
8215
8374
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("section", {
8216
8375
  className: "codexSubscriptionCard codexSubscriptionPreferencesCard",
8217
8376
  "aria-label": t("subagentBackendTitle"),
package/lib/index.js CHANGED
@@ -288,6 +288,11 @@ const supportsCodexFastMode = (modelId) => typeof modelId === "string" && (/^gpt
288
288
  //#endregion
289
289
  //#region src/preference-fields.js
290
290
  const PREFERENCE_FIELDS = Object.freeze({
291
+ compactionMode: {
292
+ choices: ["dsh", "cloud"],
293
+ default: "dsh",
294
+ error: "Invalid compaction mode"
295
+ },
291
296
  connectionMode: {
292
297
  choices: ["sse", "websocket"],
293
298
  default: "sse",
@@ -530,7 +535,8 @@ async function withCodexNetwork(run, options = {}) {
530
535
  }
531
536
  const route = await proxy;
532
537
  scopedOptions.onRoute?.(route.source);
533
- return route.url === void 0 ? baseFetch(input, init) : proxyFetch(input, init, route.url);
538
+ const response = await (route.url === void 0 ? baseFetch(input, init) : proxyFetch(input, init, route.url));
539
+ return scopedOptions.transformResponse?.(response, target) ?? response;
534
540
  };
535
541
  globalThis.fetch = scopedFetch;
536
542
  }
@@ -656,6 +662,190 @@ function createSubscriptionConnection({ resolveMode = () => "sse", resolveProxy
656
662
  };
657
663
  }
658
664
  //#endregion
665
+ //#region src/subscription-compaction.js
666
+ /** Experimental SSE bridge; callers must explicitly opt in. */
667
+ const clone$2 = (value) => JSON.parse(JSON.stringify(value));
668
+ const hash = (value) => createHash("sha256").update(JSON.stringify(value)).digest("hex");
669
+ const key = "codexCompactionV1";
670
+ const historyHash = (messages) => hash(messages.map(({ source, ...message }) => ({
671
+ ...message,
672
+ source: source && {
673
+ kind: source.kind,
674
+ provider: source.provider,
675
+ model: source.model
676
+ }
677
+ })));
678
+ const MAX_BYTES = 2 * 1024 * 1024;
679
+ const MAX_AGE_MS = 10080 * 60 * 1e3;
680
+ function createCompactionBridge({ enabled = () => false, threshold = () => 1e5, accountScope, diagnostic = () => {}, now = Date.now }) {
681
+ const scope = new AsyncLocalStorage();
682
+ const wrapStream = (factory, options) => (async function* () {
683
+ if (!enabled() || options.provider !== "openai-codex") {
684
+ yield* factory(options);
685
+ return;
686
+ }
687
+ const identity = await accountScope(options);
688
+ if (!identity) throw new Error("Compaction requires a stable account identity");
689
+ const state = {
690
+ identity: hash([identity, options.model]),
691
+ original: options.messages,
692
+ blocks: [],
693
+ suffix: void 0,
694
+ completed: false
695
+ };
696
+ let messages = options.messages;
697
+ for (let i = messages.length - 1; i >= 0; i--) {
698
+ const candidate = messages[i].source?.replayState?.response?.[key];
699
+ if (!candidate) continue;
700
+ if (Number.isFinite(candidate.createdAt) && candidate.createdAt <= now() && now() - candidate.createdAt <= MAX_AGE_MS && candidate.scope === state.identity && candidate.prefix === historyHash(messages.slice(0, i)) && candidate.content === hash(messages[i].content) && Array.isArray(candidate.items) && candidate.items[0]?.type === "compaction" && typeof candidate.items[0].encrypted_content === "string" && candidate.digest === hash(candidate.items) && JSON.stringify(candidate.items).length <= MAX_BYTES) {
701
+ state.suffix = clone$2(candidate.items);
702
+ messages = [...messages.slice(0, i + 1).filter((m) => m.role === "system"), ...messages.slice(i + 1)];
703
+ }
704
+ break;
705
+ }
706
+ const iterator = scope.run(state, () => factory({
707
+ ...options,
708
+ messages
709
+ })[Symbol.asyncIterator]());
710
+ try {
711
+ while (true) {
712
+ const result = await scope.run(state, () => iterator.next());
713
+ if (result.done) break;
714
+ let event = result.value;
715
+ if (event.type === "block-end") state.blocks[event.index] = clone$2(event.block);
716
+ if (event.type === "finish") diagnostic({
717
+ completed: state.completed,
718
+ captured: state.captured?.length ?? 0,
719
+ replay: !!event.replayState
720
+ });
721
+ if (event.type === "finish" && ["stop", "tool-calls"].includes(event.reason?.kind) && !options.signal?.aborted && state.completed && state.captured?.length && event.replayState) {
722
+ const items = state.captured;
723
+ const checkpoint = {
724
+ createdAt: now(),
725
+ scope: state.identity,
726
+ prefix: historyHash(state.original),
727
+ content: hash(state.blocks.filter(Boolean)),
728
+ items,
729
+ digest: hash(items)
730
+ };
731
+ event = {
732
+ ...event,
733
+ replayState: {
734
+ ...event.replayState,
735
+ response: {
736
+ ...event.replayState.response,
737
+ [key]: checkpoint
738
+ }
739
+ }
740
+ };
741
+ }
742
+ yield event;
743
+ }
744
+ } finally {
745
+ await scope.run(state, () => iterator.return?.());
746
+ }
747
+ })();
748
+ return {
749
+ wrapAdapter(adapter) {
750
+ return new Proxy(adapter, { get(target, property) {
751
+ if (property === "stream") return (options) => wrapStream((o) => target.stream(o), options);
752
+ if (property === "prepareCall") return async (...args) => {
753
+ const call = await target.prepareCall(...args);
754
+ return {
755
+ ...call,
756
+ stream: (options) => wrapStream((o) => call.stream(o), options)
757
+ };
758
+ };
759
+ const value = Reflect.get(target, property, target);
760
+ return typeof value === "function" ? value.bind(target) : value;
761
+ } });
762
+ },
763
+ preparePayload(payload, contextWindow) {
764
+ const state = scope.getStore();
765
+ if (!state) return payload;
766
+ const configured = threshold();
767
+ if (!Number.isSafeInteger(configured) || configured < 1e3) throw new Error("Invalid compaction threshold");
768
+ const limit = Number.isFinite(contextWindow) && contextWindow >= 2e3 ? Math.min(configured, Math.floor(contextWindow / 2)) : configured;
769
+ if (!Number.isSafeInteger(limit) || limit < 1e3) throw new Error("Invalid compaction threshold");
770
+ return {
771
+ ...payload,
772
+ input: [...state.suffix ?? [], ...payload.input],
773
+ context_management: [{
774
+ type: "compaction",
775
+ compact_threshold: limit
776
+ }]
777
+ };
778
+ },
779
+ requestOptions(options) {
780
+ return scope.getStore() ? {
781
+ ...options,
782
+ transport: "sse"
783
+ } : options;
784
+ },
785
+ networkOptions(options) {
786
+ const state = scope.getStore();
787
+ if (!state) return options;
788
+ return {
789
+ ...options,
790
+ websocket: false,
791
+ transformResponse: (response, target) => {
792
+ if (target.hostname !== "chatgpt.com" || target.pathname !== "/backend-api/codex/responses" || !response.ok || !response.body) return response;
793
+ state.completed = false;
794
+ state.captured = void 0;
795
+ let buffer = "", oversized = false;
796
+ const decoder = new TextDecoder();
797
+ const observe = (line) => {
798
+ if (!line.startsWith("data:")) return;
799
+ const data = line.slice(5).trim();
800
+ if (data === "[DONE]") return;
801
+ let event;
802
+ try {
803
+ event = JSON.parse(data);
804
+ } catch {
805
+ return;
806
+ }
807
+ if (event.type === "response.output_item.done") {
808
+ if (event.item?.type === "compaction") state.captured = [clone$2(event.item)];
809
+ else if (state.captured) state.captured.push(clone$2(event.item));
810
+ if (state.captured && JSON.stringify(state.captured).length > MAX_BYTES) {
811
+ state.captured = void 0;
812
+ oversized = true;
813
+ }
814
+ }
815
+ if (event.type === "response.completed" && event.response?.status === "completed") state.completed = !oversized;
816
+ };
817
+ const stream = response.body.pipeThrough(new TransformStream({
818
+ transform(bytes, controller) {
819
+ controller.enqueue(bytes);
820
+ if (oversized) return;
821
+ buffer += decoder.decode(bytes, { stream: true });
822
+ let index;
823
+ while ((index = buffer.indexOf("\n")) >= 0) {
824
+ observe(buffer.slice(0, index).trimEnd());
825
+ buffer = buffer.slice(index + 1);
826
+ }
827
+ if (buffer.length > MAX_BYTES) {
828
+ buffer = "";
829
+ oversized = true;
830
+ state.captured = void 0;
831
+ }
832
+ },
833
+ flush() {
834
+ buffer += decoder.decode();
835
+ if (!oversized && buffer) observe(buffer.trimEnd());
836
+ }
837
+ }));
838
+ return new Response(stream, {
839
+ status: response.status,
840
+ statusText: response.statusText,
841
+ headers: response.headers
842
+ });
843
+ }
844
+ };
845
+ }
846
+ };
847
+ }
848
+ //#endregion
659
849
  //#region src/rpc-contract.js
660
850
  const RPC_ENDPOINTS = Object.freeze([
661
851
  "status",
@@ -851,16 +1041,34 @@ const MODES = /* @__PURE__ */ new Set([
851
1041
  "workspace-write",
852
1042
  "danger-full-access"
853
1043
  ]);
854
- function subagentThreadPolicy(parent, policy) {
1044
+ function subagentThreadPolicy(parent, policy, requested = {}) {
855
1045
  if (!MODES.has(policy?.mode)) throw new Error("DSH subagent sandbox policy is unavailable");
856
1046
  const selected = parent.session.requestHeader?.()?.config ?? parent.options ?? {};
857
- const subscription = selected.provider === "openai-codex" && typeof selected.model === "string";
1047
+ for (const key of Object.keys(requested)) if (![
1048
+ "provider",
1049
+ "model",
1050
+ "reasoningEffort"
1051
+ ].includes(key)) throw new Error("Unsupported Codex child option: " + key);
1052
+ if (requested.provider !== void 0 && requested.provider !== "openai-codex") throw new Error("Codex subtasks require the openai-codex provider");
1053
+ const model = requested.model ?? (selected.provider === "openai-codex" ? selected.model : void 0);
1054
+ if (typeof model !== "string" || !model.trim()) throw new Error("Select an openai-codex model for this subtask; the parent model cannot be inherited");
1055
+ const effort = requested.reasoningEffort ?? (requested.model === void 0 ? selected.reasoningEffort : void 0);
1056
+ if (effort !== void 0 && ![
1057
+ "none",
1058
+ "minimal",
1059
+ "low",
1060
+ "medium",
1061
+ "high",
1062
+ "xhigh",
1063
+ "max",
1064
+ "ultra"
1065
+ ].includes(effort)) throw new Error("Unsupported Codex reasoning effort");
858
1066
  return {
859
- model: subscription ? selected.model : "gpt-5.6-luna",
1067
+ model,
860
1068
  modelProvider: "openai",
861
1069
  approvalPolicy: "never",
862
1070
  sandbox: policy.mode,
863
- config: { model_reasoning_effort: subscription ? selected.reasoningEffort ?? "low" : "low" }
1071
+ config: effort === void 0 ? {} : { model_reasoning_effort: effort }
864
1072
  };
865
1073
  }
866
1074
  /** Reuse the official DSH process/turn provider; keep only subscription auth here. */
@@ -876,7 +1084,7 @@ function createSubscriptionSubagent({ ctx, nativeHome, resolveAuth, store, refre
876
1084
  provider: {
877
1085
  name: SUBAGENT_PROVIDER,
878
1086
  capabilities: {
879
- agentOptions: false,
1087
+ agentOptions: true,
880
1088
  outputSchema: false,
881
1089
  depthLimit: false,
882
1090
  toolFilter: false,
@@ -890,7 +1098,7 @@ function createSubscriptionSubagent({ ctx, nativeHome, resolveAuth, store, refre
890
1098
  const signal = AbortSignal.any([request.signal, controller.signal]);
891
1099
  let run;
892
1100
  try {
893
- const thread = subagentThreadPolicy(request.parent, ctx.sandboxPolicy.resolve({ session: request.parent.session }));
1101
+ const thread = subagentThreadPolicy(request.parent, ctx.sandboxPolicy.resolve({ session: request.parent.session }), request.agentOptions);
894
1102
  const getTokens = await createSubagentTokens({
895
1103
  resolveAuth,
896
1104
  store,
@@ -935,6 +1143,7 @@ function createSubscriptionSubagent({ ctx, nativeHome, resolveAuth, store, refre
935
1143
  });
936
1144
  run = await delegate.start({
937
1145
  ...request,
1146
+ agentOptions: void 0,
938
1147
  signal
939
1148
  });
940
1149
  const result = run.result.finally(() => active.delete(controller));
@@ -972,7 +1181,7 @@ function createSubagentBackendSwitcher({ entries, prepare, persist }) {
972
1181
  const convert = (config) => ({
973
1182
  ...config,
974
1183
  provider: SUBAGENT_PROVIDER,
975
- modelSelectionSettings: false,
1184
+ modelSelectionSettings: true,
976
1185
  backgroundMode: "one-shot",
977
1186
  maxDepth: "provider-managed"
978
1187
  });
@@ -1260,7 +1469,10 @@ const sketchCommandArray = {
1260
1469
  "ellipse",
1261
1470
  "polygon",
1262
1471
  "bezier",
1263
- "eraser"
1472
+ "eraser",
1473
+ "triangle",
1474
+ "diamond",
1475
+ "star"
1264
1476
  ]
1265
1477
  },
1266
1478
  ...style,
@@ -2297,7 +2509,7 @@ const FAST_SERVICE_TIER = "priority";
2297
2509
  * persistence, headers, transport, and model behavior remain owned by the
2298
2510
  * original provider.
2299
2511
  */
2300
- function openaiCodexSubscriptionProvider({ resolveSpeedMode = () => void 0, resolveOutputVerbosity = () => OUTPUT_VERBOSITY_DEFAULT, resolveContextMode = () => void 0, resolveCustomContextWindow = () => void 0, catalog, connection, runNetwork = (_area, operation) => operation() } = {}) {
2512
+ function openaiCodexSubscriptionProvider({ resolveSpeedMode = () => void 0, resolveOutputVerbosity = () => OUTPUT_VERBOSITY_DEFAULT, resolveContextMode = () => void 0, resolveCustomContextWindow = () => void 0, catalog, connection, compaction, runNetwork = (_area, operation) => operation() } = {}) {
2301
2513
  const provider = createOpenAICodexProvider();
2302
2514
  const requestToken = Object.freeze({
2303
2515
  name: "DSH-managed Codex OAuth request token",
@@ -2331,11 +2543,12 @@ function openaiCodexSubscriptionProvider({ resolveSpeedMode = () => void 0, reso
2331
2543
  } },
2332
2544
  ...fast ? { service_tier: FAST_SERVICE_TIER } : {}
2333
2545
  };
2334
- const next = await onPayload?.(preferred, requestModel);
2546
+ const managed = compaction?.preparePayload(preferred, model?.contextWindow) ?? preferred;
2547
+ const next = await onPayload?.(managed, requestModel);
2335
2548
  return {
2336
- ...next ?? preferred,
2549
+ ...next ?? managed,
2337
2550
  ...textVerbosity === void 0 ? {} : { text: {
2338
- ...(next ?? preferred).text ?? {},
2551
+ ...(next ?? managed).text ?? {},
2339
2552
  verbosity: textVerbosity
2340
2553
  } },
2341
2554
  ...fast ? { service_tier: FAST_SERVICE_TIER } : {}
@@ -2366,12 +2579,12 @@ function openaiCodexSubscriptionProvider({ resolveSpeedMode = () => void 0, reso
2366
2579
  const step = async (method, value) => {
2367
2580
  const request = await (prepared ??= connection?.prepare(options) ?? Promise.resolve({ options }));
2368
2581
  return runNetwork("model", () => {
2369
- iterator ??= factory(request.options)[Symbol.asyncIterator]();
2582
+ iterator ??= factory(compaction?.requestOptions(request.options) ?? request.options)[Symbol.asyncIterator]();
2370
2583
  return iterator[method]?.(value) ?? (method === "throw" ? Promise.reject(value) : Promise.resolve({
2371
2584
  done: true,
2372
2585
  value
2373
2586
  }));
2374
- }, request.network);
2587
+ }, compaction?.networkOptions(request.network) ?? request.network);
2375
2588
  };
2376
2589
  return {
2377
2590
  [Symbol.asyncIterator]() {
@@ -2399,7 +2612,7 @@ function openaiCodexSubscriptionProvider({ resolveSpeedMode = () => void 0, reso
2399
2612
  Object.freeze(["0.82.1", "0.85.1"]);
2400
2613
  //#endregion
2401
2614
  //#region src/version.js
2402
- const PACKAGE_VERSION = "2.1.1-beta.1";
2615
+ const PACKAGE_VERSION = "2.1.1";
2403
2616
  const USER_AGENT = `dsh-codex-subscription/${PACKAGE_VERSION}`;
2404
2617
  //#endregion
2405
2618
  //#region src/model-catalog.js
@@ -4643,7 +4856,7 @@ function apply(ctx) {
4643
4856
  ...Object.fromEntries(Object.entries(IMAGE_FEATURE_DEFAULTS).map(([key, value]) => [key, z.boolean().default(value)])),
4644
4857
  [CUSTOM_CONTEXT_OVERRIDES_FIELD]: z.dict(z.number().step(1).min(1).max(MAX_CONTEXT_BUDGET)).default({}),
4645
4858
  [SEARCH_MODE_FIELD]: z.union(SEARCH_MODES).default("live"),
4646
- [SEARCH_DOMAINS_FIELD]: z.transform(z.array(z.string()).max(20), (value) => readCapabilitySettings({ searchDomains: value }).searchDomains).default([]),
4859
+ [SEARCH_DOMAINS_FIELD]: z.transform(z.array(z.string()).max(20), normalizeSearchDomains).default([]),
4647
4860
  ...Object.fromEntries(QUOTA_THRESHOLD_FIELDS.map((key) => [key, z.number().step(1).min(1).max(100).default(20)])),
4648
4861
  [QUOTA_ALERTS_FIELD]: z.union(QUOTA_ALERT_MODES).default("important"),
4649
4862
  [LEGACY_QUICK_QUOTA_FIELD]: z.boolean(),
@@ -4672,9 +4885,18 @@ function apply(ctx) {
4672
4885
  fetch: (input, init) => network.fetch("catalog", input, init)
4673
4886
  });
4674
4887
  const connection = createSubscriptionConnection({ resolveMode: () => settings.get().connectionMode });
4888
+ const compaction = createCompactionBridge({
4889
+ enabled: () => settings.get().compactionMode === "cloud",
4890
+ accountScope: async () => {
4891
+ await resolveAuth();
4892
+ const credential = await store.read(PROVIDER);
4893
+ return credential?.type === "oauth" ? credential.accountId : void 0;
4894
+ }
4895
+ });
4675
4896
  ctx.effect(() => () => connection.dispose());
4676
4897
  const provider = openaiCodexSubscriptionProvider({
4677
4898
  connection,
4899
+ compaction,
4678
4900
  resolveSpeedMode: () => settings.get()[SPEED_MODE_FIELD],
4679
4901
  resolveOutputVerbosity: () => normalizeOutputVerbosity(settings.get()[OUTPUT_VERBOSITY_FIELD]),
4680
4902
  resolveContextMode: () => normalizeContextMode(settings.get()[CONTEXT_MODE_FIELD]),
@@ -4690,6 +4912,7 @@ function apply(ctx) {
4690
4912
  });
4691
4913
  const preferences = {
4692
4914
  status: () => ({
4915
+ compactionMode: settings.get().compactionMode ?? "dsh",
4693
4916
  connectionMode: settings.get().connectionMode ?? "sse",
4694
4917
  subagentBackend: settings.get().subagentBackend ?? "dsh",
4695
4918
  subagentBackendAvailable: subagentBackend !== void 0,
@@ -4826,7 +5049,7 @@ function apply(ctx) {
4826
5049
  auth: adapterAuth,
4827
5050
  resolveAttachments: () => ctx.get?.("attachments")
4828
5051
  });
4829
- ctx.llm.registerAdapter([PROVIDER], adapter);
5052
+ ctx.llm.registerAdapter([PROVIDER], compaction.wrapAdapter(adapter));
4830
5053
  const currentAgent = () => ctx.get?.("agents")?.currentInitiator?.();
4831
5054
  const codexSearch = createCodexSearchProvider({
4832
5055
  resolvePreferences: () => readCapabilitySettings(settings.get()),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-codex-subscription",
3
- "version": "2.1.1-beta.1",
3
+ "version": "2.1.1",
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",
@@ -74,21 +74,21 @@
74
74
  },
75
75
  "peerDependencies": {
76
76
  "@deepseek-ai/cordis": "4.0.1 || 4.0.2",
77
- "@deepseek-ai/dsh-api-remotes": "0.1.2-rc.1 || 0.1.5-rc.1 || 0.1.5-alpha.1 || 0.1.5-alpha.2",
78
- "@deepseek-ai/dsh-client-connection": "0.1.2-rc.1 || 0.1.5-rc.1 || 0.1.5-alpha.1 || 0.1.5-alpha.2",
79
- "@deepseek-ai/dsh-client-locale": "0.1.2-rc.1 || 0.1.5-rc.1 || 0.1.5-alpha.1 || 0.1.5-alpha.2",
80
- "@deepseek-ai/dsh-client-ui-conversation": "0.1.2-rc.1 || 0.1.5-rc.1 || 0.1.5-alpha.1 || 0.1.5-alpha.2",
81
- "@deepseek-ai/dsh-client-ui-model-selection": "0.1.2-rc.1 || 0.1.5-rc.1 || 0.1.5-alpha.1 || 0.1.5-alpha.2",
82
- "@deepseek-ai/dsh-client-ui-primitives": "0.1.2-rc.1 || 0.1.5-rc.1 || 0.1.5-alpha.1 || 0.1.5-alpha.2",
83
- "@deepseek-ai/dsh-client-ui-settings": "0.1.2-rc.1 || 0.1.5-rc.1 || 0.1.5-alpha.1 || 0.1.5-alpha.2",
84
- "@deepseek-ai/dsh-client-ui-slots": "0.1.2-rc.1 || 0.1.5-rc.1 || 0.1.5-alpha.1 || 0.1.5-alpha.2",
85
- "@deepseek-ai/dsh-client-ui-tool": "0.1.2-rc.1 || 0.1.5-rc.1 || 0.1.5-alpha.1 || 0.1.5-alpha.2",
86
- "@deepseek-ai/dsh-credentials": "0.1.2-rc.1 || 0.1.5-rc.1 || 0.1.5-alpha.1 || 0.1.5-alpha.2",
87
- "@deepseek-ai/dsh-llm": "0.1.2-rc.1 || 0.1.5-rc.1 || 0.1.5-alpha.1 || 0.1.5-alpha.2",
88
- "@deepseek-ai/dsh-llm-pi-ai": "0.1.2-rc.1 || 0.1.5-rc.1 || 0.1.5-alpha.1 || 0.1.5-alpha.2",
89
- "@deepseek-ai/dsh-settings": "0.1.2-rc.1 || 0.1.5-rc.1 || 0.1.5-alpha.1 || 0.1.5-alpha.2",
90
- "@deepseek-ai/dsh-tools": "0.1.2-rc.1 || 0.1.5-rc.1 || 0.1.5-alpha.1 || 0.1.5-alpha.2",
91
- "@deepseek-ai/dsh-web": "0.1.2-rc.1 || 0.1.5-rc.1 || 0.1.5-alpha.1 || 0.1.5-alpha.2",
77
+ "@deepseek-ai/dsh-api-remotes": "0.1.2-rc.1 || 0.1.5-alpha.1 || 0.1.5-alpha.2 || 0.1.5-rc.1 || 0.1.6-alpha.1",
78
+ "@deepseek-ai/dsh-client-connection": "0.1.2-rc.1 || 0.1.5-alpha.1 || 0.1.5-alpha.2 || 0.1.5-rc.1 || 0.1.6-alpha.1",
79
+ "@deepseek-ai/dsh-client-locale": "0.1.2-rc.1 || 0.1.5-alpha.1 || 0.1.5-alpha.2 || 0.1.5-rc.1 || 0.1.6-alpha.1",
80
+ "@deepseek-ai/dsh-client-ui-conversation": "0.1.2-rc.1 || 0.1.5-alpha.1 || 0.1.5-alpha.2 || 0.1.5-rc.1 || 0.1.6-alpha.1",
81
+ "@deepseek-ai/dsh-client-ui-model-selection": "0.1.2-rc.1 || 0.1.5-alpha.1 || 0.1.5-alpha.2 || 0.1.5-rc.1 || 0.1.6-alpha.1",
82
+ "@deepseek-ai/dsh-client-ui-primitives": "0.1.2-rc.1 || 0.1.5-alpha.1 || 0.1.5-alpha.2 || 0.1.5-rc.1 || 0.1.6-alpha.1",
83
+ "@deepseek-ai/dsh-client-ui-settings": "0.1.2-rc.1 || 0.1.5-alpha.1 || 0.1.5-alpha.2 || 0.1.5-rc.1 || 0.1.6-alpha.1",
84
+ "@deepseek-ai/dsh-client-ui-slots": "0.1.2-rc.1 || 0.1.5-alpha.1 || 0.1.5-alpha.2 || 0.1.5-rc.1 || 0.1.6-alpha.1",
85
+ "@deepseek-ai/dsh-client-ui-tool": "0.1.2-rc.1 || 0.1.5-alpha.1 || 0.1.5-alpha.2 || 0.1.5-rc.1 || 0.1.6-alpha.1",
86
+ "@deepseek-ai/dsh-credentials": "0.1.2-rc.1 || 0.1.5-alpha.1 || 0.1.5-alpha.2 || 0.1.5-rc.1 || 0.1.6-alpha.1",
87
+ "@deepseek-ai/dsh-llm": "0.1.2-rc.1 || 0.1.5-alpha.1 || 0.1.5-alpha.2 || 0.1.5-rc.1 || 0.1.6-alpha.1",
88
+ "@deepseek-ai/dsh-llm-pi-ai": "0.1.2-rc.1 || 0.1.5-alpha.1 || 0.1.5-alpha.2 || 0.1.5-rc.1 || 0.1.6-alpha.1",
89
+ "@deepseek-ai/dsh-settings": "0.1.2-rc.1 || 0.1.5-alpha.1 || 0.1.5-alpha.2 || 0.1.5-rc.1 || 0.1.6-alpha.1",
90
+ "@deepseek-ai/dsh-tools": "0.1.2-rc.1 || 0.1.5-alpha.1 || 0.1.5-alpha.2 || 0.1.5-rc.1 || 0.1.6-alpha.1",
91
+ "@deepseek-ai/dsh-web": "0.1.2-rc.1 || 0.1.5-alpha.1 || 0.1.5-alpha.2 || 0.1.5-rc.1 || 0.1.6-alpha.1",
92
92
  "@deepseek-ai/schemastery": "3.18.1 || ^3.18.2",
93
93
  "@earendil-works/pi-ai": "0.82.1 || 0.85.1",
94
94
  "react": "^18.2.0",