Chuyển đến nội dung chính

dsh-short-tool-ids

Đã xác minh

dsh-short-tool-ids · v0.4.0 · MIT · Giao diện web

Scoped, reversible tool-call ID compatibility plugin for DeepSeek Harness

Cài đặt

dsh plugin add dsh-short-tool-ids

Xác nhận layer đã áp bằng dsh --profile default --dump-config — xem hướng dẫn cài plugin.

Mã nguồn

Thẻ

Tác giả

Readme

dsh-short-tool-ids

An experimental DeepSeek Harness (DSH) plugin that fixes chats failing with errors like maximum length 64, got length 81. Some OpenAI-compatible Chat Completions providers reject tool-call IDs longer than 64 characters. This plugin shortens those IDs in outgoing requests, only for the providers you switch on in Settings → Short tool-call IDs. Saved sessions are never edited.

Source repository

Contents: Supported DSH versions · Why this plugin exists · Install · Settings tab · What it changes · Upgrading · Compatibility and risk · Development

Supported DSH versions

Supported range: DSH 0.1.5-rc.1 up to (not including) 0.3.0, with dsh-short-tool-ids 0.4.0 or later. Check yours with dsh --version.

DSH version npm tag (at the time of this release) Status Where the switches are stored
0.2.0-rc.2 latest, next ✅ Tested this plugin's entry in the profile patch (cordis.patch.yml)
0.2.0-rc.1 — ✅ Tested this plugin's entry in the profile patch (cordis.patch.yml)
0.1.7-rc.2 — ✅ Tested this plugin's entry in the profile patch (cordis.patch.yml)
0.1.5-rc.3 — ✅ Tested settings.yaml, section short-tool-ids
0.1.5-rc.2 — ✅ Tested settings.yaml, section short-tool-ids
0.1.5-rc.1 — ✅ Tested settings.yaml, section short-tool-ids
other releases from 0.1.5-rc.1 up to 0.3.0 (not included) — ⚠️ Untested but should work: loads with a warning if the API check passes detected automatically
older than 0.1.5-rc.1 — ❌ Not supported —
0.3.0 and newer (prereleases included) — ❌ Refused until tested (you can override with allowUntestedHarness: true) —

Tested pi-ai (@earendil-works/pi-ai) versions: 0.85.1 (DSH 0.1.5 – 0.2.0-rc.1) and 0.87.1 (DSH 0.2.0-rc.2). The plugin does not pin pi-ai: it never loads the model catalog, and pi-ai 0.87.1 still skips ID shortening for same-model history on providers not named exactly openai, so the workaround is still needed.

Node.js: ^22.19.0 or >=24.0.0, the same floor as pi-ai itself. The test suite passes on Node 22.19.0 and 24.12.0.

Which plugin version do I need?

dsh-short-tool-ids Works with DSH
0.4.0 and later 0.1.5-rc.1 up to 0.3.0 (not included): the 0.1.5, 0.1.7 and 0.2 releases. Node ^22.19.0 or >=24.
0.3.0 and older only 0.1.5-rc.2 (pi-ai adapter 0.1.5-rc.2, pi-ai 0.85.1), Node >=24. Refuses to load on DSH 0.1.7 and 0.2 (untested versions … refusing to patch).

A refused plugin logs a clear error at startup and does not load. It never half-loads and never touches your sessions. When a refusal happens, the Settings tab says the host plugin is not running. Whatever the version, the plugin also checks that the pi-ai adapter still has the methods it wraps (stream, prepareCall, current, modelOf) and refuses to load if one is missing.

Why this plugin exists

This plugin was built to recover a real DSH chat session that had stopped accepting messages. The session history held tool-call IDs of 81 characters, but the OpenAI-compatible API it was sending to accepts at most 64. Every new turn resent that history, so each request failed before the model could respond:

Invalid 'input[5].call_id': string too long. Expected a string with maximum length 64, but got a string with length 81 instead.

The chat used a custom provider named cc. pi-ai only shortens IDs when the history comes from a different model, and only for a provider named exactly openai. Renaming the provider to openai: cc does not match that exact name, and even openai would still skip same-model history. This plugin closes that gap. It is a targeted workaround, not a general fix for Responses or Anthropic message IDs.

Install from npm

dsh plugin --profile web add dsh-short-tool-ids

Stop the running DSH Web process when your active work is finished, then start it again normally, e.g. dsh web --no-open --port 3080, and refresh the page. Open Settings → Short tool-call IDs and switch on the provider that returns the ID-length error, then retry the chat.

To install from a local checkout instead:

dsh plugin --profile web add "/absolute/path/to/dsh-short-tool-ids"

To remove it:

dsh plugin --profile web remove dsh-short-tool-ids

Alternatively, switch a provider off: the next request goes out unchanged.

The Settings tab

The plugin adds its own Short tool-call IDs tab to Settings, containing:

  • a heading and a short explanation;
  • a notice that it is an experimental workaround;
  • every model provider, each with its own switch, which is off by default.

