dsh-packycode-api 1.4.5 → 1.4.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,29 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.4.7
4
+
5
+ - **Images move to GPT Image 2.6.** PackyCode added `gpt-image-2.6-flare` and `gpt-image-2.6-sunburst`: on 2026-11-05 `/api/pricing` lists them in the `image` group beside the 2.5 pair, with the `image-generation` endpoint. They replace `gpt-image-2.5-flare` and `gpt-image-2.5-sunburst` in the settings card, the `packycode_image_generate` tool and `scripts/image-check.mjs`, whose default is now 2.6 Sunburst. OpenAI's [image generation guide](https://developers.openai.com/api/docs/guides/image-generation) gives "GPT Image 2.6 and 2.5 Sunburst and Flare" one quality list, `low` to `max`, and its [Sunburst](https://developers.openai.com/api/docs/models/gpt-image-2.6-sunburst) and [Flare](https://developers.openai.com/api/docs/models/gpt-image-2.6-flare) pages list `/v1/images/edits`, so both keep `auto`, `low`, `medium`, `high`, `xhigh` and `max`, and requests, sizes and edits are sent as before. `gpt-image-2` is unchanged.
6
+ - **A saved 2.5 choice keeps working.** Taking the 2.5 ids out of the Config schema would make the plugin's Config fail to parse for anyone who had picked one (`expected "gpt-image-2" | … but got "gpt-image-2.5-sunburst"`). The schema keeps them as hidden values, and the image preference reads each as the 2.6 engine of the same name with the saved quality (`RETIRED_IMAGE_MODELS` in `src/image-models.js`). The card and the tool offer only the 2.6 pair and refuse a 2.5 id; images that earlier sessions made with 2.5 still show.
7
+ - Validation, 2026-11-05:
8
+ - **Offline:** 558 tests (new: a saved `gpt-image-2.5-flare` or `gpt-image-2.5-sunburst` parses through the plugin Config, stays out of the offered choices, and reads as its 2.6 successor with `max` or `xhigh` kept; a quality-only change on such a setting is written without touching the saved model; a 2.5 id is refused on write; an unknown id still fails the Config; the existing generation, settings and card tests now run on the 2.6 ids), both rebuilt bundles and the versioned tarball. The suite also passed on Node 22.23.1.
9
+ - **Live, `scripts/image-check.mjs` with the image key:** 15 requests to `https://cf.api.fan`, all 1024×1024 PNGs with no retry. 2.6 Flare and 2.6 Sunburst each passed generation and editing at `low`, `xhigh` and `max`, and every response reported the requested quality. `gpt-image-2` passed generation at `low`, and 2.6 Sunburst at `auto` came back reported as `low`. Generate/edit times were 6/9 s at `low`, 14/15 s at `xhigh` and 24/26 s at `max` on Flare, and 13/17 s, 51/64 s and 96/97 s on Sunburst. The edits turned the blue teapot orange and kept the composition. Responses carry no `model` field, so this shows the ids are served on this key, not which engine the gateway runs. Transparent backgrounds, masks, other sizes and the full chat flow in the desktop app were not checked.
10
+ - **The live check sends its images at each model's least effort.** `scripts/live-check.mjs --with-vision` sent its two plain-color images at `high` under the script's 2,048-token output cap, and Hy4 sometimes reasoned past the cap: of 20 direct requests on 2026-11-04, 9 came back incomplete after 55–72 s with no answer, so the check failed though the image had been read. The image turns now run at the least effort the model offers (pi-ai's `getSupportedThinkingLevels`, the rule DSH's titles follow): `off` for DeepSeek Flash, GPT-6.1 Terra and Hy4, `low` for the rest. The text turns keep `high`. A turn the cap cuts off is now reported as such instead of "no finish".
11
+ - Validation, 2026-11-04:
12
+ - **Offline:** 557 tests, both rebuilt bundles (unchanged) and the versioned tarball.
13
+ - **Live, `--model <id> --with-vision` with the test key:** Hy4 named both images at `off` in 3 of 3 runs, in about 15 s per run with the text turn at `high`. DeepSeek Flash and GPT-6.1 Terra at `off`, and GPT-6.1 Sol, GPT-6 Astra, GPT-5.6 Sol and Grok 4.7 at `low`, named both. Gemini 3.8 Flash ran past the script's 90 s timeout in each of 3 runs, once already on the text turn at `high`. Sent through the built route outside the script, 12 requests per effort over two rounds, it named the color in 11 of 12 at both `low` and `high`, with one 120 s stall at each and answers taking up to 93 s at `low` and 75 s at `high`: the `gemini-slb` channel's latency, not the effort. The Claude models (the CLI route on this key) and Gemini 4 Argon (outside the key's groups) were not run.
14
+
15
+ ## 1.4.6
16
+
17
+ - **Hy4 joins the catalog.** PackyCode added the `hunyuan-officially` group (腾讯混元官方渠道) and Tencent's `hy4` model: on 2026-11-04 `/api/pricing` lists `hy4` in that group alone, with `anthropic`, `openai` and `openai-response` endpoints. `hy4` takes the Responses route: `openai-responses` at `https://cf.api.fan/v1`, text and image input, 1,024,000 context and 64,000 output. TokenHub's [Hunyuan guide](https://cloud.tencent.com/document/product/1823/132252) gives Hy4 a 1024K context, of which at most 960K input, 64K output and image input on all three protocols, and its [model overview](https://cloud.tencent.com/document/product/1823/130079) marks Hy4's Responses support as native rather than converted. The gateway does not check `max_output_tokens` (1,000,000 was accepted), so the output ceiling is the documented 64K, read as 64,000 like DeepSeek's 384K. Hy4 sits after Grok 4.7 in the picker, and the settings panel counts it on a Hunyuan line under each key.
18
+ - **Its efforts are `off` and `high`.** TokenHub's [deep thinking page](https://cloud.tencent.com/document/product/1823/131208) lists `reasoning_effort` `high` and `no_think` for Hy4, with thinking on by default. `high` is sent as is, and `off` sends `reasoning.effort: "no_think"`, the value Hy4's own row names. pi-ai's default `none` answered the same, and TokenHub's [Responses compatibility page](https://cloud.tencent.com/document/product/1823/133813) accepts both. The gateway also accepts `minimal`, `low`, `medium`, `xhigh` and `max`, but Hy4 does not document them and did not answer them differently from `high`, so they are not offered. Session titles run on Hy4 itself at `off`, the least effort it offers.
19
+ - **Reasoning, caching and tools.** Reasoning streams as `response.reasoning_summary_text.delta` into `summary_text` items, which pi-ai shows as thinking and replays unchanged with the turn's tool calls and in later turns, as TokenHub's [preserved thinking](https://cloud.tencent.com/document/product/1823/133534) asks for Hy4. The prefix cache hits as often without `prompt_cache_key` as with it, so Hy4 is sent none, like DeepSeek. Tools go without `strict`: TokenHub documents a function tool's `strict` as defaulting to true, but Hy4 filled DSH's optional sandbox fields about as rarely with `strict` omitted as with `strict: false`.
20
+ - **Hy4 is told who made it.** DSH's system prompt opens with "You are an AI agent powered by DeepSeek Harness." and "You are a coding agent powered by the hy4 model.": it names the harness, and the model only by its id. In the desktop app Hy4 then said it was a DeepSeek model, and asked whether it was Hunyuan, it denied it and claimed `hy` did not stand for Hunyuan. Every Hy4 request now ends its leading instructions with one sentence (`src/hy4-identity.js`): the hy4 model is Hy4 from Tencent Hunyuan, reached through PackyCode, and DeepSeek Harness is the agent app it runs in, not its model or its maker. DSH's text stays as written, and the sentence never changes, so the cached prefix stays stable; a caller's own payload hook still sees the final body. No other model's request changes: under DSH's prompt with their own ids, GPT-6.1 Sol and Terra named OpenAI, Grok 4.7 xAI, Gemini 3.8 Flash Google, and DeepSeek Flash and V4 Pro DeepSeek.
21
+ - Validation, 2026-11-04:
22
+ - **Offline:** 557 tests (new: Hy4's catalog entry, efforts, wire dialect and resolved metadata; `high` sent without the cache key or `strict`; `off` sent as `no_think`; summary reasoning streamed as thinking and replayed unchanged with its tool call and in the next user turn; undocumented efforts refused through the route before any request; Hy4 titling its own sessions at `off`; an image reaching Responses through DSH's `LlmRuntime`; pricing and coverage for `hunyuan-officially`; the identity sentence appended once after DSH's instructions, or sent alone without them, ahead of a caller's payload hook, and absent from the other models' requests), both rebuilt bundles and the versioned tarball. The suite also passed on Node 22.23.1.
23
+ - **Live, direct to `/v1/responses` with the test key (`hunyuan-officially` among its groups):** with no effort the gateway echoed `high`. `no_think` and `none` both answered with no reasoning item and 4 output tokens, at 52 prompt tokens against 49 for every thinking level, and a made-up effort was refused with 400. On one arithmetic problem, four requests per level all had 69 prompt tokens, and mean reasoning tokens were 4,160 at `low`, 2,917 at `medium`, 4,117 at `high`, 3,823 at `xhigh` and 3,506 at `max`, against a spread of 1,270–7,737 within the levels. With DSH's bash tool, the optional sandbox pair was filled in 1 of 14 calls with `strict` omitted, 1 of 14 with `strict: false` and 0 of 14 with `strict: true`. A prefix of about 13,000 tokens sent 8 times was cached on 4 of the 7 repeats both with and without `prompt_cache_key`.
24
+ - **Live, through the built route:** `off` sent `no_think` and answered `ok` without thinking, and `high` answered `ok` with streamed thinking; `minimal`, `low`, `medium`, `xhigh` and `max` were refused before any request. An `echo` tool call continued to `ok` 2 of 2 times at `high` and 2 of 2 at `off`, replaying the reasoning item and the `fc_` call item, and a following user turn carried every earlier reasoning item and answered with the echoed text, 4 of 4. DSH's title request at `off` came back as 整理十月发货单并标缺货. `scripts/live-check.mjs --model hy4 --with-vision` answered `ok` and named a red and a blue image. With the identity sentence in place, the efforts, 3 more `echo` continuations and the title came back the same; the vision check named both images in 1 of 3 runs, and in the other two Hy4 reasoned past the script's 2,048-token output cap at `high` on the red image and was cut off without an answer. Sent directly with the same image, 5 of 10 requests without the sentence and 4 of 10 with it ended at that cap, so the sentence is not the cause; DSH's own requests use the model's 64,000-token ceiling. In the full `scripts/live-check.mjs`, the key's groups read as reaching Hy4 and every model answered except `gemini-4-argon`: `/api/pricing` now lists Argon only in `gemini-officially`, which the test key lacks, and the gateway refused it with `分组 gemini-slb 下模型 gemini-4-argon 无可用渠道(distributor)`. That is upstream, and nothing in this change touches Gemini. Key rotation, the rejected-key classification, both auto reviewers and the RPC projections were unchanged. Not checked in the desktop app.
25
+ - **Live, Hy4's identity:** the desktop session's log showed both answers coming from `packycode / hy4` in Hy4's own reply format. Sent directly without a system prompt, Hy4 answered "我是混元,是由腾讯开发的大模型" 3 of 3 times. With DSH's system prompt it named DeepSeek Harness or no maker at all, never Tencent, in 3 of 3; after the desktop session's first answer it denied being Hunyuan 6 of 6 times; with the harness renamed it no longer claimed DeepSeek. With the sentence, sent directly with DSH's prompt, it named Tencent Hunyuan in 4 of 4 first answers, confirmed being Hunyuan in 4 of 4 follow-ups and named Tencent in 4 of 4 English answers; through the built route, 3 of 3 for each turn. The sentence did not leak into other answers: `ok` 3 of 3, a JavaScript question 3 of 3 and DSH titles 3 of 3 carried no identity talk, and a bare 你好 introduced itself as Tencent Hunyuan's Hy4 in 2 of 3. Not checked in the desktop app.
26
+
3
27
  ## 1.4.5
4
28
 
5
29
  - **Diagnostics now say how a request to PackyCode failed on the network.** An Ubuntu user running `dsh --profile web` saw model requests retried over and over: one session had 39 failed attempts in 12 steps, logged as `Request timed out.`, a later one `Connection error.`, and the balance read `fetch failed (ETIMEDOUT)` from every status host. Each attempt failed about 0.5 s after it started. `cf.api.fan` and `www.packyapi.ai` resolve to two IPv4 and two IPv6 addresses. Node tries them in turn and gives every address but the last 250 ms (`net.getDefaultAutoSelectFamilyAttemptTimeout()`). On that machine the lookup returned the IPv6 addresses but they could not be reached, so the last address failed at once, and the connection failed whenever both IPv4 handshakes took longer than 250 ms. Node's own undici reports that as an `AggregateError`, which the OpenAI SDK calls `Connection error.`. The undici 8 that DSH installs with a proxy policy rewrites it as a `ConnectTimeoutError` that still says `timeout: 10000ms`, which the SDK calls `Request timed out.`. The report kept neither the cause nor the addresses, so the two texts looked like two problems.
package/README.en.md CHANGED
@@ -31,7 +31,7 @@ The `PackyCode` model group ships with the plugin. No YAML edits and no separate
31
31
  | **Visible balance** | Settings lists each key's remaining, used, limit, reset period, and a usage bar. The composer shows the active key's remaining balance |
32
32
  | **Claude route by group** | The `cc` group only serves the official client, so Claude sessions on `cc` keys are carried out by this device's Claude Code itself, with its own system prompt and tools, while DSH shows every tool call and handles permissions, plan review and questions; `cc-sale`, `cc-expensive`, `claude-officially` and other groups use the plugin's HTTP route with DSH's own agent |
33
33
  | **Web search through PackyCode** | Optional: DSH's `web_search` searches through PackyCode, with a DeepSeek or GPT backend, for every request or for PackyCode models only |
34
- | **Image generation and editing** | Separate image keys, GPT Image 2 / 2.5 Flare / 2.5 Sunburst, model and quality settings, reference edits and original PNG storage; generation and editing verified against the gateway |
34
+ | **Image generation and editing** | Separate image keys, GPT Image 2 / 2.6 Flare / 2.6 Sunburst, model and quality settings, reference edits and original PNG storage; generation and editing verified against the gateway |
35
35
  | **Auto review on your model** | With DSH's built-in “Auto authorization review” switched on, the permission menu's Auto review can review each tool call with jev-latest or DeepSeek Flash; the rules and outcomes stay the official ones |
36
36
  | **Credentials stay on the machine** | Keys live in the DSH credential file. The browser receives labels, state, and balances only |
37
37
 
@@ -48,10 +48,10 @@ You need **DeepSeek Harness** and a **PackyCode (PackyAPI) API key**. For DSH se
48
48
  Open the desktop application's **Plugins** page, click **Add plugin**, and enter the package name **with a version** as the **package name or address**:
49
49
 
50
50
  ```text
51
- dsh-packycode-api@1.4.5
51
+ dsh-packycode-api@1.4.7
52
52
  ```
53
53
 
54
- Choose the **official** install source, then click **Install**. `1.4.5` was the latest release when this was written; the [npm page](https://www.npmjs.com/package/dsh-packycode-api) shows the current one.
54
+ Choose the **official** install source, then click **Install**. `1.4.7` was the latest release when this was written; the [npm page](https://www.npmjs.com/package/dsh-packycode-api) shows the current one.
55
55
 
56
56
  > **Always include the version.** With a bare `dsh-packycode-api`, the install prompt shows the newest version on npm, but DSH's bundled pnpm by default installs only versions published at least 24 hours ago, so you can end up several releases behind with no sign of it in the prompt. With an exact version, pnpm installs that version and adds it to the profile's `minimumReleaseAgeExclude` itself. Afterwards, check **Current version** under **Settings → PackyCode → Plugin version**.
57
57
 
@@ -65,14 +65,14 @@ Open **Settings → PackyCode**. Paste the API key under **Add a key**. A label
65
65
 
66
66
  ### 3. Select a model
67
67
 
68
- Choose a model from the `PackyCode` group. Of the twelve models, Claude runs through this device's Claude Code CLI on `cc` keys; everything else uses the plugin’s HTTP route. Your key’s groups must cover the selected model.
68
+ Choose a model from the `PackyCode` group. Of the thirteen models, Claude runs through this device's Claude Code CLI on `cc` keys; everything else uses the plugin’s HTTP route. Your key’s groups must cover the selected model.
69
69
 
70
70
  <details>
71
71
  <summary>Verify the install / other profiles / a local checkout</summary>
72
72
 
73
73
  The **Plugins** page shows the installed state and version, and is also where you enable, disable, or uninstall.
74
74
 
75
- **For non-desktop profiles only:** `dsh plugin --profile <name> add dsh-packycode-api@1.4.5`. Do not use it for `desktop` — the CLI refuses it (`profile "desktop" is managed exclusively by the Electron application`).
75
+ **For non-desktop profiles only:** `dsh plugin --profile <name> add dsh-packycode-api@1.4.7`. Do not use it for `desktop` — the CLI refuses it (`profile "desktop" is managed exclusively by the Electron application`).
76
76
 
77
77
  For a local checkout, keep the `link:` prefix: `dsh plugin --profile <name> add link:/path/to/dsh-packycode-api`. **Do not pass a bare path or `file:`** — that install copies the whole checkout, `node_modules` included, into the profile, where it then shadows the packages the DSH installation itself provides and the plugin looks uninstalled; see the FAQ. If you already installed that way, uninstall first and reinstall as above.
78
78
 
@@ -86,7 +86,7 @@ A profile without a browser can still use the model route. It just has no settin
86
86
 
87
87
  **Switch keys.** Keys are used in the order they were added. **Use this key** picks the preferred key, effective from the next turn; **Rename** changes its label (at most 60 characters, empty names are refused); **Re-enable** puts a disabled key back after a top-up or replacement.
88
88
 
89
- **See groups.** Under **Accounts and keys**, each key lists its PackyCode groups (hover for the group's description) and which models they reach: ✓ yes, ◐ partly, ✕ no. The groups come from the gateway itself (its refusal of a model id it cannot route names the token's groups, as “已选分组=[…]”, or for a single-group key as “分组 … 下模型 … 无可用渠道”; nothing is billed), matched against PackyCode's public model-group table. Check Claude group coverage per model; do not assume `cc-sale` serves all three models; GPT needs `codex` / `codex-sale`; DeepSeek needs `deepseek-officially` / `deepseek-sale`.
89
+ **See groups.** Under **Accounts and keys**, each key lists its PackyCode groups (hover for the group's description) and which models they reach: ✓ yes, ◐ partly, ✕ no. The groups come from the gateway itself (its refusal of a model id it cannot route names the token's groups, as “已选分组=[…]”, or for a single-group key as “分组 … 下模型 … 无可用渠道”; nothing is billed), matched against PackyCode's public model-group table. Check Claude group coverage per model; do not assume `cc-sale` serves all three models; GPT needs `codex` / `codex-sale`; DeepSeek needs `deepseek-officially` / `deepseek-sale`; Hy4 needs `hunyuan-officially`.
90
90
 
91
91
  **Read the balance.** Each key under **Accounts and keys** shows its own remaining, used, and limit (limit = remaining + used); an unlimited key shows **No quota limit**. Keys are not added up into a total. An API key can read only its own quota, not the PackyCode account's balance, so check the account balance in the PackyCode console. A key that could not be read says why on its own row; a key whose read failed this time but succeeded before keeps showing its last balance with the time it was read (the composer shows it as `≈US$…`) until DSH restarts. The composer shows the active key's remaining balance only while a PackyCode model is selected. **Refresh** bypasses the roughly 60-second cache. The default model host is `https://cf.api.fan` and the balance host is `https://www.packyapi.ai`; both can be changed under **Advanced: endpoints**. The old default, `https://www.packyapi.com`, is DNS-poisoned on mainland networks and answers `fetch failed` without a proxy; even when settings still name it, `.ai` is tried first.
92
92
 
@@ -161,13 +161,13 @@ Claude generates and edits images through DSH’s `packycode_image_generate`, wi
161
161
 
162
162
  Tool callers can set `model` and `quality` to `settings` to follow the saved preferences; `auto` is an explicit API quality. New images may omit `referenceImages` or pass an empty array. Explicit `operation: edit` requires valid references, and invalid real references are never discarded in favor of new-image generation.
163
163
 
164
- Image 2 accepts `auto / low / medium / high`; both 2.5 models also accept `xhigh / max`. These are Images API `quality` values, separate from text reasoning effort. There is no automatic model substitution, quality downgrade or paid retry. Each call returns one PNG; original bytes are saved under `~/.dsh/packycode-api/images/` (following `DSH_HOME` when set), alongside the chat preview. References and optional PNG masks must belong to the current session; file paths cannot replace attachment references.
164
+ Image 2 accepts `auto / low / medium / high`; both 2.6 models also accept `xhigh / max`. A saved 2.5 Flare or Sunburst setting is read as the 2.6 engine of the same name, with its quality kept. These are Images API `quality` values, separate from text reasoning effort. There is no automatic model substitution, quality downgrade or paid retry. Each call returns one PNG; original bytes are saved under `~/.dsh/packycode-api/images/` (following `DSH_HOME` when set), alongside the chat preview. References and optional PNG masks must belong to the current session; file paths cannot replace attachment references.
165
165
 
166
166
  Click a generated image to open the in-app large preview. **Download original**, immediately left of Close, opens a save-location picker for the complete preserved PNG. Cancelling is harmless; a moved or deleted original reports a retryable error instead of downloading the chat thumbnail. Saved conversations also support this as long as their original file is still on this host.
167
167
 
168
168
  After adding the image key, `node scripts/image-check.mjs --all --edit` checks all three engines and one edit. Use `--model <id> --edit` for generation and editing on a specific engine, adding `--quality xhigh` or `--quality max` to check a quality. This consumes image quota, saves outputs under `.artifacts/`, and prints only a masked key tail plus the gateway-reported model/quality.
169
169
 
170
- Live checks on 2026-10-15 passed generation and editing at `low` on all three engines. Sunburst also passed both operations at `xhigh` and `max`, with matching quality values in the responses. All 10 requests succeeded without retries and returned 1024×1024 PNGs; visual inspection confirmed the requested color edits with composition preserved. Generate/edit times were about 43/48 seconds at xhigh and 84/91 seconds at max. These are built-client gateway checks; no desktop conversation was created to verify the full chat flow in this run. See the [protocol research and gateway results](docs/research/image-api.md) for scope and evidence.
170
+ Live checks on 2026-11-05 passed generation and editing at `low`, `xhigh` and `max` on both 2.6 Flare and 2.6 Sunburst, with matching quality values in the responses; `gpt-image-2` passed generation at `low`, and the gateway reported Sunburst's `auto` as `low`. All 15 requests succeeded without retries and returned 1024×1024 PNGs; visual inspection confirmed the requested color edits with composition preserved. Generate/edit times were about 14/15 seconds at xhigh and 24/26 seconds at max on Flare, and 51/64 and 96/97 seconds on Sunburst. These are built-client gateway checks; no desktop conversation was created to verify the full chat flow in this run. See the [protocol research and gateway results](docs/research/image-api.md) for scope and evidence.
171
171
 
172
172
  ### Auto review
173
173
 
@@ -227,6 +227,7 @@ The card shows whether DSH's plugin is on, how many reviews this plugin answered
227
227
  | `gpt-6-astra` | Same | Cannot be off; `low` / `medium` / `high` / `xhigh` / `max` | Same |
228
228
  | `gpt-5.6-sol` | Same | Same | Same |
229
229
  | `grok-4.7` (Grok 4.7) | HTTP, Responses, text/image input; 500K context | Cannot be off; `low` / `medium` / `high` / `xhigh` | The Grok coverage read from the gateway in Settings |
230
+ | `hy4` (Hy4, Tencent Hunyuan) | HTTP, Responses, text/image input; 1024K context (at most 960K input), 64K output | Can be off; `high` only | `hunyuan-officially` |
230
231
  | `gemini-4-argon` (Gemini 4 Argon) | HTTP, native Gemini streaming, text/image input; 1,048,576 context, 65,536 output | Cannot be off; `low` / `medium` / `high` | `gemini-slb` |
231
232
  | `gemini-3.8-flash` (Gemini 3.8 Flash) | HTTP, native Gemini streaming, text/image input; 1,048,576 input, 65,536 output | Cannot be off; `low` / `medium` / `high` | `gemini-slb` |
232
233
  | `claude-opus-5-5` | Anthropic Messages, images and native tools: this device's Claude Code CLI as the agent for `cc` keys, HTTP otherwise | Cannot be off; `low` / `medium` / `high` / `xhigh` / `max` | Claude-group coverage reported in Settings |
@@ -237,7 +238,7 @@ A model in the list does not mean the current token group allows it. When changi
237
238
 
238
239
  `jev-latest` (TypeSafe Jev) is not in the model picker: it is a decision model that answers classification questions and cannot hold a conversation, so it only serves [Auto review](#auto-review). The plugin calls `/v1/systemone` host-side; it needs a key in the `typesafe-officially` group, and each key's Jev entry under Accounts and keys shows whether it can.
239
240
 
240
- Of the twelve models in the current catalog, all but DeepSeek V4 Pro declare text and image input. DeepSeek Flash follows the [official vision guide](https://api-docs.deepseek.com/guides/vision/); images are read through DSH's attachment service and sent with the Responses request. DeepSeek V4 Pro takes text only, per DeepSeek's [models and pricing page](https://api-docs.deepseek.com/quick_start/pricing/): DSH does not let you attach an image to it, and an image already in the session (say, one switched over from Flash) is sent as a one-line "image omitted" note. PackyCode's gateway does not refuse an image sent to V4 Pro; it drops it.
241
+ Of the thirteen models in the current catalog, all but DeepSeek V4 Pro declare text and image input. DeepSeek Flash follows the [official vision guide](https://api-docs.deepseek.com/guides/vision/); images are read through DSH's attachment service and sent with the Responses request. DeepSeek V4 Pro takes text only, per DeepSeek's [models and pricing page](https://api-docs.deepseek.com/quick_start/pricing/): DSH does not let you attach an image to it, and an image already in the session (say, one switched over from Flash) is sent as a one-line "image omitted" note. PackyCode's gateway does not refuse an image sent to V4 Pro; it drops it.
241
242
 
242
243
  Gemini capabilities and limits follow Google's model pages: [Gemini 4 Argon](https://ai.google.dev/gemini-api/docs/models/gemini-4-argon), [Gemini 3.8 Flash](https://ai.google.dev/gemini-api/docs/models/gemini-3.8-flash). Both models use the native Gemini protocol through `/v1beta/models/{model}:streamGenerateContent`, streaming text, thinking and tool calls; images are read through DSH's attachment service. Thinking levels are sent with `thinkingLevel`. Both routes use the single-stream output limit without automatic continuation beyond 65,536 tokens. Available endpoints and groups follow the [PackyAPI live model catalog](https://www.packyapi.com/api/pricing).
243
244
 
@@ -245,7 +246,9 @@ Gemini capabilities and limits follow Google's model pages: [Gemini 4 Argon](htt
245
246
 
246
247
  Grok 4.7's context and reasoning levels follow the [official guide](https://docs.x.ai/developers/grok-4-7). There is no separate text-output limit; the plugin uses the context size as its numeric output ceiling, bounded by the remaining context per request.
247
248
 
248
- Only GPT Responses requests keep `prompt_cache_key`; other Responses models omit it by default. This gateway's Grok route reports a misleading `Incorrect API key provided` error when the field is present, and DeepSeek Flash hits its prefix cache without it. GPT tool definitions also carry an explicit `strict: false`: PackyCode's GPT route treats a tool without `strict` as strict, which forces the model to fill every optional parameter (see the FAQ).
249
+ Hy4's protocols, context, output limit and image input follow Tencent Cloud TokenHub's [Hunyuan guide](https://cloud.tencent.com/document/product/1823/132252), and its effort levels follow the [deep thinking page](https://cloud.tencent.com/document/product/1823/131208): Hy4 thinks by default, and `reasoning_effort` takes only `high` and `no_think`. The plugin sends `high` as is; with effort off it sends `reasoning.effort: "no_think"`, and the answer comes back without reasoning. The gateway also accepts `low`, `medium`, `xhigh` and `max`, but Hy4's documentation does not list them, and in testing they came back with the same prompt tokens as `high` and no consistent difference in reasoning, so the plugin does not offer them. Images are read through DSH's attachment service and sent with the Responses request, as for DeepSeek Flash. Reasoning comes back as `summary_text` items; as TokenHub's [preserved thinking](https://cloud.tencent.com/document/product/1823/133534) asks, the plugin sends it back unchanged with tool continuations and in later turns. DSH's system prompt says only "powered by DeepSeek Harness" and "powered by the hy4 model", without saying whose model hy4 is, and Hy4 then calls itself a DeepSeek model and denies being Hunyuan (the other models recognize their own ids). So the plugin ends the system prompt of every Hy4 request with one sentence: hy4 is Tencent Hunyuan's Hy4, reached through PackyCode, and DeepSeek Harness is only the app it runs in. DSH's own prompt is kept as written, and other models' requests are unchanged.
250
+
251
+ Only GPT Responses requests keep `prompt_cache_key`; other Responses models omit it by default. This gateway's Grok route reports a misleading `Incorrect API key provided` error when the field is present, and DeepSeek Flash and Hy4 hit their prefix caches without it. GPT tool definitions also carry an explicit `strict: false`: PackyCode's GPT route treats a tool without `strict` as strict, which forces the model to fill every optional parameter (see the FAQ).
249
252
 
250
253
  GPT-6.1 Terra's context, output limit and effort levels follow OpenAI's [model page](https://developers.openai.com/api/docs/models/gpt-6.1-terra). It is the only GPT model whose reasoning can be off: with effort off it sends `reasoning.effort: "none"`, which the gateway passes through, and the answer comes back without reasoning. GPT-5.6 Sol's documentation lists `none` too, but through PackyCode it answers at `medium`, so it cannot be off.
251
254
 
@@ -272,9 +275,9 @@ DeepSeek Flash uses the gateway's Responses endpoint (`/api/pricing` lists `open
272
275
 
273
276
  ## Update and uninstall
274
277
 
275
- > **Upgrading from 1.3.2 or earlier:** install `dsh-packycode-api@1.4.5` on the Plugins page instead of clicking **Update plugin** in the old settings card. The old button bypasses pnpm's release-age policy: if the version it installs is less than 24 hours old, the profile refuses every other plugin install until that version is 24 hours old. After the install and a restart, the button is the fixed one, and later updates can use it.
278
+ > **Upgrading from 1.3.2 or earlier:** install `dsh-packycode-api@1.4.7` on the Plugins page instead of clicking **Update plugin** in the old settings card. The old button bypasses pnpm's release-age policy: if the version it installs is less than 24 hours old, the profile refuses every other plugin install until that version is 24 hours old. After the install and a restart, the button is the fixed one, and later updates can use it.
276
279
 
277
- **Update:** open **Settings → PackyCode** and, when a newer version is listed, click **Update plugin**. It installs that exact version into the owning profile with DSH's bundled pnpm and reads `package.json` back before reporting success. The install keeps pnpm's release-age policy instead of overriding it: by default pnpm installs the version at once and records it in the profile's `minimumReleaseAgeExclude`; under a stricter pnpm policy the button says when the update can run. The newer version is read from npm, while pnpm downloads it from the profile's own install source: right after a release that source (a regional mirror in particular) may not have it yet, and the button asks you to update again in a few minutes; when the source cannot be reached, it asks you to check the network or proxy. A local `link:` checkout does not get the button. Then quit and reopen the desktop application. A page refresh does not reload the Host. Reinstalling from the **Plugins** page works too, again with the version in the package name (for example `dsh-packycode-api@1.4.5`); without it you may get a version that is merely the newest one published at least 24 hours ago.
280
+ **Update:** open **Settings → PackyCode** and, when a newer version is listed, click **Update plugin**. It installs that exact version into the owning profile with DSH's bundled pnpm and reads `package.json` back before reporting success. The install keeps pnpm's release-age policy instead of overriding it: by default pnpm installs the version at once and records it in the profile's `minimumReleaseAgeExclude`; under a stricter pnpm policy the button says when the update can run. The newer version is read from npm, while pnpm downloads it from the profile's own install source: right after a release that source (a regional mirror in particular) may not have it yet, and the button asks you to update again in a few minutes; when the source cannot be reached, it asks you to check the network or proxy. A local `link:` checkout does not get the button. Then quit and reopen the desktop application. A page refresh does not reload the Host. Reinstalling from the **Plugins** page works too, again with the version in the package name (for example `dsh-packycode-api@1.4.7`); without it you may get a version that is merely the newest one published at least 24 hours ago.
278
281
 
279
282
  **Coming back from a local-path install, uninstall first.** An update is a `pnpm add`: it rewrites the files inside the package directory and leaves a `node_modules` that an earlier local-path install left there. That older tree keeps shadowing the packages the DSH installation provides, so the plugin row fails to load with no visible reason. **Uninstall** runs `pnpm remove`, which deletes the package directory outright — only a reinstall after that is clean. `node scripts/install-check.mjs` reports whether a profile is in that state.
280
283
 
@@ -290,7 +293,7 @@ ls ~/.dsh/profiles/desktop/node_modules/dsh-packycode-api/node_modules
290
293
 
291
294
  Output means a leftover tree: a registry install ships no `node_modules`, so this one usually comes from an earlier local-path install (`file:`, or a bare path instead of `link:`). It sits inside the profile directory, and DSH resolves a plugin's imports from inside the profile first, so the plugin gets those old copies — for example `@deepseek-ai/schemastery` 3.18.2, which has no `Schema.volatile()`, so the module throws while it is imported. When an import fails the Loader creates no fiber for that row and no client bundle is composed either, so the model route, the RPC channel, and the settings panel all stay absent.
292
295
 
293
- Recovery: **uninstall** the plugin on the **Plugins** page, **install** it again with the version in the package name (for example `dsh-packycode-api@1.4.5`), then quit and reopen the desktop application. Uninstall runs `pnpm remove` and deletes the whole package directory; reinstalling or clicking **Update** only rewrites files and keeps the leftover tree. Deleting that `node_modules` by hand and restarting works too.
296
+ Recovery: **uninstall** the plugin on the **Plugins** page, **install** it again with the version in the package name (for example `dsh-packycode-api@1.4.7`), then quit and reopen the desktop application. Uninstall runs `pnpm remove` and deletes the whole package directory; reinstalling or clicking **Update** only rewrites files and keeps the leftover tree. Deleting that `node_modules` by hand and restarting works too.
294
297
 
295
298
  **Right after a first install, every card in Settings shows `transport failure for /packycode-api/…: HTTP 405`?** The installed version is 1.1.6 or earlier, usually because only the bare package name was entered: the install prompt shows the newest version, but pnpm installs the newest one published at least 24 hours ago (see **Install the plugin**). Those older versions can register their settings channel only after DSH restarts and rebuilds its `connection` service. So right after a first install `/packycode-api` does not exist yet, requests fall through to the static page, and it answers 405; the model route and the settings panel itself load normally. From 1.1.7 on, a first install needs no restart. Check which version was installed:
296
299
 
package/README.md CHANGED
@@ -31,7 +31,7 @@
31
31
  | **余额一眼可见** | 设置页列出每个 Key 的剩余、已用、额度、重置周期和用量条;输入框右侧显示当前 Key 的剩余额度 |
32
32
  | **Claude 按分组选通道** | `cc` 分组只接受官方客户端,这些 Key 的 Claude 会话由本机 Claude Code 自己完成:它用自己的系统提示词和工具做事,DSH 显示每次工具调用,并负责授权、计划审阅和提问;`cc-sale`、`cc-expensive`、`claude-officially` 等分组走插件内 HTTP,由 DSH 自己的 agent 执行 |
33
33
  | **网页搜索可走 PackyCode** | 可选:DSH 的 `web_search` 改用 PackyCode 搜索,后端在 DeepSeek 与 GPT 之间切换;可只对 PackyCode 模型生效 |
34
- | **图片生成与编辑** | 独立图片 Key,支持 GPT Image 2 / 2.5 Flare / 2.5 Sunburst、型号与质量设置、参考图编辑和 PNG 原图保存;已通过网关生图与编辑实测 |
34
+ | **图片生成与编辑** | 独立图片 Key,支持 GPT Image 2 / 2.6 Flare / 2.6 Sunburst、型号与质量设置、参考图编辑和 PNG 原图保存;已通过网关生图与编辑实测 |
35
35
  | **自动审查可换模型** | 开启 DSH 自带的「自动授权审查」后,权限菜单里的「自动审查」可改用 jev-latest 或 DeepSeek Flash 审查每次工具调用,审查规则和处理方式保持官方原样 |
36
36
  | **凭据不离开本机** | Key 只存在 DSH 凭据文件里。浏览器只能看到备注、状态和余额,拿不到 Key |
37
37
 
@@ -48,10 +48,10 @@
48
48
  打开桌面应用的**插件**页,点击**添加插件**,在**包名或地址**中填入**带版本号**的包名:
49
49
 
50
50
  ```text
51
- dsh-packycode-api@1.4.5
51
+ dsh-packycode-api@1.4.7
52
52
  ```
53
53
 
54
- 在**安装源**中选择**官方源**,然后点击**安装**。`1.4.5` 是写这份说明时的最新版,当前最新版本号以 [npm 页面](https://www.npmjs.com/package/dsh-packycode-api) 为准。
54
+ 在**安装源**中选择**官方源**,然后点击**安装**。`1.4.7` 是写这份说明时的最新版,当前最新版本号以 [npm 页面](https://www.npmjs.com/package/dsh-packycode-api) 为准。
55
55
 
56
56
  > **一定要带版本号。** 只填 `dsh-packycode-api` 时,安装前的提示显示的是 npm 上的最新版,但 DSH 自带的 pnpm 默认只安装发布满 24 小时的版本,实际装上的可能是好几个版本之前的旧版,而安装提示里看不出这一点。填写精确版本时,pnpm 会直接安装这个版本,并自动把它加入 profile 的 `minimumReleaseAgeExclude`。装好后可以在 **设置 → PackyCode → 插件版本** 核对「当前版本」。
57
57
 
@@ -65,14 +65,14 @@ dsh-packycode-api@1.4.5
65
65
 
66
66
  ### 3. 选择模型
67
67
 
68
- 回到对话,在模型选择器里选 `PackyCode` 分组下的模型。十二个模型里,Claude 在 `cc` 分组的 Key 上由本机 Claude Code CLI 执行,其余都通过插件内 HTTP 调用;Key 的分组必须覆盖所选模型。
68
+ 回到对话,在模型选择器里选 `PackyCode` 分组下的模型。十三个模型里,Claude 在 `cc` 分组的 Key 上由本机 Claude Code CLI 执行,其余都通过插件内 HTTP 调用;Key 的分组必须覆盖所选模型。
69
69
 
70
70
  <details>
71
71
  <summary>检查安装 / 其它 profile / 本地目录</summary>
72
72
 
73
73
  桌面应用的**插件**页可以看到已安装状态与版本,也可以在那里启用、停用或卸载。
74
74
 
75
- **仅用于非 desktop profile:** `dsh plugin --profile <name> add dsh-packycode-api@1.4.5`。不要对 `desktop` 使用它 —— CLI 会直接拒绝(`profile "desktop" is managed exclusively by the Electron application`)。
75
+ **仅用于非 desktop profile:** `dsh plugin --profile <name> add dsh-packycode-api@1.4.7`。不要对 `desktop` 使用它 —— CLI 会直接拒绝(`profile "desktop" is managed exclusively by the Electron application`)。
76
76
 
77
77
  本地开发要加 `link:` 前缀:`dsh plugin --profile <name> add link:/path/to/dsh-packycode-api`。**不要直接写路径(或 `file:`)** —— 那样的安装会把整个仓库目录(连同 `node_modules`)复制进 profile,之后它会在 profile 内部挡住 DSH 自带的包,插件看起来像没装,见「常见问题」。已经那样装过的话,先卸载再按上面的方式重装。
78
78
 
@@ -86,7 +86,7 @@ dsh-packycode-api@1.4.5
86
86
 
87
87
  **换 Key。** Key 按添加顺序使用。点「切到此 Key」指定优先使用的 Key,下一轮就生效;「重命名」改备注(最多 60 字,不能为空);充值或更换后点「重新启用」。
88
88
 
89
- **看分组。** 「账户与 Key」里每个 Key 下面列出它所在的 PackyCode 分组(鼠标悬停可看分组说明),以及能用哪些模型:✓ 可用、◐ 部分可用、✕ 不可用。分组由网关自己报出(对一个不存在的模型 id 的拒绝里会写明「已选分组」,单分组的 Key 则是「分组 … 下模型 … 无可用渠道」,不产生费用),再对照 PackyCode 公开的模型分组表。Claude 的分组覆盖要按具体模型确认,不能假定 `cc-sale` 支持全部三个型号;GPT 需要 `codex` / `codex-sale`;DeepSeek 需要 `deepseek-officially` / `deepseek-sale`。
89
+ **看分组。** 「账户与 Key」里每个 Key 下面列出它所在的 PackyCode 分组(鼠标悬停可看分组说明),以及能用哪些模型:✓ 可用、◐ 部分可用、✕ 不可用。分组由网关自己报出(对一个不存在的模型 id 的拒绝里会写明「已选分组」,单分组的 Key 则是「分组 … 下模型 … 无可用渠道」,不产生费用),再对照 PackyCode 公开的模型分组表。Claude 的分组覆盖要按具体模型确认,不能假定 `cc-sale` 支持全部三个型号;GPT 需要 `codex` / `codex-sale`;DeepSeek 需要 `deepseek-officially` / `deepseek-sale`;Hy4 需要 `hunyuan-officially`。
90
90
 
91
91
  **看余额。** 「账户与 Key」里每个 Key 显示它自己的剩余、已用与额度(额度 = 剩余 + 已用),不限额的 Key 显示「不限额度」;多个 Key 不相加成合计。API Key 只能读到自己的额度,读不到 PackyCode 账号的总余额,账号余额请到 PackyCode 控制台查看。读失败的 Key 会在它那一行注明原因;某个 Key 这次读失败但之前读到过,会继续显示上次的余额并注明读取时间(输入框里显示为 `≈US$…`),重启 DSH 后才清空。输入框右侧只在选中 PackyCode 模型时显示当前 Key 的剩余额度。「刷新」会跳过约 60 秒的缓存。默认模型接口是 `https://cf.api.fan`,余额接口是 `https://www.packyapi.ai`,可在「高级:接口地址」里改。旧默认值 `https://www.packyapi.com` 在国内网络下 DNS 被污染、直连会 `fetch failed`,即使设置里保存的是它,插件也会先试 `.ai`。
92
92
 
@@ -161,13 +161,13 @@ Claude 与其它模型一样,通过 DSH 的 `packycode_image_generate` 工具
161
161
 
162
162
  工具调用可将 `model` 和 `quality` 设为 `settings` 来跟随已保存的图片设置;`auto` 是一个明确的 API 质量档位。新图可省略 `referenceImages` 或传空数组;显式指定 `operation: edit` 时必须提供有效参考图,错误的真实参考图不会被丢弃后改生成新图。
163
163
 
164
- `gpt-image-2` 的质量为 `auto / low / medium / high`;两款 2.5 另支持 `xhigh / max`。质量按 Images API 的 `quality` 原样发送,不作为文字推理强度;不会自动换型号、降档或重试付费请求。输出先采用 PNG,每次一张,聊天预览之外的原图保存在 `~/.dsh/packycode-api/images/`(设置了 `DSH_HOME` 时跟随该目录)。参考图与可选 PNG mask 必须来自当前会话;不能用路径替代附件引用。
164
+ `gpt-image-2` 的质量为 `auto / low / medium / high`;两款 2.6 另支持 `xhigh / max`。设置里原来选的 2.5 Flare / Sunburst 会按同名的 2.6 型号读取,质量不变,无需重新设置。质量按 Images API 的 `quality` 原样发送,不作为文字推理强度;不会自动换型号、降档或重试付费请求。输出先采用 PNG,每次一张,聊天预览之外的原图保存在 `~/.dsh/packycode-api/images/`(设置了 `DSH_HOME` 时跟随该目录)。参考图与可选 PNG mask 必须来自当前会话;不能用路径替代附件引用。
165
165
 
166
166
  点击生成图可在应用内查看大图,右上角关闭按钮左侧的「下载原图」可选择保存位置,另存本机保留的完整 PNG。取消保存不会报错;若原图已被移走或删除,会提示失败,不会改为下载聊天缩略图。已有会话也可使用此功能,前提是记录对应的本机原图仍存在。
167
167
 
168
168
  用户填入图片 Key 后,可运行 `node scripts/image-check.mjs --all --edit` 验证三个型号与一次编辑;用 `--model <型号> --edit` 单独验证某个型号的生图和编辑,搭配 `--quality xhigh` 或 `--quality max` 验证质量。测试会消耗图片额度,输出写入 `.artifacts/`,日志只显示 Key 的掩码尾号,并记录网关回报的型号/质量。
169
169
 
170
- 2026-10-15 实测:三个型号均通过 `low` 生图与编辑;Sunburst 额外通过 `xhigh`、`max` 生图与编辑,两档响应的 quality 均与请求一致。合计 10 次成功请求,无重试,全部返回 1024×1024 PNG;编辑正确改色并保留构图。xhigh 生成/编辑约 43/48 秒,max 约 84/91 秒。这是已构建图片 client 的网关验证;本轮未新建 DSH 对话验证完整聊天流程。完整范围和记录见[协议核查与网关实测](docs/research/image-api.md)。
170
+ 2026-11-05 实测:2.6 Flare 和 2.6 Sunburst 都通过 `low`、`xhigh`、`max` 的生图与编辑,响应回报的 quality 与请求一致;`gpt-image-2` 通过 `low` 生图,Sunburst 的 `auto` 被网关回报为 `low`。合计 15 次请求全部成功,无重试,均返回 1024×1024 PNG;编辑正确改色并保留构图。Flare 的 xhigh 生图/编辑约 14/15 秒、max 约 24/26 秒;Sunburst 的 xhigh 约 51/64 秒、max 约 96/97 秒。这是已构建图片 client 的网关验证;本轮未新建 DSH 对话验证完整聊天流程。完整范围和记录见[协议核查与网关实测](docs/research/image-api.md)。
171
171
 
172
172
  ### 自动审查
173
173
 
@@ -227,6 +227,7 @@ DSH 自带一个实验性插件「自动授权审查」,默认关闭。开启
227
227
  | `gpt-6-astra` | 同上 | 不能关;`low` / `medium` / `high` / `xhigh` / `max` | 同上 |
228
228
  | `gpt-5.6-sol` | 同上 | 同上 | 同上 |
229
229
  | `grok-4.7`(Grok 4.7) | HTTP,Responses,可带图;500k 上下文 | 不能关;`low` / `medium` / `high` / `xhigh` | 以设置页从网关读取的 Grok 分组覆盖为准 |
230
+ | `hy4`(Hy4,腾讯混元) | HTTP,Responses,可带图;1024K 上下文(输入最多 960K),64K 输出 | 可关;只有 `high` | `hunyuan-officially` |
230
231
  | `gemini-4-argon`(Gemini 4 Argon) | HTTP,Gemini 原生流式,可带图;1,048,576 上下文,65,536 输出 | 不能关;`low` / `medium` / `high` | `gemini-slb` |
231
232
  | `gemini-3.8-flash`(Gemini 3.8 Flash) | HTTP,Gemini 原生流式,可带图;1,048,576 输入,65,536 输出 | 不能关;`low` / `medium` / `high` | `gemini-slb` |
232
233
  | `claude-opus-5-5` | Anthropic Messages,可带图和原生工具:`cc` 分组由本机 Claude Code CLI 当 agent,其它分组走 HTTP | 不能关;`low` / `medium` / `high` / `xhigh` / `max` | 以设置页读取的 Claude 分组覆盖为准 |
@@ -237,7 +238,7 @@ DSH 自带一个实验性插件「自动授权审查」,默认关闭。开启
237
238
 
238
239
  `jev-latest`(TypeSafe Jev)不在模型选择器里:它是只回答分类问题的决策模型,不能对话,只用于[自动审查](#自动审查)。插件在宿主侧直接调用 `/v1/systemone`,需要 Key 在 `typesafe-officially` 分组;「账户与 Key」里每个 Key 的「Jev」一项会显示能否使用。
239
240
 
240
- 当前目录的 12 个模型中,除 DeepSeek V4 Pro 外都声明了文字和图像输入。DeepSeek Flash 的识图能力按 [官方图像理解文档](https://api-docs.deepseek.com/zh-cn/guides/vision/) 配置;图片通过 DSH 附件服务读取,再随 Responses 请求发送。DeepSeek V4 Pro 按 [官方模型与价格页](https://api-docs.deepseek.com/zh-cn/quick_start/pricing/) 只收文字:DSH 不让给它附图,会话里已有的图片(比如从 Flash 切过来的会话)会换成一行「图片已省略」的说明再发送。PackyCode 网关收到发给 V4 Pro 的图片不报错,而是直接丢掉。
241
+ 当前目录的 13 个模型中,除 DeepSeek V4 Pro 外都声明了文字和图像输入。DeepSeek Flash 的识图能力按 [官方图像理解文档](https://api-docs.deepseek.com/zh-cn/guides/vision/) 配置;图片通过 DSH 附件服务读取,再随 Responses 请求发送。DeepSeek V4 Pro 按 [官方模型与价格页](https://api-docs.deepseek.com/zh-cn/quick_start/pricing/) 只收文字:DSH 不让给它附图,会话里已有的图片(比如从 Flash 切过来的会话)会换成一行「图片已省略」的说明再发送。PackyCode 网关收到发给 V4 Pro 的图片不报错,而是直接丢掉。
241
242
 
242
243
  Gemini 的能力与限制来自 Google 官方模型页:[Gemini 4 Argon](https://ai.google.dev/gemini-api/docs/models/gemini-4-argon)、[Gemini 3.8 Flash](https://ai.google.dev/gemini-api/docs/models/gemini-3.8-flash)。两款模型统一使用 Gemini 原生协议,通过 `/v1beta/models/{model}:streamGenerateContent` 流式返回文字、思考和工具调用,图片仍由 DSH 附件服务读取。思考档位通过 `thinkingLevel` 传入。两者均使用单次流式输出上限,不执行超过 65,536 token 的自动续写。可用端点与分组以 [PackyAPI 实时模型目录](https://www.packyapi.com/api/pricing) 为准。
243
244
 
@@ -245,7 +246,9 @@ Gemini 的能力与限制来自 Google 官方模型页:[Gemini 4 Argon](https:
245
246
 
246
247
  Grok 4.7 的上下文与推理档位来自 [官方文档](https://docs.x.ai/developers/grok-4-7)。官方没有单独限制文字输出长度;插件将输出上限设为上下文大小,并按每次请求的剩余上下文收紧。
247
248
 
248
- Responses 请求只有 GPT 模型保留 `prompt_cache_key`,其他 Responses 模型默认省略。当前网关的 Grok 路由会将这个字段误报成 `Incorrect API key provided`;DeepSeek Flash 不带它也能命中前缀缓存。GPT 的工具定义还会显式带上 `strict: false`:PackyCode 的 GPT 通道把没写 `strict` 的工具当作严格模式,模型会被迫填满所有可选参数(见「常见问题」)。
249
+ Hy4 的协议、上下文、输出上限和识图能力来自腾讯云 TokenHub 的 [混元调用指南](https://cloud.tencent.com/document/product/1823/132252),推理档位来自 [深度思考](https://cloud.tencent.com/document/product/1823/131208):Hy4 默认开启思考,`reasoning_effort` 只有 `high` 和 `no_think` 两档。插件按 `high` 发送,关闭推理时发送 `reasoning.effort: "no_think"`,返回时不带思考。网关也接受 `low`、`medium`、`xhigh`、`max`,但 Hy4 的文档没有这些档位,实测时它们的提示 token 与 `high` 相同,推理长度也看不出差别,所以插件不提供。图片和 DeepSeek Flash 一样由 DSH 附件服务读取,随 Responses 请求发送。推理以 `summary_text` 条目返回;按 TokenHub [保留式思考](https://cloud.tencent.com/document/product/1823/133534) 的要求,插件把推理原样回传给工具续聊和之后的轮次。DSH 的系统提示词只写了「powered by DeepSeek Harness」和「powered by the hy4 model」,没说 hy4 是谁家的模型,hy4 会因此自称 DeepSeek 的模型、否认自己是混元(其它模型都认得出自己的模型名)。所以插件在 hy4 每个请求的系统提示词末尾补一句英文说明:hy4 是腾讯混元的 Hy4,经 PackyCode 接入,DeepSeek Harness 只是运行它的应用。DSH 自己的提示词原样保留,其它模型的请求不受影响。
250
+
251
+ Responses 请求只有 GPT 模型保留 `prompt_cache_key`,其他 Responses 模型默认省略。当前网关的 Grok 路由会将这个字段误报成 `Incorrect API key provided`;DeepSeek Flash 和 Hy4 不带它也能命中前缀缓存。GPT 的工具定义还会显式带上 `strict: false`:PackyCode 的 GPT 通道把没写 `strict` 的工具当作严格模式,模型会被迫填满所有可选参数(见「常见问题」)。
249
252
 
250
253
  GPT-6.1 Terra 的上下文、输出上限和推理档位来自 [OpenAI 模型页](https://developers.openai.com/api/docs/models/gpt-6.1-terra)。它是唯一可以关闭推理的 GPT 模型:关闭时发送 `reasoning.effort: "none"`,网关原样转发,返回时不带思考。GPT-5.6 Sol 的文档虽然也列出 `none`,经 PackyCode 却按 `medium` 回答,所以不能关。
251
254
 
@@ -272,9 +275,9 @@ DeepSeek Flash 走网关的 Responses 接口(`/api/pricing` 列出 `openai-res
272
275
 
273
276
  ## 更新与卸载
274
277
 
275
- > **从 1.3.2 或更早版本升级:** 请在插件页填写 `dsh-packycode-api@1.4.5` 安装,不要点旧版设置页里的「更新插件」。旧按钮安装时会绕过 pnpm 的发布冷却期:装到的版本如果发布还不满 24 小时,这个 profile 在它满 24 小时之前就装不了其他插件。装好并重启后,按钮就换成了修好的版本,以后直接点即可。
278
+ > **从 1.3.2 或更早版本升级:** 请在插件页填写 `dsh-packycode-api@1.4.7` 安装,不要点旧版设置页里的「更新插件」。旧按钮安装时会绕过 pnpm 的发布冷却期:装到的版本如果发布还不满 24 小时,这个 profile 在它满 24 小时之前就装不了其他插件。装好并重启后,按钮就换成了修好的版本,以后直接点即可。
276
279
 
277
- **更新:** 打开 **设置 → PackyCode**,有新版本时点「更新插件」。它会在当前 profile 目录里用 DSH 自带的 pnpm 安装精确版本,并读回 `package.json` 确认版本落地。安装遵守 pnpm 的发布冷却策略,不会绕过它:默认情况下 pnpm 会直接装上这个版本,并把它记进 profile 的 `minimumReleaseAgeExclude`;如果你给 pnpm 配了更严格的策略,按钮会提示什么时候可以更新。新版本号是从 npm 读到的,pnpm 却从 profile 配置的安装源下载:刚发布的版本,安装源(尤其是国内镜像)可能还没同步到,这时按钮会提示过几分钟再更新;连不上安装源时,会提示检查网络或代理。本地 `link:` 开发安装不会出现这个按钮。完成后完全退出并重新打开桌面应用。只刷新页面不会重载 Host。也可以在**插件**页重新安装,同样要填写带版本号的包名(例如 `dsh-packycode-api@1.4.5`),否则装上的可能是发布满 24 小时的旧版。
280
+ **更新:** 打开 **设置 → PackyCode**,有新版本时点「更新插件」。它会在当前 profile 目录里用 DSH 自带的 pnpm 安装精确版本,并读回 `package.json` 确认版本落地。安装遵守 pnpm 的发布冷却策略,不会绕过它:默认情况下 pnpm 会直接装上这个版本,并把它记进 profile 的 `minimumReleaseAgeExclude`;如果你给 pnpm 配了更严格的策略,按钮会提示什么时候可以更新。新版本号是从 npm 读到的,pnpm 却从 profile 配置的安装源下载:刚发布的版本,安装源(尤其是国内镜像)可能还没同步到,这时按钮会提示过几分钟再更新;连不上安装源时,会提示检查网络或代理。本地 `link:` 开发安装不会出现这个按钮。完成后完全退出并重新打开桌面应用。只刷新页面不会重载 Host。也可以在**插件**页重新安装,同样要填写带版本号的包名(例如 `dsh-packycode-api@1.4.7`),否则装上的可能是发布满 24 小时的旧版。
278
281
 
279
282
  **从本地路径安装切回官方源时,必须先卸载。** 「更新」是 `pnpm add`,它只重写包目录里的文件,不会删除更早一次本地路径安装留在包目录内的 `node_modules`;那份旧依赖会继续挡住 DSH 自带的包,插件行加载失败且看不出原因。「卸载」执行的是 `pnpm remove`,会删掉整个包目录,重装才是干净的。用 `node scripts/install-check.mjs` 可以确认当前 profile 是否处于这个状态。
280
283
 
@@ -290,7 +293,7 @@ ls ~/.dsh/profiles/desktop/node_modules/dsh-packycode-api/node_modules
290
293
 
291
294
  有输出就是残留:从 npm 安装的包不会自带 `node_modules`,这一份通常来自更早一次「本地路径」安装(`file:` 或直接写路径,而不是 `link:`)。它位于 profile 目录内部,而 DSH 解析插件导入时优先使用 profile 内的副本,所以插件拿到的仍是那份旧依赖 —— 例如 `@deepseek-ai/schemastery` 3.18.2 没有 `Schema.volatile()`,模块在导入阶段就抛错。导入失败时 Loader 不会为这一行创建 fiber,客户端 bundle 也不会被组合,于是模型路由、RPC 通道和设置页全都不会出现。
292
295
 
293
- 修复:到**插件**页**卸载**本插件,再用带版本号的包名重新**安装**(例如 `dsh-packycode-api@1.4.5`),然后完全退出并重新打开桌面应用。卸载执行的是 `pnpm remove`,会删掉整个包目录;直接重装或点「更新」只重写文件,不会清掉这份残留。也可以手动删掉上面那个 `node_modules` 再重启。
296
+ 修复:到**插件**页**卸载**本插件,再用带版本号的包名重新**安装**(例如 `dsh-packycode-api@1.4.7`),然后完全退出并重新打开桌面应用。卸载执行的是 `pnpm remove`,会删掉整个包目录;直接重装或点「更新」只重写文件,不会清掉这份残留。也可以手动删掉上面那个 `node_modules` 再重启。
294
297
 
295
298
  **首次安装后,设置页每张卡片都显示 `transport failure for /packycode-api/…: HTTP 405`?** 实际装上的是 1.1.6 或更早的版本,通常是因为安装时只填了包名:安装提示显示的是最新版,pnpm 实际装的却是发布满 24 小时的旧版(见「安装插件」)。这些旧版要等 DSH 重启、重建它的 `connection` 服务之后,才能注册设置通道。所以首次安装后 `/packycode-api` 通道还不存在,请求落到静态页面,返回 405;模型路由和设置页本身照常加载。1.1.7 起首次安装不需要重启。先确认装上的版本:
296
299
 
@@ -1,4 +1,4 @@
1
- # GPT Image 2 / 2.5 Images API 核查
1
+ # GPT Image 2 / 2.5 / 2.6 Images API 核查
2
2
 
3
3
  核查日期:2026-10-15(Asia/Shanghai)。协议核查部分只查阅公开资料;末尾另记录用户添加独立图片 Key 并授权测试后的 PackyCode 网关结果。协议能力与实际网关结果分开记录,不记录任何完整凭据。
4
4
 
@@ -75,3 +75,26 @@ JSON 编辑的字段为 `images: [{ image_url: "…" }]` 或 `images: [{ file_id
75
75
  回归测试先复现同样错误,再验证修复:空引用数组表示没有参考图;只把明确的零值、空 ID / 全零 ID 遮罩占位视为未提供。`operation: edit` 仍要求有效参考图,`operation: generate` 拒绝非空参考图,真实无效附件和真实遮罩不能变成新图请求。工具专用的 `model: settings` / `quality: settings` 可明确跟随已保存的设置,`settings` 不会发给网关。
76
76
 
77
77
  修复后,通过已构建的 `createPackyCodeImageTool().execute()` 回放原生参数结构(提示词替换为公共茶壶测试描述),只发出一次 `/v1/images/generations` 请求并成功返回 PNG,耗时 12.267 秒,`size: auto` 的实际图片为 1329×1183。结果可渲染成图片附件,日志和结果均不含完整 Key。该检查使用真实专用图片 Key、真实网关和本地附件测试适配器;它验证了工具参数路径,仍不等同于自动驱动整个桌面对话。记录在本地 `.artifacts/native-image-argument-replay-results.json`。
78
+
79
+ ## GPT Image 2.6 替换 2.5(2026-11-05)
80
+
81
+ 2026-11-05 的 `/api/pricing` 在 `image` 分组列出 `gpt-image-2.6-flare` 和 `gpt-image-2.6-sunburst`,端点为 `image-generation`;2.5 两款仍在列表里。插件的设置卡、`packycode_image_generate` 工具和 `scripts/image-check.mjs` 改为 2.6 两款,`gpt-image-2` 不变。
82
+
83
+ 官方[生图指南](https://developers.openai.com/api/docs/guides/image-generation)把 2.6 和 2.5 的 Sunburst / Flare 写在同一句质量说明里:`low`、`medium`、`high`、`xhigh`、`max`。`auto` 依据同一指南的通用输出设置说明保留。2.6 的 [Sunburst](https://developers.openai.com/api/docs/models/gpt-image-2.6-sunburst) 和 [Flare](https://developers.openai.com/api/docs/models/gpt-image-2.6-flare) 模型页都把 `v1/images/edits` 标为支持、`v1/responses` 标为不支持。尺寸限制、透明背景和 mask 在指南里只写在 2.5 的章节中,2.6 没有单独说明;插件沿用原有尺寸校验,本轮没有单独验证这几项。指南另写 2.6 支持 complexity、markup 编辑、SVG 和 GIF 输出,插件没有接入这些参数。
84
+
85
+ 已保存的 `gpt-image-2.5-flare` / `gpt-image-2.5-sunburst` 设置:从 Config schema 里直接删掉这两个值,会让选过它们的用户的插件 Config 解析失败。schema 把它们保留为隐藏值,读取图片偏好时映射到同名的 2.6 型号,质量不变;设置卡和工具只提供 2.6,并拒绝 2.5 的 id。
86
+
87
+ 网关实测同前:已构建的图片 client 调用 `https://cf.api.fan`,Key 只从 `packycode-api/image-keys` 读取(尾号 …ECMQ),提示和编辑指令与 2026-10-15 相同,每次 `1024x1024`、PNG、`n: 1`,无重试。
88
+
89
+ | 请求型号 | 请求 quality | 生图 | 编辑 | 响应回报 quality | 生图 / 编辑耗时 |
90
+ | --- | --- | --- | --- | --- | --- |
91
+ | `gpt-image-2` | `low` | 通过 | 未测 | `low` | 11.6 秒 |
92
+ | `gpt-image-2.6-flare` | `low` | 通过 | 通过 | `low` | 5.7 秒(另一轮 6.4)/ 9.0 秒 |
93
+ | `gpt-image-2.6-flare` | `xhigh` | 通过 | 通过 | `xhigh` | 13.7 / 14.7 秒 |
94
+ | `gpt-image-2.6-flare` | `max` | 通过 | 通过 | `max` | 24.3 / 26.1 秒 |
95
+ | `gpt-image-2.6-sunburst` | `auto` | 通过 | 未测 | `low` | 16.1 秒 |
96
+ | `gpt-image-2.6-sunburst` | `low` | 通过 | 通过 | `low` | 13.3 / 16.8 秒 |
97
+ | `gpt-image-2.6-sunburst` | `xhigh` | 通过 | 通过 | `xhigh` | 50.6 / 64.4 秒 |
98
+ | `gpt-image-2.6-sunburst` | `max` | 通过 | 通过 | `max` | 95.9 / 96.6 秒 |
99
+
100
+ 共 15 次请求全部成功,均返回 1024×1024 PNG。抽查的生图为白底蓝色茶壶,编辑后茶壶变橙、构图和白底保留。`auto` 发出后网关回报 `low`。响应没有可识别的 `model` 字段,所以结论仍是这些型号在当前 Key 和网关下可用、回报的 quality 与请求一致,不独立证明网关内部的模型身份。本轮没有在 DSH 桌面对话里跑完整的模型 → 工具 → 聊天预览流程。PNG 保存在本地 `.artifacts/image-check-*/`,不进入 Git 或 npm 包。
package/lib/client.js CHANGED
@@ -57,7 +57,7 @@ window.__ModuleLoader__.load({
57
57
  imagesQuality_high: "高",
58
58
  imagesQuality_xhigh: "超高(xhigh)",
59
59
  imagesQuality_max: "最高(max)",
60
- imagesQualityHint: "2.5 支持额外的 xhigh / max;质量越高,耗时和费用通常越高。网关实际支持情况需用图片 Key 验证。不会自动换型号或降低质量。",
60
+ imagesQualityHint: "2.6 支持额外的 xhigh / max;质量越高,耗时和费用通常越高。网关实际支持情况需用图片 Key 验证。不会自动换型号或降低质量。",
61
61
  imagesAddKey: "添加图片 Key",
62
62
  imagesKeyPlaceholder: "粘贴专用的图片 API Key",
63
63
  imagesNoKey: "尚未添加图片 Key。添加后可使用图片工具;对话 Key 不会用于图片请求。",
@@ -298,7 +298,7 @@ window.__ModuleLoader__.load({
298
298
  imagesQuality_high: "High",
299
299
  imagesQuality_xhigh: "Extra high (xhigh)",
300
300
  imagesQuality_max: "Maximum (max)",
301
- imagesQualityHint: "The 2.5 engines also support xhigh / max. Higher quality usually takes longer and costs more. Gateway support needs testing with an image key. Models and quality are never changed automatically.",
301
+ imagesQualityHint: "The 2.6 engines also support xhigh / max. Higher quality usually takes longer and costs more. Gateway support needs testing with an image key. Models and quality are never changed automatically.",
302
302
  imagesAddKey: "Add an image key",
303
303
  imagesKeyPlaceholder: "Paste the dedicated image API key",
304
304
  imagesNoKey: "No image key yet. Add one to enable the image tool. Conversation keys are never used for images.",
@@ -1959,6 +1959,7 @@ window.__ModuleLoader__.load({
1959
1959
  "gpt-5.6-sol"
1960
1960
  ]],
1961
1961
  ["Grok", ["grok-4.7"]],
1962
+ ["Hunyuan", ["hy4"]],
1962
1963
  ["Gemini", ["gemini-4-argon", "gemini-3.8-flash"]],
1963
1964
  ["Claude", [
1964
1965
  "claude-opus-5-5",
package/lib/index.js CHANGED
@@ -1083,7 +1083,9 @@ const DEFAULT_REASONING_LEVEL = "high";
1083
1083
  * Astra and GPT-5.6 Sol `reasoning.effort` (developers.openai.com model
1084
1084
  * pages), DeepSeek thinking mode (`low|high|max` effort, or off, for Flash
1085
1085
  * and V4 Pro alike), Grok 4.7
1086
- * (docs.x.ai/developers/grok-4-7), and Gemini 4 Argon and 3.8 Flash
1086
+ * (docs.x.ai/developers/grok-4-7), Hy4 (`high` or `no_think`, TokenHub's
1087
+ * deep-thinking page cloud.tencent.com/document/product/1823/131208), and
1088
+ * Gemini 4 Argon and 3.8 Flash
1087
1089
  * (ai.google.dev/gemini-api/docs/models/gemini-4-argon and gemini-3.8-flash).
1088
1090
  *
1089
1091
  * @module dsh-packycode-api/catalog
@@ -1104,8 +1106,8 @@ const GEMINI_BASE = `${DEFAULT_API_HOST}/v1beta`;
1104
1106
  * escalation pair then came back as `workspace-write` with an empty
1105
1107
  * justification, which DSH's edit and write refuse. Declaring strict-mode
1106
1108
  * support makes pi-ai send `strict: false` on each tool, as the official
1107
- * Codex client does; the schemas stay as DSH wrote them. DeepSeek and Grok
1108
- * leave optional parameters out either way.
1109
+ * Codex client does; the schemas stay as DSH wrote them. DeepSeek, Grok and
1110
+ * Hy4 fill optional parameters no more often without `strict` than with it.
1109
1111
  */
1110
1112
  const GPT_COMPAT = Object.freeze({ supportsStrictMode: true });
1111
1113
  /**
@@ -1155,6 +1157,22 @@ const GROK_LEVELS = Object.freeze({
1155
1157
  ...ALWAYS_THINKING_LEVELS,
1156
1158
  max: null
1157
1159
  });
1160
+ /**
1161
+ * Hy4 documents `reasoning_effort` high | no_think and nothing else, with
1162
+ * thinking on by default. Through PackyCode `no_think` answers without
1163
+ * reasoning, so `off` sends it. The gateway does not refuse low, medium, xhigh
1164
+ * or max, but they are undocumented, and they came back with high's prompt
1165
+ * tokens and no consistent difference in reasoning, so they are not offered.
1166
+ */
1167
+ const HY4_LEVELS = Object.freeze({
1168
+ off: "no_think",
1169
+ minimal: null,
1170
+ low: null,
1171
+ medium: null,
1172
+ high: "high",
1173
+ xhigh: null,
1174
+ max: null
1175
+ });
1158
1176
  /** Gemini 4 Argon and 3.8 Flash support low | medium | high, with no off. */
1159
1177
  const GEMINI_LEVELS = Object.freeze({
1160
1178
  ...ALWAYS_THINKING_LEVELS,
@@ -1258,6 +1276,19 @@ const PACKYCODE_MODELS = Object.freeze([
1258
1276
  thinkingLevelMap: GROK_LEVELS,
1259
1277
  compat: Object.freeze({ supportsLongCacheRetention: false })
1260
1278
  }),
1279
+ Object.freeze({
1280
+ id: "hy4",
1281
+ name: "Hy4",
1282
+ api: "openai-responses",
1283
+ provider: PROVIDER,
1284
+ baseUrl: RESPONSES_BASE,
1285
+ reasoning: true,
1286
+ input: Object.freeze(["text", "image"]),
1287
+ cost: NO_COST,
1288
+ contextWindow: 1024e3,
1289
+ maxTokens: 64e3,
1290
+ thinkingLevelMap: HY4_LEVELS
1291
+ }),
1261
1292
  Object.freeze({
1262
1293
  id: "gemini-4-argon",
1263
1294
  name: "Gemini 4 Argon",
@@ -6504,7 +6535,7 @@ const IMAGE_MODELS = Object.freeze({
6504
6535
  "medium",
6505
6536
  "high"
6506
6537
  ]),
6507
- "gpt-image-2.5-flare": Object.freeze([
6538
+ "gpt-image-2.6-flare": Object.freeze([
6508
6539
  "auto",
6509
6540
  "low",
6510
6541
  "medium",
@@ -6512,7 +6543,7 @@ const IMAGE_MODELS = Object.freeze({
6512
6543
  "xhigh",
6513
6544
  "max"
6514
6545
  ]),
6515
- "gpt-image-2.5-sunburst": Object.freeze([
6546
+ "gpt-image-2.6-sunburst": Object.freeze([
6516
6547
  "auto",
6517
6548
  "low",
6518
6549
  "medium",
@@ -6522,6 +6553,16 @@ const IMAGE_MODELS = Object.freeze({
6522
6553
  ])
6523
6554
  });
6524
6555
  const IMAGE_MODEL_IDS = Object.freeze(Object.keys(IMAGE_MODELS));
6556
+ /**
6557
+ * Engines the settings once offered, mapped to the ones that replaced them.
6558
+ * A saved setting still names them, so the Config schema keeps them as hidden
6559
+ * values (dropping them would fail the plugin's Config at load) and reading
6560
+ * the preference moves them to their successor with the same quality.
6561
+ */
6562
+ const RETIRED_IMAGE_MODELS = Object.freeze({
6563
+ "gpt-image-2.5-flare": "gpt-image-2.6-flare",
6564
+ "gpt-image-2.5-sunburst": "gpt-image-2.6-sunburst"
6565
+ });
6525
6566
  const IMAGE_QUALITIES = Object.freeze([
6526
6567
  "auto",
6527
6568
  "low",
@@ -6555,7 +6596,8 @@ function validateImageOptions({ model = DEFAULT_IMAGE_MODEL, quality = "auto", s
6555
6596
  //#endregion
6556
6597
  //#region src/image-settings.js
6557
6598
  function readImagePreference(value = {}) {
6558
- const model = fieldValue(value.imageModel);
6599
+ const saved = fieldValue(value.imageModel);
6600
+ const model = Object.hasOwn(RETIRED_IMAGE_MODELS, saved) ? RETIRED_IMAGE_MODELS[saved] : saved;
6559
6601
  const imageModel = IMAGE_MODEL_IDS.includes(model) ? model : DEFAULT_IMAGE_MODEL;
6560
6602
  const quality = fieldValue(value.imageQuality);
6561
6603
  return {
@@ -7064,7 +7106,7 @@ function createPackyCodeImageTool({ client, attachments, getPreference, getSessi
7064
7106
  quality: {
7065
7107
  type: "string",
7066
7108
  enum: ["settings", ...IMAGE_QUALITIES],
7067
- description: "Use settings (or omit) to follow the user image setting. auto is an explicit API quality, not a request to follow settings. xhigh and max require a 2.5 model; never downgrade automatically."
7109
+ description: "Use settings (or omit) to follow the user image setting. auto is an explicit API quality, not a request to follow settings. xhigh and max require a 2.6 model; never downgrade automatically."
7068
7110
  },
7069
7111
  size: {
7070
7112
  type: "string",
@@ -8086,6 +8128,49 @@ function createGeminiApi() {
8086
8128
  };
8087
8129
  }
8088
8130
  //#endregion
8131
+ //#region src/hy4-identity.js
8132
+ /** The sentence appended to Hy4's instructions; checked live as worded. */
8133
+ const HY4_IDENTITY_NOTE = "About yourself: the hy4 model is Hy4 from Tencent Hunyuan (腾讯混元), reached through PackyCode. DeepSeek Harness is the agent app you run in, not your model or its maker.";
8134
+ const INSTRUCTION_ROLES = /* @__PURE__ */ new Set(["developer", "system"]);
8135
+ const carriesNote = (item) => typeof item?.content === "string" && item.content.includes("About yourself: the hy4 model is Hy4 from Tencent Hunyuan (腾讯混元), reached through PackyCode. DeepSeek Harness is the agent app you run in, not your model or its maker.");
8136
+ /**
8137
+ * Add the note to a Responses payload: after the leading instructions, or as
8138
+ * the only ones when the request has none. A payload that already carries it
8139
+ * is returned unchanged, and the given payload is never modified.
8140
+ * @param payload - the Responses request body pi-ai built.
8141
+ * @returns the body to send.
8142
+ */
8143
+ function withIdentityNote(payload) {
8144
+ if (!Array.isArray(payload?.input) || payload.input.some(carriesNote)) return payload;
8145
+ const [first, ...rest] = payload.input;
8146
+ const input = INSTRUCTION_ROLES.has(first?.role) && typeof first.content === "string" ? [{
8147
+ ...first,
8148
+ content: `${first.content}\n\n${HY4_IDENTITY_NOTE}`
8149
+ }, ...rest] : [{
8150
+ role: "developer",
8151
+ content: HY4_IDENTITY_NOTE
8152
+ }, ...payload.input];
8153
+ return {
8154
+ ...payload,
8155
+ input
8156
+ };
8157
+ }
8158
+ /**
8159
+ * pi-ai options whose payload carries the note before any caller hook sees
8160
+ * it, so a caller's own `onPayload` still has the last word.
8161
+ * @param options - the request's pi-ai options.
8162
+ * @returns the same options with the note added on the way out.
8163
+ */
8164
+ function withHy4Identity(options) {
8165
+ return {
8166
+ ...options,
8167
+ onPayload: async (payload, model) => {
8168
+ const noted = withIdentityNote(payload);
8169
+ return await options?.onPayload?.(noted, model) ?? noted;
8170
+ }
8171
+ };
8172
+ }
8173
+ //#endregion
8089
8174
  //#region src/provider.js
8090
8175
  /**
8091
8176
  * The PackyCode pi-ai provider, built in code so the user configures no route.
@@ -8141,10 +8226,13 @@ function createPackyCodeProvider({ claudeCli } = {}) {
8141
8226
  "google-generative-ai": createGeminiApi()
8142
8227
  }
8143
8228
  });
8144
- const requestOptions = (model, options) => model.api === "openai-responses" && !model.id.startsWith("gpt-") ? {
8145
- ...options,
8146
- cacheRetention: "none"
8147
- } : options;
8229
+ const requestOptions = (model, options) => {
8230
+ const cached = model.api === "openai-responses" && !model.id.startsWith("gpt-") ? {
8231
+ ...options,
8232
+ cacheRetention: "none"
8233
+ } : options;
8234
+ return model.id === "hy4" ? withHy4Identity(cached) : cached;
8235
+ };
8148
8236
  return Object.freeze({
8149
8237
  ...provider,
8150
8238
  stream: (model, context, options) => provider.stream(model, context, requestOptions(model, options)),
@@ -9757,7 +9845,8 @@ const Config = z.object({
9757
9845
  /** Only the picker is filtered; an existing session can keep its model. */
9758
9846
  hiddenModels: live(z.array(z.string()).default([])),
9759
9847
  imageEnabled: live(z.boolean().default(true)),
9760
- imageModel: live(z.union([...IMAGE_MODEL_IDS]).default(DEFAULT_IMAGE_MODEL)),
9848
+ /** A retired engine still parses, hidden, and is read as its successor. */
9849
+ imageModel: live(z.union([...IMAGE_MODEL_IDS, ...Object.keys(RETIRED_IMAGE_MODELS).map((id) => z.const(id).hidden())]).default(DEFAULT_IMAGE_MODEL)),
9761
9850
  imageQuality: live(z.union([...IMAGE_QUALITIES]).default("auto")),
9762
9851
  /** Path to the Claude Code CLI; empty means "the usual install places, then PATH". */
9763
9852
  claudeCliPath: live(z.string().default("")),
@@ -10209,4 +10298,4 @@ function apply(ctx, config) {
10209
10298
  });
10210
10299
  }
10211
10300
  //#endregion
10212
- export { AUTO_PRESET, AUTO_REVIEW_FLASH, AUTO_REVIEW_JEV, AUTO_REVIEW_MODELS, AUTO_REVIEW_MODEL_NAMES, AUTO_REVIEW_SESSION, AUTO_REVIEW_TIMEOUT_MS, CHANNEL, CLAUDE_INSTALL_COMMAND, CLAUDE_MIN_VERSION, CLAUDE_MISSING_MESSAGE, CLAUDE_NPM_LATEST_URL, CLAUDE_NPM_PACKAGE, CLAUDE_NPM_UPDATE_COMMAND, CLAUDE_PERMISSION_MODES, CLAUDE_SELF_UPDATE_COMMAND, CLI_ONLY_GROUPS, CLI_PROJECT_DIR_NAME, CLI_SESSION_IDLE_MS, Config, DEFAULT_API_HOST, DEFAULT_AUTO_REVIEW_MODEL, DEFAULT_CLAUDE_CONFIG_DIR, DEFAULT_IMAGE_MODEL, DEFAULT_SEARCH_BACKEND, DEFAULT_STATUS_HOST, DIAGNOSTICS_FORMAT, DIAGNOSTICS_LIMITS, DISPLAY_NAME, DSH_AUTO_REVIEW_ROW, HTTP_CLAUDE_GROUPS, IMAGE_MODELS, IMAGE_MODEL_IDS, IMAGE_QUALITIES, IMAGE_TIMEOUT_MS, IMAGE_TOOL_NAME, JEV_ALLOW_THRESHOLD, JEV_HIGH_RISK_LIMIT, JEV_LIMITS, JEV_QUESTIONS, LEGACY_STATUS_HOSTS, MAX_IMAGE_BYTES, MAX_LIVE_CLI_SESSIONS, MIRROR_TOOL, PACKYCODE_AUTO_SEARCH_PROVIDER_ID, PACKYCODE_CLASSIFIER_MODELS, PACKYCODE_COVERED_MODEL_IDS, PACKYCODE_MODELS, PACKYCODE_MODEL_IDS, PACKYCODE_SEARCH_PROVIDER_ID, PLAN_TOOL, PLUGIN_ID, PROVIDER, PackyCodeKeyRing, SEARCH_BACKENDS, SEARCH_BACKEND_MODELS, SEARCH_MODES, SETTINGS_NAMESPACE, TEST_MESSAGE_POLICY_CODE, answerChunks, answersFor, apply, approvalReason, assertApiKey, baseUrlOf, buildCliArgs, buildCliEnvironment, buildSearchRequest, buildTranscript, catalogCoverage, classifyCliOutdated, classifyCliUnavailable, classifyClientPolicy, classifyGatewayFailure, classifyTestMessagePolicy, classifyUpstreamServerError, claudeBinaryCandidates, claudePermissionMode, claudeTransportFor, cliErrorMessage, compactionSummary, createAutoReviewController, createBalanceReader, createClaudeAgentBridge, createClaudeCliManager, createClaudeCliTransport, createClaudeLatestReader, createClaudeToolNames, createDiagnostics, createGroupReader, createImageController, createJevReviewer, createKeyChooser, createModelSelectionController, createPackyCodeAutoSearchProvider, createPackyCodeImageClient, createPackyCodeImageTool, createPackyCodeProfile, createPackyCodeProvider, createPackyCodeRpc, createPackyCodeSearchProvider, createProfileSearchComposition, createRouteAdapter, createSearchComposition, createSearchController, decideFromJev, decodeImagePng, describeRequest, dshSystemText, explainCliClientPolicyFailure, explainCliOutdated, explainCliUnavailable, explainClientPolicyFailure, explainNpmFailure, explainTestMessagePolicyFailure, failureChunk, guardKeyRotation, inject, isClaudeCliOutdated, isNpmClaudeInstall, isOfficialReviewRequest, jevState, locateClaudeBinary, locateNpm, messageFingerprint, name, normalizeFailureMessage, normalizeHost, officialAnswer, orderKeysFor, parseClaudeVersion, parseMessagesSearchResponse, parsePricing, parseResponsesSearchResponse, parseSelectedGroups, parseTokenUsage, pickKeyForModel, planAnswer, planContinuation, pngDimensions, presentClaudeCall, presentClaudeResult, questionPrompt, questionsFor, readAutoReviewChoice, readHiddenModels, readImagePreference, readReviewSections, readSearchChoice, refusalMessage, resolveSpawnCommand, responseFingerprint, sessionUuid, splitAtLastAnswer, startClaudeCliSession, statusHostOrder, summarizeSessionEvents, textResponse, titlePrompt, toCliHistory, toolResultText, validateImageOptions };
10301
+ export { AUTO_PRESET, AUTO_REVIEW_FLASH, AUTO_REVIEW_JEV, AUTO_REVIEW_MODELS, AUTO_REVIEW_MODEL_NAMES, AUTO_REVIEW_SESSION, AUTO_REVIEW_TIMEOUT_MS, CHANNEL, CLAUDE_INSTALL_COMMAND, CLAUDE_MIN_VERSION, CLAUDE_MISSING_MESSAGE, CLAUDE_NPM_LATEST_URL, CLAUDE_NPM_PACKAGE, CLAUDE_NPM_UPDATE_COMMAND, CLAUDE_PERMISSION_MODES, CLAUDE_SELF_UPDATE_COMMAND, CLI_ONLY_GROUPS, CLI_PROJECT_DIR_NAME, CLI_SESSION_IDLE_MS, Config, DEFAULT_API_HOST, DEFAULT_AUTO_REVIEW_MODEL, DEFAULT_CLAUDE_CONFIG_DIR, DEFAULT_IMAGE_MODEL, DEFAULT_SEARCH_BACKEND, DEFAULT_STATUS_HOST, DIAGNOSTICS_FORMAT, DIAGNOSTICS_LIMITS, DISPLAY_NAME, DSH_AUTO_REVIEW_ROW, HTTP_CLAUDE_GROUPS, IMAGE_MODELS, IMAGE_MODEL_IDS, IMAGE_QUALITIES, IMAGE_TIMEOUT_MS, IMAGE_TOOL_NAME, JEV_ALLOW_THRESHOLD, JEV_HIGH_RISK_LIMIT, JEV_LIMITS, JEV_QUESTIONS, LEGACY_STATUS_HOSTS, MAX_IMAGE_BYTES, MAX_LIVE_CLI_SESSIONS, MIRROR_TOOL, PACKYCODE_AUTO_SEARCH_PROVIDER_ID, PACKYCODE_CLASSIFIER_MODELS, PACKYCODE_COVERED_MODEL_IDS, PACKYCODE_MODELS, PACKYCODE_MODEL_IDS, PACKYCODE_SEARCH_PROVIDER_ID, PLAN_TOOL, PLUGIN_ID, PROVIDER, PackyCodeKeyRing, RETIRED_IMAGE_MODELS, SEARCH_BACKENDS, SEARCH_BACKEND_MODELS, SEARCH_MODES, SETTINGS_NAMESPACE, TEST_MESSAGE_POLICY_CODE, answerChunks, answersFor, apply, approvalReason, assertApiKey, baseUrlOf, buildCliArgs, buildCliEnvironment, buildSearchRequest, buildTranscript, catalogCoverage, classifyCliOutdated, classifyCliUnavailable, classifyClientPolicy, classifyGatewayFailure, classifyTestMessagePolicy, classifyUpstreamServerError, claudeBinaryCandidates, claudePermissionMode, claudeTransportFor, cliErrorMessage, compactionSummary, createAutoReviewController, createBalanceReader, createClaudeAgentBridge, createClaudeCliManager, createClaudeCliTransport, createClaudeLatestReader, createClaudeToolNames, createDiagnostics, createGroupReader, createImageController, createJevReviewer, createKeyChooser, createModelSelectionController, createPackyCodeAutoSearchProvider, createPackyCodeImageClient, createPackyCodeImageTool, createPackyCodeProfile, createPackyCodeProvider, createPackyCodeRpc, createPackyCodeSearchProvider, createProfileSearchComposition, createRouteAdapter, createSearchComposition, createSearchController, decideFromJev, decodeImagePng, describeRequest, dshSystemText, explainCliClientPolicyFailure, explainCliOutdated, explainCliUnavailable, explainClientPolicyFailure, explainNpmFailure, explainTestMessagePolicyFailure, failureChunk, guardKeyRotation, inject, isClaudeCliOutdated, isNpmClaudeInstall, isOfficialReviewRequest, jevState, locateClaudeBinary, locateNpm, messageFingerprint, name, normalizeFailureMessage, normalizeHost, officialAnswer, orderKeysFor, parseClaudeVersion, parseMessagesSearchResponse, parsePricing, parseResponsesSearchResponse, parseSelectedGroups, parseTokenUsage, pickKeyForModel, planAnswer, planContinuation, pngDimensions, presentClaudeCall, presentClaudeResult, questionPrompt, questionsFor, readAutoReviewChoice, readHiddenModels, readImagePreference, readReviewSections, readSearchChoice, refusalMessage, resolveSpawnCommand, responseFingerprint, sessionUuid, splitAtLastAnswer, startClaudeCliSession, statusHostOrder, summarizeSessionEvents, textResponse, titlePrompt, toCliHistory, toolResultText, validateImageOptions };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-packycode-api",
3
- "version": "1.4.5",
3
+ "version": "1.4.7",
4
4
  "description": "Use PackyCode API keys in DeepSeek Harness with multi-protocol models, image generation and editing, separate key rings, and balance display",
5
5
  "type": "module",
6
6
  "main": "./lib/index.js",