dsh-llm-fallbacks 0.1.0-alpha.1 → 0.1.0-alpha.3

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.md CHANGED
@@ -9,10 +9,10 @@
9
9
 
10
10
  Automatic provider/model fallback chains for dsh (DeepSeek Harness): when an agent's LLM requests keep failing — retries exhausted, auth errors, quota exceeded, rate limiting (429) — the plugin switches provider/model along the fallback chain for the current role, and the current step/turn continues on the target model: tasks are not interrupted by model problems.
11
11
 
12
- Install with a single command (pnpm ≥ 10 needs one build-allow step — see [Install](#install)):
12
+ Install with a single command (see [Install](#install)):
13
13
 
14
14
  ```sh
15
- dsh plugin --profile web add github:btspoony/dsh-llm-fallbacks # pin a commit with #<sha>
15
+ dsh plugin --profile web add dsh-llm-fallbacks # pin a version with @<version>
16
16
  ```
17
17
 
18
18
  ## Features
@@ -27,13 +27,31 @@ dsh plugin --profile web add github:btspoony/dsh-llm-fallbacks # pin a commit
27
27
 
28
28
  ## Install
29
29
 
30
- ### One-line git install
30
+ ### One-line install
31
31
 
32
32
  ```sh
33
- dsh plugin --profile web add github:btspoony/dsh-llm-fallbacks # pin a commit with #<sha>
33
+ dsh plugin --profile web add dsh-llm-fallbacks # pin a version with @<version>
34
34
  ```
35
35
 
36
- A git install fetches **sources, not built artifacts**, so the bundle builds itself on install (`prepare` self-build). The plugin is **mount-only**: it never modifies the dsh source tree, and no patch / postinstall step exists — dsh upgrades never require re-patching. pnpm ≥ 10 blocks a git dependency's `prepare` by default: the first `add` fails with `ERR_PNPM_GIT_DEP_PREPARE_NOT_ALLOWED`, and pnpm prints the exact package key. Allow the build in the profile's `pnpm-workspace.yaml` (`onlyBuiltDependencies: [dsh-llm-fallbacks]`, or run `dsh plugin --profile web approve-builds`), then re-run the `add`. Treat that allowance as permission to execute the package's code on your machine at install time, and pin a commit (`github:btspoony/dsh-llm-fallbacks#<sha>`) so a later push cannot silently change what runs. The full URL form works equivalently: `dsh plugin --profile web add https://github.com/btspoony/dsh-llm-fallbacks.git`.
36
+ A registry install fetches the **built package** (`dist/`) — nothing is built on the target machine. The plugin is **mount-only**: it never modifies the dsh source tree, and no patch / postinstall step exists — dsh upgrades never require re-patching. Versioning follows npm dist-tags (`latest` by default); pin an exact version with `dsh plugin --profile web add dsh-llm-fallbacks@<version>`.
37
+
38
+ > **Release status**: published as `dsh-llm-fallbacks@0.1.0-alpha.2` (latest). The first publish used a one-time `NODE_AUTH_TOKEN` bootstrap secret; Trusted Publishing is configured afterwards for tokenless releases.
39
+
40
+ ### Registry package (npm / pnpm)
41
+
42
+ ```sh
43
+ npm install dsh-llm-fallbacks # or: pnpm add dsh-llm-fallbacks
44
+ ```
45
+
46
+ > Release process → [docs/release.md](docs/release.md).
47
+
48
+ ### Git install (works today)
49
+
50
+ ```sh
51
+ dsh plugin --profile web add github:omdsh-dev/dsh-llm-fallbacks # pin a commit with #<sha>
52
+ ```
53
+
54
+ A git install fetches **sources, not built artifacts** — the bundle builds itself on install (`prepare` self-build), so the target machine needs node + pnpm. pnpm ≥ 10 blocks a git dependency's `prepare` by default (`ERR_PNPM_GIT_DEP_PREPARE_NOT_ALLOWED`); allow the build in the profile's `pnpm-workspace.yaml` and re-run the `add` (details in [docs/install.md](docs/install.md)).
37
55
 
38
56
  ### Local directory install (recommended for development / verification)
39
57
 
@@ -77,7 +95,7 @@ fallbacks:
77
95
  role: reviewer
78
96
  ```
79
97
 
80
- Roles are declared entities: `roles.list` holds role cards (id/label/description + optional chain/fallback), and `roles.rules` match origin/provider/model in order to a declared role id or the built-in `inherit` (first match wins) — **no rule match → `inherit` → `rootChain`**. A declared role is only ever hit when a rule references it. The legacy chain-key namespace and role-default field are gone (migration table: [docs/configuration.md](docs/configuration.md)).
98
+ Roles are declared entities: `roles.list` holds role cards (id/label/description + chain/fallback), and `roles.rules` match origin/provider/model in order to a declared role id or the built-in `inherit` (first match wins) — **no rule match → `inherit` → `rootChain`**. A declared role is only ever hit when a rule references it. A role without a chain is meaningless — the settings card blocks saving it and the host warns at startup; give every declared role a chain, or point its rules at the built-in `inherit`. (A hand-written YAML role with a missing/empty chain is not fatal: with `fallback: inherit-root` (the default) an empty chain still falls back to `rootChain`; with `fallback: none` an empty chain leaves no candidates and the request passes through untouched — either way it is only a startup warn.) The legacy chain-key namespace and role-default field are gone (migration table: [docs/configuration.md](docs/configuration.md)).
81
99
 
82
100
  Save and restart the web session for the changes to take effect. The feature switch `fallbacks.enabled` **defaults to off (`false`)** — the plugin only engages once it is turned on; `triggerCodes` defaults to `AUTH` / `QUOTA` / `RATE_LIMIT`; and with **no `rootChain`/role chains configured the behavior is identical to not having the plugin installed**. More examples (role entities, fallback strategies, rules referencing `inherit`) → [docs/configuration.md](docs/configuration.md).
83
101
 
@@ -103,7 +121,7 @@ The plugin installs as a **pure mount** — it never modifies the dsh source tre
103
121
  the Fallbacks card on the Settings → 插件配置 page, and settings read/write/reset
104
122
  go through the plugin's own gateway channel (`/api/fallbacks/get|set|reset`).
105
123
  - **No patches, no auto-apply step**: there are no dsh-body patch files and no install
106
- lifecycle step that applies one. A one-line git install works as-is.
124
+ lifecycle step that applies one. A one-line registry install works as-is.
107
125
  - **dsh upgrades never require re-patching**: a dsh upgrade that resets the source
108
126
  tree changes nothing for this plugin — it keeps working without any re-apply step.
109
127
  - **Stale leftover patches are harmless**: the plugin never depends on a patch
@@ -111,12 +129,23 @@ The plugin installs as a **pure mount** — it never modifies the dsh source tre
111
129
  was removed), so a previously patched dsh tree can be left as-is or manually
112
130
  reverted — neither is required.
113
131
 
132
+ ## Developer consumption
133
+
134
+ Beyond the dsh plugin mount, `dsh-llm-fallbacks` exposes a programmable consumer surface — both faces share the same function implementations (single point of truth, no copied logic):
135
+
136
+ - **Library API**: import the runtime functions and types from the package root — `import { resolveRole, resolveChain, validateFallbacksConfig } from 'dsh-llm-fallbacks'`.
137
+ - **Named cordis service**: while the plugin is applied, `ctx.get('llm-fallbacks')` returns a pure-function service (`{ name, version, resolveRole, resolveChain, validateFallbacksConfig, detectLegacyKeys }`); after the plugin is disposed it is `undefined`. Runtime state stays observable via `fallbacks/switch` events, not through the service.
138
+
139
+ Full contract (export inventory, minimal examples, lifecycle, typing) → [docs/consumer-api.md](docs/consumer-api.md).
140
+
114
141
  ## Documentation
115
142
 
116
143
  | Doc | Content |
117
144
  |---|---|
118
- | [docs/install.md](docs/install.md) | profile install / git install / uninstall / `--dump-config` verification |
145
+ | [docs/install.md](docs/install.md) | profile install / registry install / uninstall / `--dump-config` verification |
146
+ | [docs/release.md](docs/release.md) | release process: Trusted Publishing setup, Release prep SOP, fragment format, rollback |
119
147
  | [docs/configuration.md](docs/configuration.md) | full `fallbacks` namespace reference, selector syntax, example YAML, plugin-config card usage, behavior notes |
148
+ | [docs/consumer-api.md](docs/consumer-api.md) | developer consumption contract: export inventory, minimal examples, lifecycle, typing |
120
149
  | [docs/verification.md](docs/verification.md) | verification records (test matrix, bundle layer order, runtime contracts, QA gate script) |
121
150
 
122
151
  ## License
package/README.zh-CN.md CHANGED
@@ -9,10 +9,10 @@
9
9
 
10
10
  dsh(DeepSeek Harness)的自动模型降级插件:当 root agent 或 subagent 的模型请求持续失败(重试耗尽、权限、配额超限、限流 429)时,按角色/模型 fallback 链自动切换 provider/model,当前 step/turn 在目标模型上继续完成——任务不因模型问题中断。
11
11
 
12
- 一句话安装(pnpm ≥ 10 需一次构建放行,见 [安装](#安装)):
12
+ 一句话安装(见 [安装](#安装)):
13
13
 
14
14
  ```sh
15
- dsh plugin --profile web add github:btspoony/dsh-llm-fallbacks # 钉 commit:加 #<sha>
15
+ dsh plugin --profile web add dsh-llm-fallbacks # 钉版本:加 @<version>
16
16
  ```
17
17
 
18
18
  ## 能力一览
@@ -27,13 +27,31 @@ dsh plugin --profile web add github:btspoony/dsh-llm-fallbacks # 钉 commit:
27
27
 
28
28
  ## 安装
29
29
 
30
- ### 一句话 git 安装
30
+ ### 一句话安装
31
31
 
32
32
  ```sh
33
- dsh plugin --profile web add github:btspoony/dsh-llm-fallbacks # 钉 commit:加 #<sha>
33
+ dsh plugin --profile web add dsh-llm-fallbacks # 钉版本:加 @<version>
34
34
  ```
35
35
 
36
- git 安装拉取的是**源码而非构建产物**,安装时由包自行构建(`prepare` 自构建)。插件为**纯挂载**:对 dsh 源码树零修改,无任何补丁 / postinstall 步骤——dsh 升级无需重打。pnpm ≥ 10 默认不执行 git 依赖的 `prepare`:第一次 `add` 会失败并打印 `ERR_PNPM_GIT_DEP_PREPARE_NOT_ALLOWED`,同时给出精确的包 key。在该 profile 的 `pnpm-workspace.yaml` 中放行构建(`onlyBuiltDependencies: [dsh-llm-fallbacks]`,或运行 `dsh plugin --profile web approve-builds`),然后重跑 `add`。请把这次放行当作它本来的样子:允许该包代码在安装期于你的机器上执行——建议钉 commit(`github:btspoony/dsh-llm-fallbacks#<sha>`),防止后续 push 悄悄改变实际运行的代码。完整 URL 形式等价:`dsh plugin --profile web add https://github.com/btspoony/dsh-llm-fallbacks.git`。
36
+ registry 安装拉取的是**已构建产物**(`dist/`),目标机无需构建。插件为**纯挂载**:对 dsh 源码树零修改,无任何补丁 / postinstall 步骤——dsh 升级无需重打。版本跟随 npm dist-tag(默认 `latest`);钉精确版本:`dsh plugin --profile web add dsh-llm-fallbacks@<version>`。
37
+
38
+ > **发布状态**:已发布 `dsh-llm-fallbacks@0.1.0-alpha.2`(latest)。首次发布用一次性 `NODE_AUTH_TOKEN` bootstrap;Trusted Publishing 后续配置为无 token 发布。
39
+
40
+ ### registry 包安装(npm / pnpm)
41
+
42
+ ```sh
43
+ npm install dsh-llm-fallbacks # 或:pnpm add dsh-llm-fallbacks
44
+ ```
45
+
46
+ > 发布流程见 [docs/release.md](docs/release.md)。
47
+
48
+ ### git 安装(当前可用)
49
+
50
+ ```sh
51
+ dsh plugin --profile web add github:omdsh-dev/dsh-llm-fallbacks # 钉 commit:加 #<sha>
52
+ ```
53
+
54
+ git 安装拉取的是**源码而非构建产物**——安装时由 `prepare` 自构建,目标机需要 node 与 pnpm。pnpm ≥ 10 默认拦截 git 依赖的 `prepare`(`ERR_PNPM_GIT_DEP_PREPARE_NOT_ALLOWED`);在 profile 的 `pnpm-workspace.yaml` 中放行构建后重跑 `add`(详见 [docs/install.md](docs/install.md))。
37
55
 
38
56
  ### 本地目录安装(开发/验证推荐)
39
57
 
@@ -75,7 +93,7 @@ fallbacks:
75
93
  role: reviewer
76
94
  ```
77
95
 
78
- 角色是声明式实体:`roles.list` 存放角色卡(id/label/description + 可选 chain/fallback),`roles.rules` 按 origin/provider/model 顺序匹配到**已声明角色 id 或内置 `inherit`**(首个命中即停)——**未命中 → `inherit` → `rootChain`**。只声明不写规则的角色永不命中。旧链键命名空间与角色兜底字段已删除(迁移表见 [docs/configuration.md](docs/configuration.md))。
96
+ 角色是声明式实体:`roles.list` 存放角色卡(id/label/description + chain/fallback),`roles.rules` 按 origin/provider/model 顺序匹配到**已声明角色 id 或内置 `inherit`**(首个命中即停)——**未命中 → `inherit` → `rootChain`**。只声明不写规则的角色永不命中。角色无 chain 无意义——设置卡拦截保存、启动时告警;请为每个声明角色配置 chain,或让规则直接引用内置 `inherit`。(手写 YAML 角色链缺省/为空不致命:`fallback: inherit-root`(默认)时空链仍按防御语义回退 `rootChain`;`fallback: none` 时空链无候选 → no-op 透传;两种情况都仅启动告警。)旧链键命名空间与角色兜底字段已删除(迁移表见 [docs/configuration.md](docs/configuration.md))。
79
97
 
80
98
  保存并重启 web 会话后生效。功能级开关 `fallbacks.enabled` **默认关闭(`false`)**——打开开关后插件才会介入;`triggerCodes` 默认覆盖 `AUTH` / `QUOTA` / `RATE_LIMIT`;**未配置任何 `rootChain`/角色链时行为与未安装插件完全一致**。更多示例(角色实体、fallback 策略、引用 `inherit` 的规则)见 [docs/configuration.md](docs/configuration.md)。
81
99
 
@@ -101,17 +119,28 @@ fallbacks:
101
119
  Fallbacks 卡片,设置读写/重置
102
120
  走插件自有 gateway 通道(`/api/fallbacks/get|set|reset`)。
103
121
  - **无补丁、无自动打补丁**:没有 dsh 本体 patch 文件,也没有任何安装期 apply 步骤;
104
- 一句话 git 安装即可用。
122
+ 一句话 registry 安装即可用。
105
123
  - **dsh 升级永不需重打**:dsh 升级重置源码树对本插件无影响——无需任何重打步骤。
106
124
  - **残留旧补丁无害**:插件不依赖任何补丁导出(角色解析 rules-only;model-selection
107
125
  标记协调已移除)——已打过旧补丁的 dsh 树可原样保留或手动回滚,均非必需。
108
126
 
127
+ ## 开发者消费面
128
+
129
+ 除插件挂载外,`dsh-llm-fallbacks` 还暴露可编程消费面——两个入口共享同一函数实现(单点真相,无复制逻辑):
130
+
131
+ - **库 API**:从包根直接 import 运行时函数与类型——`import { resolveRole, resolveChain, validateFallbacksConfig } from 'dsh-llm-fallbacks'`。
132
+ - **具名 cordis service**:插件 apply 期间 `ctx.get('llm-fallbacks')` 返回纯函数服务(`{ name, version, resolveRole, resolveChain, validateFallbacksConfig, detectLegacyKeys }`),插件 dispose 后为 `undefined`。运行态(冷却、最近切换)请读 `fallbacks/switch` 事件,不走服务对象。
133
+
134
+ 完整契约(导出清单、最小示例、生命周期、类型说明)见 [docs/consumer-api.md](docs/consumer-api.md)。
135
+
109
136
  ## 文档
110
137
 
111
138
  | 文档 | 内容 |
112
139
  |---|---|
113
- | [docs/install.md](docs/install.md) | profile 安装 / git 安装 / 卸载 / `--dump-config` 验证 |
140
+ | [docs/install.md](docs/install.md) | profile 安装 / registry 安装 / 卸载 / `--dump-config` 验证 |
141
+ | [docs/release.md](docs/release.md) | 发布流程:Trusted Publishing 前置、Release prep SOP、fragment 格式、回滚 |
114
142
  | [docs/configuration.md](docs/configuration.md) | `fallbacks` 命名空间全字段、selector 语法、示例 YAML、插件配置卡使用、行为说明 |
143
+ | [docs/consumer-api.md](docs/consumer-api.md) | 开发者消费契约:导出清单、最小示例、生命周期、类型说明 |
115
144
  | [docs/verification.md](docs/verification.md) | 验证记录(测试矩阵、bundle 层序、运行契约、QA gate 剧本) |
116
145
 
117
146
  ## 许可
@@ -74,13 +74,13 @@ export type ConversationFallbackSwitchProps = PropsRuntime<'conversation.chat.no
74
74
  * Render one fallback switch as a compact system-style transcript line.
75
75
  *
76
76
  * Geometry follows the upstream chat system rows (the compaction boundary
77
- * notice: dim title + separator + ellipsized summary — `chat/MessageItem
78
- * .module.css:38-122`); every color resolves through a `--dsw-alias-*`
79
- * token. A reason outside the current union renders raw (forward-compatible
77
+ * notice: warning-toned title + separator + ellipsized summary —
78
+ * `chat/MessageItem .module.css:38-122`); every color resolves through a
79
+ * `--dsw-alias-*` token. A reason outside the current union renders raw (forward-compatible
80
80
  * durable log, same rule as the card/general row summaries). A malformed or
81
81
  * partial payload (version skew) degrades to the title-only line instead of
82
- * throwing during interpolation — the transcript slot stays visible with a
83
- * truthful "a switch happened" notice and no summary details.
82
+ * throwing during interpolation — the transcript slot stays visible with the
83
+ * warning-toned "model downgraded" title (T1 copy) and no summary details.
84
84
  * @param props - composed keyed seat props.
85
85
  * @returns the switch line element tree.
86
86
  */
@@ -26,8 +26,9 @@
26
26
  * `roles.rules`, whose role field is a dropdown bound to the declared ids
27
27
  * + the built-in `inherit`, same-page live). Saving runs `validateDraft`
28
28
  * first — id format/reserved word/duplicates, undeclared rule role
29
- * references, and illegal selectors block the write with a validation
30
- * banner + inline red borders (never touching the store error path); a
29
+ * references, illegal selectors, and a role with no chain entries (no
30
+ * model config) block the write with a validation banner + inline red
31
+ * borders / hints (never touching the store error path); a
31
32
  * non-empty `state.legacyKeys` renders the migration banner at the top of
32
33
  * the card body. The row editors keep their filled editorCard surface
33
34
  * inside the card, with `--dsw-alias-*` tokens throughout. The reset-