Each row shows the provider's display name, its route id and its protocol. Non-pi-ai providers (the built-in DeepSeek ones, for example) are listed, but their switches are disabled because the plugin never changes their requests. A pi-ai provider on another protocol, such as anthropic-messages, is marked "not affected". A provider that was switched on and has since been removed stays listed so you can switch it off.

A change applies from the next request, including a request that has been prepared but not yet sent, and needs no restart. A failed or conflicting save shows an error instead of false success. If the host plugin is not running (for example on an unsupported DSH), the tab says so and the switches are disabled.

What it changes

  • It changes pi-ai providers using openai-completions only. Other protocols and native adapters are untouched, even if their switch is on.
  • Ordinary IDs longer than 64 characters become call_ plus 48 SHA-256 hex characters (53 in total). Each call and its matching result get the same ID.
  • Both DSH history formats are handled:
    • 0.1.5 stores results as tool-result blocks inside a message;
    • 0.1.7 and later store each result as its own tool message.
  • Valid IDs, arguments, outputs, replay metadata, tool execution identities and saved session files are left unchanged. The fix works on existing history as well as new requests.
  • If a shortened ID would collide with another ID, the plugin refuses the request instead of pairing the wrong result.
  • Compound Responses call_id|item_id IDs are left untouched. Unsupported signed or native history that would need an unsafe rewrite is refused rather than stripped.

Upgrading from 0.3.x or older

  • The switch has moved. It used to be a checkbox on each provider card under Settings → Models. It now lives in its own Short tool-call IDs tab.
  • The dsh-rpm rate-limit row has been removed. Version 0.3.0 showed dsh-rpm's "Rate limit" input under its checkbox. This plugin is now fully independent: it never reads or writes another plugin's settings and does not register on the provider cards.
  • Existing switches carry over. On DSH 0.1.5 they stay in the short-tool-ids section of settings.yaml. When DSH 0.1.7+ first starts, it moves settings.yaml into the profile (the file is renamed to settings.yaml.imported), so your old values end up as this plugin's config.
  • Stop DSH, reinstall the plugin, start DSH again and refresh the page. The browser bundle is cached until the server restarts.

Compatibility and risk

Zero regressions are not guaranteed. This is a prototype wrapper, not an officially supported adapter-decorator API. DSH's ordinary llm/stream middleware only sees frozen durable requests and cannot replace their history.

The plugin finds the adapter through the running CLI's own dependency tree. It wraps PiAiAdapter.stream() and prepareCall() in a reversible way and keeps the original prepared handles and model snapshots. It must not be combined with another wrapper of the same methods; a second copy of this plugin is refused (already installed).

Plugin config keys (optional, set on the short-tool-ids entry):

Key Meaning
enabled: false Load without patching the adapter.
harnessEntry Path of the running dsh CLI entry (detected automatically).
allowUntestedHarness: true Load on a DSH outside the supported range. Not recommended.
providers DSH 0.1.7+: the per-provider switches edited by the Settings tab.

Development

The plugin has zero npm runtime or build dependencies. The host code is plain ESM, and a dependency-free builder writes the browser bundle in DSH's ModuleLoader format, using the shell's own React.

File Role
index.mjs Host entry: version gate, settings (both DSH generations), adapter shim.
normalize.mjs ID rewriting and the reversible adapter shim.
client/index.mjs Source of the Settings tab.
lib/client.js Generated by npm run build; never edit it by hand.
npm run build
npm test
DSH_TEST_HARNESS_ENTRY="/absolute/path/to/dsh/lib/bin.js" npm run test:integration
npm run pack:check

To run the integration suite against another DSH version, install that version in a scratch folder and point DSH_TEST_HARNESS_ENTRY at it:

npm install --prefix /tmp/dsh-017 @deepseek-ai/[email protected] --ignore-scripts
DSH_TEST_HARNESS_ENTRY=/tmp/dsh-017/node_modules/@deepseek-ai/dsh/lib/bin.js npm run test:integration

The integration suite sends the real adapter's HTTP requests to a loopback mock server (fake credentials, no paid API calls), in the history format of the DSH under test. It also mounts the plugin on that DSH's real settings API. The optional DSH_TEST_SESSION=/path/to/decoded-session.jsonl enables private-history replay checks. Never package or commit real session history.

The UI tests use a fake React harness rather than a browser. Version 0.4.0 was also checked in the real DSH Web app on 0.2.0-rc.2 (under Node 22.19.0), 0.2.0-rc.1, 0.1.7-rc.2 and 0.1.5-rc.3, by installing the packed tarball into an isolated DSH_HOME and chatting with a mock provider that returns 81-character IDs. On each version:

  • the tab rendered;
  • the switch saved, and on 0.2 persisted across a restart;
  • the provider received 53-character IDs while the switch was on;
  • the saved session kept the original IDs;
  • switching off restored the original IDs on the next request (checked on 0.2).

License

MIT. Maintainer release steps are in RELEASE.md.