dsh-llm-fallbacks 0.7.0 → 0.8.0
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 +27 -27
- package/README.zh-CN.md +25 -25
- package/dist/chain-walk.d.ts +63 -77
- package/dist/chains.d.ts +32 -101
- package/dist/client/FallbacksCard.d.ts +27 -80
- package/dist/client/fallbacks-store.d.ts +71 -225
- package/dist/client/index.d.ts +0 -1
- package/dist/client/index.js +1256 -1926
- package/dist/client/locales.d.ts +59 -105
- package/dist/commands.d.ts +68 -103
- package/dist/config.d.ts +152 -105
- package/dist/gateway.d.ts +63 -109
- package/dist/index.d.ts +3 -25
- package/dist/index.js +552 -775
- package/dist/role-resolution.d.ts +14 -43
- package/dist/schema.d.ts +6 -5
- package/dist/seeds.d.ts +5 -7
- package/dist/state.d.ts +0 -42
- package/dist/subagents-seam.d.ts +23 -45
- package/dist/time-slots.d.ts +21 -24
- package/dist/tui-settings.d.ts +5 -8
- package/dist/virtual-adapter.d.ts +63 -108
- package/locale/en.json +1 -1
- package/locale/zh.json +1 -1
- package/package.json +1 -1
- package/dist/client/GeneralFallbacksRow.d.ts +0 -19
- package/dist/roles.d.ts +0 -89
- package/dist/route-allowlist.d.ts +0 -43
- package/dist/subagent-policy.d.ts +0 -137
package/dist/chains.d.ts
CHANGED
|
@@ -1,30 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Fallback chain resolution
|
|
2
|
+
* Fallback chain resolution: candidate resolution over ONE chain's effective
|
|
3
|
+
* entries (named virtual chains, plan named-virtual-chains T2).
|
|
3
4
|
*
|
|
4
|
-
* `resolveChain`
|
|
5
|
-
* (provider, model).
|
|
6
|
-
* `
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
* it is the legal no-rule-match role, not a typo'd id. A truly undeclared
|
|
11
|
-
* role id (defense) resolves to `rootChain` alone + one warn. Chain-key
|
|
12
|
-
* specificity lookup (`exact` / `provider/*` / role / `default` keys) is
|
|
13
|
-
* deleted — the two-block config model has no chain keys.
|
|
14
|
-
*
|
|
15
|
-
* Wildcard entries (`provider/*`) are resolved against the failing model —
|
|
16
|
-
* keep the model id, swap only the provider; the "target provider has no
|
|
17
|
-
* such model id" skip is judged by {@link resolveCandidate} (via
|
|
18
|
-
* `modelExists`) or by the caller's filter.
|
|
19
|
-
*
|
|
20
|
-
* The concatenation itself lives in ONE helper — {@link roleChainEntries}
|
|
21
|
-
* (qc1 S-3 SSOT) — shared by {@link resolveChainViews} and
|
|
22
|
-
* {@link hasWildcardEntry}, so the wildcard probe is exact (qc2 F-003:
|
|
23
|
-
* `fallback: 'none'` excludes `rootChain`) and can never diverge from the
|
|
24
|
-
* resolution. Defensive warns (unknown role / undeclared rule target) go
|
|
25
|
-
* through an injected `warn` callback — the wiring passes the cordis
|
|
26
|
-
* `logger.warn` (qc2 F-002 / qc3 S-3), with `console.warn` as the
|
|
27
|
-
* direct-call default.
|
|
5
|
+
* `resolveChainViews` / `resolveChain` walk the chain's entries ONCE and
|
|
6
|
+
* resolve each against the failing (provider, model). Wildcard entries
|
|
7
|
+
* (`provider/*`) keep the model id and swap only the provider; the "target
|
|
8
|
+
* provider has no such model id" skip is judged by {@link resolveCandidate}
|
|
9
|
+
* (via `modelExists`) or by the caller's filter — applied to wildcard-origin
|
|
10
|
+
* candidates ONLY ({@link selectCandidates}).
|
|
28
11
|
*
|
|
29
12
|
* Cooldown / failed-set / same-as-current filtering is caller-side;
|
|
30
13
|
* {@link createCandidateFilter} provides the ready-made predicate. A
|
|
@@ -33,9 +16,8 @@
|
|
|
33
16
|
* than the failing model's cannot fit the request either
|
|
34
17
|
* ({@link fitsContextWindow}; unknown windows keep the candidate).
|
|
35
18
|
*
|
|
36
|
-
|
|
19
|
+
@module dsh-llm-fallbacks/chains
|
|
37
20
|
*/
|
|
38
|
-
import { type FallbacksRole } from './config.ts';
|
|
39
21
|
import type { CooldownStore } from './cooldown.ts';
|
|
40
22
|
import { type Selector } from './selectors.ts';
|
|
41
23
|
/** The model that just failed — the anchor for chain resolution. */
|
|
@@ -56,42 +38,16 @@ export interface FailingModel {
|
|
|
56
38
|
*/
|
|
57
39
|
export declare function resolveCandidate(entry: string, failing: FailingModel, modelExists?: (provider: string, model: string) => boolean): Selector | null;
|
|
58
40
|
/**
|
|
59
|
-
*
|
|
60
|
-
*
|
|
61
|
-
*
|
|
62
|
-
*
|
|
63
|
-
*
|
|
64
|
-
*
|
|
65
|
-
*
|
|
66
|
-
*
|
|
67
|
-
* compared by trim (qc2 F-001 — the runtime canonicalizes padded declared
|
|
68
|
-
* ids, and `resolveRole` returns the declared raw id).
|
|
69
|
-
*
|
|
70
|
-
* Exported for the chain walk's head anchor (`src/chain-walk.ts`): the walk
|
|
71
|
-
* resolves the FIRST DISPATCHABLE exact entry over these same entries, so the
|
|
72
|
-
* head it starts at is the head the candidate walk below it starts from.
|
|
73
|
-
*/
|
|
74
|
-
export declare function roleChainEntries(roles: readonly FallbacksRole[], rootChain: readonly string[], role: string): readonly string[];
|
|
75
|
-
/**
|
|
76
|
-
* Single-pass chain resolution for the decision path (T1 review Important
|
|
77
|
-
* #2). Walks the role's concatenated entries ONCE and returns the unfiltered
|
|
78
|
-
* view — `all` (every resolvable candidate, no filter and no existence
|
|
79
|
-
* probe: the caller's early-exit / annotation view) — plus the parallel
|
|
80
|
-
* `wildcard` provenance (`wildcard[i]` = candidate `all[i]` came from a
|
|
81
|
-
* `provider/*` entry). The caller builds the existence probe from `all` and
|
|
82
|
-
* then derives the surviving view with {@link selectCandidates}, so the
|
|
83
|
-
* decision path never resolves the chain twice (and an unknown role warns
|
|
84
|
-
* at most once per decision).
|
|
85
|
-
*
|
|
86
|
-
* The reserved built-in `inherit` id (INHERIT_ROLE_ID) is legal — it
|
|
87
|
-
* resolves to `rootChain` silently (the no-rule-match role, not a typo'd
|
|
88
|
-
* id). Only a truly undeclared id (∉ declared ids ∪ {'inherit'}) warns once
|
|
89
|
-
* (defensive — never crashes) through `warn` (defaults to `console.warn`
|
|
90
|
-
* for direct-call compatibility; the decision path injects the cordis
|
|
91
|
-
* `logger.warn` — qc2 F-002 / qc3 S-3). Malformed entries never become
|
|
92
|
-
* candidates.
|
|
41
|
+
* Single-pass chain resolution over one chain's entries. Walks `entries` ONCE
|
|
42
|
+
* and returns the unfiltered view — `all` (every resolvable candidate, no
|
|
43
|
+
* filter and no existence probe: the caller's early-exit / annotation view) —
|
|
44
|
+
* plus the parallel `wildcard` provenance (`wildcard[i]` = candidate `all[i]`
|
|
45
|
+
* came from a `provider/*` entry). The caller builds the existence probe from
|
|
46
|
+
* `all` and then derives the surviving view with {@link selectCandidates}, so
|
|
47
|
+
* the decision path never resolves the chain twice. Malformed entries never
|
|
48
|
+
* become candidates.
|
|
93
49
|
*/
|
|
94
|
-
export declare function resolveChainViews(
|
|
50
|
+
export declare function resolveChainViews(entries: readonly string[], provider: string, model: string, warn?: (message: string) => void): {
|
|
95
51
|
all: Selector[];
|
|
96
52
|
wildcard: boolean[];
|
|
97
53
|
};
|
|
@@ -105,46 +61,24 @@ export declare function resolveChainViews(roles: readonly FallbacksRole[], rootC
|
|
|
105
61
|
*/
|
|
106
62
|
export declare function selectCandidates(all: readonly Selector[], wildcard: readonly boolean[], filter?: (candidate: Selector) => boolean, modelExists?: (provider: string, model: string) => boolean): Selector[];
|
|
107
63
|
/**
|
|
108
|
-
* Ordered fallback candidates for the failing (provider, model)
|
|
109
|
-
*
|
|
110
|
-
*
|
|
111
|
-
*
|
|
112
|
-
*
|
|
113
|
-
*
|
|
114
|
-
* reserved built-in `inherit` id resolves to `rootChain` silently; a truly
|
|
115
|
-
* undeclared/unknown `role` id resolves to `rootChain` alone and warns once
|
|
116
|
-
* (defensive — never crashes). `filter` optionally drops candidates — the
|
|
117
|
-
* caller owns cooldown/failed-set/same-model filtering (see
|
|
118
|
-
* {@link createCandidateFilter}). The `modelExists` existence probe is NOT
|
|
119
|
-
* applied per entry here: {@link resolveChainViews} returns the parallel
|
|
120
|
-
* `wildcard` provenance, and {@link selectCandidates} applies `modelExists`
|
|
121
|
-
* to `provider/*`-origin candidates ONLY (qc1 S-2 — exact entries are never
|
|
122
|
-
* existence-filtered, spec §2 clause 2 / T2 review Important #1
|
|
123
|
-
* decision-path contract). `warn` forwards to {@link resolveChainViews}
|
|
124
|
-
* (defaults to `console.warn`; the decision path injects `logger.warn`).
|
|
64
|
+
* Ordered fallback candidates for the failing (provider, model), over ONE
|
|
65
|
+
* chain's `entries`. `filter` optionally drops candidates — the caller owns
|
|
66
|
+
* cooldown/failed-set/same-model filtering (see {@link createCandidateFilter}).
|
|
67
|
+
* The `modelExists` existence probe is applied by {@link selectCandidates} to
|
|
68
|
+
* `provider/*`-origin candidates ONLY (exact entries are never
|
|
69
|
+
* existence-filtered). `warn` forwards to {@link resolveChainViews}.
|
|
125
70
|
*
|
|
126
71
|
* Single-pass: delegates to {@link resolveChainViews} + {@link selectCandidates}
|
|
127
|
-
* (one
|
|
72
|
+
* (one entry walk).
|
|
128
73
|
*/
|
|
129
|
-
export declare function resolveChain(
|
|
74
|
+
export declare function resolveChain(entries: readonly string[], provider: string, model: string, filter?: (candidate: Selector) => boolean, modelExists?: (provider: string, model: string) => boolean, warn?: (message: string) => void): Selector[];
|
|
130
75
|
/**
|
|
131
|
-
* Whether any entry of
|
|
132
|
-
*
|
|
133
|
-
*
|
|
134
|
-
*
|
|
135
|
-
* `resolveChain` walks to decide whether the catalog existence probe is
|
|
136
|
-
* needed at all.
|
|
137
|
-
*
|
|
138
|
-
* The probe walks {@link roleChainEntries} — the SAME concatenation
|
|
139
|
-
* {@link resolveChainViews} resolves (qc1 S-3 single SSOT) — so it is
|
|
140
|
-
* exact, never an over-approximation (qc2 F-003 / qc3 S-1): for
|
|
141
|
-
* `fallback: 'none'` roles `rootChain` is excluded, and a wildcard that can
|
|
142
|
-
* never reach the candidate list never builds a catalog probe. No
|
|
143
|
-
* false-negative is possible: any wildcard the resolution could reach is on
|
|
144
|
-
* this concatenation by construction. Malformed entries never become
|
|
145
|
-
* candidates and are skipped.
|
|
76
|
+
* Whether any entry of `entries` is a wildcard (`provider/*`). The decision
|
|
77
|
+
* path consults this to decide whether the catalog existence probe is needed
|
|
78
|
+
* at all — a wildcard that can never reach the candidate list never builds a
|
|
79
|
+
* catalog probe. Malformed entries never become candidates and are skipped.
|
|
146
80
|
*/
|
|
147
|
-
export declare function hasWildcardEntry(
|
|
81
|
+
export declare function hasWildcardEntry(entries: readonly string[]): boolean;
|
|
148
82
|
/** Inputs for {@link createCandidateFilter}. */
|
|
149
83
|
export interface CandidateFilterOptions {
|
|
150
84
|
/** The currently active (failing) model — skipped as "same as current". */
|
|
@@ -179,11 +113,8 @@ export declare function createCandidateFilter(options: CandidateFilterOptions):
|
|
|
179
113
|
* 行为可见性). `context-window` is the `CONTEXT_WINDOW_EXCEEDED` walk's
|
|
180
114
|
* exclusion: the candidate's disclosed window is not larger than the failing
|
|
181
115
|
* model's, so the request that just overflowed cannot fit there either.
|
|
182
|
-
* `allowlist` is the subagent-policy exclusion: the candidate survived every
|
|
183
|
-
* filter but sits outside the host allowlist, so a plugin-originated walk may
|
|
184
|
-
* not switch to it. The walk owns that label — the policy read lives there.
|
|
185
116
|
*/
|
|
186
|
-
export type CandidateSkipReason = 'same-as-current' | 'cooldown' | 'step-failed' | 'context-window' | 'missing-id'
|
|
117
|
+
export type CandidateSkipReason = 'same-as-current' | 'cooldown' | 'step-failed' | 'context-window' | 'missing-id';
|
|
187
118
|
/** One entry of the ordered, per-candidate annotation (T3 review Minor 1). */
|
|
188
119
|
export interface AnnotatedCandidate {
|
|
189
120
|
candidate: Selector;
|
|
@@ -1,83 +1,32 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Fallbacks settings card — the `fallbacks` plugin card on the web
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
* the upstream bash/agent-loop/web-search cards and the advisor card, in
|
|
6
|
-
* registration order); owner props are empty and all data flows
|
|
7
|
-
* through {@link FallbacksSettingsController}.
|
|
2
|
+
* Fallbacks settings card — the `fallbacks` plugin card on the web Plugins
|
|
3
|
+
* page (named virtual chains, plan named-virtual-chains T5; the FROZEN UI
|
|
4
|
+
* mockup `.mstar/design/named-virtual-chains/settings-mockup.html`).
|
|
8
5
|
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
* headings. The card is ALWAYS open —
|
|
20
|
-
* nothing needs card-level disclosure state; the degraded /
|
|
21
|
-
* error / read-only / migration notices render flat atop the form (the
|
|
22
|
-
* unavailable notice stays always-visible per KD-G5 — the documented
|
|
23
|
-
* divergence from the advisor, whose unavailable card renders nothing: the
|
|
24
|
-
* fallbacks skeleton stays the USABLE last-known form and saves are
|
|
25
|
-
* attempted).
|
|
6
|
+
* Flat form vocabulary unchanged: fields at 12px vertical padding with 0.5px
|
|
7
|
+
* hairline separators, 34px inputs on the 0.5px l4 border, per-section
|
|
8
|
+
* Discard + Save pairs. The 虚拟链 group is TAB-PER-CHAIN: underline tabs on
|
|
9
|
+
* the 0.5px l2 hairline (active label = label-primary + 2px brand underline,
|
|
10
|
+
* dirty pip, error "!" mark), a "+" add affordance and a "⋯" chain menu
|
|
11
|
+
* (delete, ≥1 chain), WAI-ARIA tabs with roving tabindex.
|
|
12
|
+
* Each tab body carries 链名称 (the single label editor — the ⋯ menu binds to
|
|
13
|
+
* the same draft field) followed by the SHIPPED block order 分时槽设置 →
|
|
14
|
+
* 默认降级链 → 默认模型(链尾) plus a per-tab Discard/Save writing ONLY that
|
|
15
|
+
* chain (block ids per chain, error text under the owning block).
|
|
26
16
|
*
|
|
27
|
-
* The
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
17
|
+
* The 子代理 section is role cards: id + persona + 指定降级链 (a MANUAL
|
|
18
|
+
* named-chain pointer; 未指定(沿用 dsh 默认) = the plugin does not
|
|
19
|
+
* intervene). No rules, no per-role chain entries, no host-policy block.
|
|
20
|
+
* The 高级选项 group is unchanged; the 运行状态(只读) block and the
|
|
21
|
+
* General settings row are REMOVED with the client switch-history read.
|
|
31
22
|
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
* bottom Save outweighed it. Each section's Save writes ONLY that section's
|
|
36
|
-
* fields (patch = the last ACCEPTED config with the section's fields
|
|
37
|
-
* replaced — the ride-along protection, PR #62 UX round 3), gated by that
|
|
38
|
-
* section's dirty term and validation bucket only (KD-U1: save =
|
|
39
|
-
* `!sectionDirty || saving || !writable`, discard = `!sectionDirty ||
|
|
40
|
-
* saving`; Save additionally carries `!writable` — W-1, qc2 fix wave: the
|
|
41
|
-
* dirty-implies-writable assumption does not hold for this in-place-draft
|
|
42
|
-
* store). Violations render live under their OWNING section heading, and a
|
|
43
|
-
* store write failure renders under the section whose Save was last
|
|
44
|
-
* clicked (`lastSaveSection`). Discard is kept — our staged edits survive
|
|
45
|
-
* refresh, the advisor's documented divergence from the official
|
|
46
|
-
* no-discard form — a pure client-side revert of THAT section's editors to
|
|
47
|
-
* the last accepted config.
|
|
23
|
+
* Validation blocks the owning save only: chain id format/duplicates,
|
|
24
|
+
* missing label, per-chain slot guards, tail conformance, role id checks.
|
|
25
|
+
* A non-empty `state.legacyKeys` renders the migration banner at the top.
|
|
48
26
|
*
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
*
|
|
52
|
-
* and the roles block (block 2 — declared role entity cards from
|
|
53
|
-
* `roles.list` plus the rule rows from `roles.rules`, whose role field is a
|
|
54
|
-
* dropdown bound to the declared ids + the built-in `inherit`, same-page
|
|
55
|
-
* live). Row-level disclosures that are CONTENT keep their expand/collapse:
|
|
56
|
-
* the time-slot row cards and the role entity cards (with the seeded
|
|
57
|
-
* persona briefs) stay collapsible — a read-only view forces them open so
|
|
58
|
-
* the configs stay reachable. The 主代理 / 子代理 / 高级选项 group labels
|
|
59
|
-
* are semantic `<h2>` headings (T1); 高级选项 is a content-level disclosure
|
|
60
|
-
* collapsed by default (T3 — same expand/collapse contract as the rows, a
|
|
61
|
-
* read-only view forces it open).
|
|
62
|
-
*
|
|
63
|
-
* Validation: id format/reserved word/duplicates, undeclared rule role
|
|
64
|
-
* references, illegal selectors, and a role with no chain entries (no model
|
|
65
|
-
* config) block the write (the Save disabled gate) with per-section banners
|
|
66
|
-
* + inline red borders / hints (never touching the store error path); a
|
|
67
|
-
* non-empty `state.legacyKeys` renders the migration banner at the top.
|
|
68
|
-
* The reset-to-defaults affordance is GONE from the card (PR #62 UX
|
|
69
|
-
* round 3) — the gateway RPC `fallbacks/reset` and the store
|
|
70
|
-
* `resetToDefaults()` stay as host APIs, only the card UI was removed.
|
|
71
|
-
*
|
|
72
|
-
* The AC-7 read-only status block (recent-switch summary, D-5) stays at the
|
|
73
|
-
* bottom, flat.
|
|
74
|
-
*
|
|
75
|
-
* Presentation is ui-primitives-free (T4, advisor parity + reference §4
|
|
76
|
-
* risk): Button/Tooltip and the five icon imports are replaced by
|
|
77
|
-
* self-drawn styled elements — inline SVG icons (plus / trash / chevron /
|
|
78
|
-
* grip) and the CSS `data-tip` tooltip bubble (the card's existing
|
|
79
|
-
* icon-button pattern); every color resolves through a `--dsw-alias-*`
|
|
80
|
-
* token so the card adapts to the light/dark theme.
|
|
27
|
+
* Presentation stays ui-primitives-free: inline SVG icons and the CSS
|
|
28
|
+
* `data-tip` tooltip bubble; every color resolves through a
|
|
29
|
+
* `--dsw-alias-*` token (light/dark parity).
|
|
81
30
|
*/
|
|
82
31
|
import type { ReactNode } from 'react';
|
|
83
32
|
import type { InjectFace, PropsLocale, PropsRuntime } from '@deepseek-ai/dsh-client-ui-slots';
|
|
@@ -94,10 +43,8 @@ export interface FallbacksCardInjected {
|
|
|
94
43
|
/** Props delivered by the slot outlet: runtime share + locale seat + inject face. */
|
|
95
44
|
export type FallbacksCardProps = PropsRuntime<'plugins.bundle.config'> & PropsLocale<'fallbacks'> & InjectFace<FallbacksCardInjected>;
|
|
96
45
|
/**
|
|
97
|
-
* Render the Fallbacks settings card inside the plugin-config section
|
|
98
|
-
*
|
|
99
|
-
* the page's plugin title/description
|
|
100
|
-
* @param props - slot-delivered injected dependencies and the synthesized t seat.
|
|
101
|
-
* @returns the card.
|
|
46
|
+
* Render the Fallbacks settings card inside the plugin-config section
|
|
47
|
+
* (named virtual chains): the 虚拟链 tab group, the 子代理 role cards and
|
|
48
|
+
* the 高级选项 group, flat under the page's plugin title/description.
|
|
102
49
|
*/
|
|
103
50
|
export declare function FallbacksCard({ controller, useSnapshot, t }: FallbacksCardProps): ReactNode;
|