dsh-finish-reason-patch
Manifest validTolerate OpenAI-compatible model streams that end without a terminal finish_reason so DSH turns complete instead of aborting.
dsh-finish-reason-patch
DSH plugin: stop agent turns from being aborted when an OpenAI-compatible
provider (GPT-family models, gateways, proxies) ends a streaming response with
full output but without a terminal finish_reason.
The bug it fixes
DSH routes OpenAI-compatible providers through @earendil-works/pi-ai. When
the wire stream ends without ever seeing choices[].finish_reason, pi-ai
raises Stream ended without finish_reason (openai-completions.js:438). By
that point every content block is already closed and delivered — the response
is complete, only the terminal marker is missing. pi-ai surfaces that as an
error event, the dsh-llm-pi-ai adapter maps it to a terminal
finish {kind:'error', code:'TRANSPORT'} chunk, and the agent loop
(dsh-agent-loop) throws — aborting a perfectly good model turn. Other agents
(e.g. Codex) tolerate the same wire behavior by treating end-of-stream as the
end of the response.
The fix
The plugin hooks the llm/stream waterfall — every model call (agent turns,
session-title requests, prepared calls, subagents) flows through it via
LlmRuntime.streamWithRegistration. When the terminal finish is exactly that
error, it is rewritten to a normal stop finish (or tool-calls if tool-call
deltas were delivered), so the turn completes instead of aborting. This holds
whether or not content was delivered: some OpenAI-compatible gateways stream
only usage — or nothing — before ending without a finish_reason (reporting
outputTokens: 0), and they are accepted as complete empty responses instead
of retry-looping (Codex-style tolerance). All other error finishes (transport
resets, rate limits, HTTP errors, ...) pass through untouched, so the existing
retry policy still applies to genuinely broken responses.
When it fires you'll see:
[finish-reason-patch] provider finished without finish_reason -> mapped to "stop"
Installation
The plugin is a plain Cordis host plugin (exports name / apply, no external
dependencies beyond the ctx Cordis passes in).
1. As a persistent profile bundle (recommended, survives restarts)
Ship this folder as a package named dsh-finish-reason-patch:
- Place the package where your DSH profile can resolve it, e.g. a junction or
symlink inside
<profile root>/node_modules/dsh-finish-reason-patchpointing at this folder (same pattern as other local DSH plugins). - In the profile root
package.json, add the package todsh.profile.bundlesand todependencies(e.g."dsh-finish-reason-patch": "link:<absolute path to this folder>"). - Restart DSH — bundle patches compose at boot. The package's own
cordis.patch.ymlinserts the plugin row automatically.
2. As a dynamic Cordis plugin (current process only)
Define/run the plugin host body (plugin.mjs) through the Cordis dynamic
plugin tools. It stays active until the process exits; re-run after a restart.
Effects are identical and idempotent if both routes are active.
Verifying
- Logic self-test (no network):
node selftest.mjs— all 5 cases pass. - Live: run a normal conversation with a GPT-class model. Turns that used to abort now complete, and the log line above appears.
Removal
Remove the bundle entry + dependency from the profile package.json, delete
the node_modules junction, restart DSH. No changes are made to any shipped
DSH file.
Files
plugin.mjs— the plugin (llm/streamwaterfall hook + rewrite logic)cordis.patch.yml— bundle patch layer (the profile-tree insert row)package.json— npm metadata (dsh.runtime: host,dsh.bundle.patch)selftest.mjs— local logic self-testLICENSE— MIT
Comments
Loading…
Similar plugins
by paulalesius
OpenAI-compatible /v1/chat/completions (streaming and non-streaming) and /v1/models endpoint on the DSH web server.
★ 0
TypeScript
Aug 24, 2026
dsh plugin --profile web add dsh-plugin-openai-apiby ArisuYuuko
DSH 审批弹窗 AI 注释器:模型请求权限外操作时,用模型自己的推理解释这次操作的意义与风险
★ 0
MIT
JavaScript
Oct 19, 2026
dsh plugin --profile web add dsh-approval-explainerby SnowNight777
把 DSH 已配置的模型共享给本机程序——无需重复配置,用 OpenAI 兼容接口直接调用
★ 0
JavaScript
Oct 4, 2026
dsh plugin --profile web add dsh-llm-gatewayby callqh
Sign in to OpenAI Codex from DeepSeek Harness with a ChatGPT Plus/Pro subscription, by driving the authorization flow llm-pi-ai already registers.
★ 0
MIT
JavaScript
Sep 30, 2026
dsh plugin --profile web add dsh-codex-oauthby Long-Yin-Zi
把 AI 每轮抛出的待决问题收进右侧边栏,选完写备注一键回传(DSH 桌面端插件)
★ 0
MIT
JavaScript
Nov 4, 2026
dsh plugin --profile web add dsh-task-decisionUses OpenAI GPT via the official Codex app-server, with ChatGPT subscription login, DSH tools, native settings, quota and manual token usage history.
★ 0
MIT
TypeScript
dsh plugin --profile web add dsh-codex-native