dsh-llm-fallbacks 0.6.13 → 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 +34 -30
- package/README.zh-CN.md +32 -28
- package/dist/chain-walk.d.ts +197 -0
- package/dist/chains.d.ts +35 -82
- 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 +1332 -2110
- package/dist/client/locales.d.ts +61 -117
- package/dist/commands.d.ts +70 -112
- package/dist/config.d.ts +152 -117
- package/dist/cooldown.d.ts +1 -15
- package/dist/events.d.ts +8 -8
- package/dist/gateway.d.ts +66 -110
- package/dist/index.d.ts +21 -64
- package/dist/index.js +900 -1313
- package/dist/role-resolution.d.ts +15 -83
- package/dist/schema.d.ts +6 -5
- package/dist/seeds.d.ts +5 -7
- package/dist/state.d.ts +15 -141
- package/dist/subagents-seam.d.ts +51 -14
- package/dist/time-slots.d.ts +21 -24
- package/dist/tui-settings.d.ts +5 -6
- package/dist/virtual-adapter.d.ts +70 -119
- package/docs/DETAIL.md +1 -0
- package/docs/DETAIL.zh.md +1 -0
- package/docs/preview.svg +47 -0
- package/docs/preview.zh.svg +47 -0
- package/locale/en.json +2 -1
- package/locale/zh.json +2 -1
- package/package.json +29 -25
- package/dist/authorized-route.d.ts +0 -68
- package/dist/automatch.d.ts +0 -98
- package/dist/client/GeneralFallbacksRow.d.ts +0 -19
- package/dist/override.d.ts +0 -39
- package/dist/roles.d.ts +0 -90
- package/dist/route-allowlist.d.ts +0 -43
- package/dist/subagent-policy.d.ts +0 -123
|
@@ -1,67 +1,38 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Virtual `FallbacksChain
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* dsh-TUI (web and TUI share the adapter catalog).
|
|
2
|
+
* Virtual `FallbacksChain` LLM adapter (named virtual chains, plan
|
|
3
|
+
* named-virtual-chains T2): one provider carrying N model rows — ONE per
|
|
4
|
+
* named chain, the row id BEING the chain id (picker selection is
|
|
5
|
+
* `FallbacksChain/<chain id>`), without patching dsh or dsh-TUI.
|
|
7
6
|
*
|
|
8
|
-
* Wiring
|
|
7
|
+
* Wiring: `installFallbacksAdapter` installs ONE conditional
|
|
9
8
|
* `ctx.inject(['llm'])` child — absent `llm` service (test harness) is a
|
|
10
9
|
* clean no-op, and fiber unload ⇒ the child's disposer unregisters the
|
|
11
10
|
* route. Registration is an idempotent transition-reconcile on COMMITTED
|
|
12
|
-
* config snapshots: register when
|
|
13
|
-
* (`isFallbackActive`
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
* all-day). The registration gate is `isFallbackActive` content presence
|
|
20
|
-
* (`rootChain` / `timeSlots` / declared roles): a slot-row edit that flips
|
|
21
|
-
* that gate (e.g. removing the only slot while `rootChain` and roles are
|
|
22
|
-
* empty) intentionally churns registration — the content-presence contract
|
|
23
|
-
* (plan fallbacks-web-ux-alignment T2), not churn to design away; do NOT
|
|
24
|
-
* re-narrow the condition to ignore `timeSlots`. Conformance-only chain
|
|
25
|
-
* edits still never churn (conformance gates the delegate, not the row).
|
|
11
|
+
* config snapshots: register when `chains` goes empty → non-empty
|
|
12
|
+
* (`isFallbackActive` = `chains.length > 0`), unregister on the reverse,
|
|
13
|
+
* driven by the settings `onChange` hook (the returned reconcile thunk,
|
|
14
|
+
* wired by `apply()`) plus child activation. A chain with empty or
|
|
15
|
+
* non-conforming `entries` still shows its row (conformance gates the
|
|
16
|
+
* delegate via {@link effectiveHeadOf}, not the row). One
|
|
17
|
+
* `llm.registerAdapter([FALLBACKS_PROVIDER], adapter)` call serves all rows.
|
|
26
18
|
*
|
|
27
|
-
* Adapter behavior
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
* `
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
* policy and the token meter — also never throwing.
|
|
19
|
+
* Adapter behavior: `listModels` advertises one row per chain;
|
|
20
|
+
* `stream()` WALKS the selected chain (cooldown / failed-set / switch cap /
|
|
21
|
+
* recovery bookkeeping) in `src/chain-walk.ts` — the walk is injected at
|
|
22
|
+
* install and owns the pre-attempt guards. `resolveModel` /
|
|
23
|
+
* `imageRequestPricing` resolve the chain FROM the `model` argument and
|
|
24
|
+
* follow its effective head (permissive default otherwise — never throw).
|
|
25
|
+
* `providerRetryPolicy` returns `undefined` (documented degradation): the
|
|
26
|
+
* host captures the policy ONCE per provider at registration, so the virtual
|
|
27
|
+
* route cannot mirror a per-chain head's policy — the host default applies.
|
|
37
28
|
*
|
|
38
|
-
|
|
29
|
+
@module dsh-llm-fallbacks/virtual-adapter
|
|
39
30
|
*/
|
|
40
31
|
import type { Context } from '@deepseek-ai/cordis';
|
|
41
32
|
import { LlmAdapter, type GenerateOptions, type LlmImageRequestPricing, type LlmModelInfo, type LlmResolvedModelInfo, type LlmRuntime, type ResolvedRetryPolicy, type StreamChunk } from '@deepseek-ai/dsh-llm';
|
|
42
|
-
import { type FallbacksConfig } from './config.ts';
|
|
33
|
+
import { type FallbacksConfig, type NamedChain } from './config.ts';
|
|
43
34
|
/** Provider route of the virtual adapter (exact string, spec lock). */
|
|
44
35
|
export declare const FALLBACKS_PROVIDER = "FallbacksChain";
|
|
45
|
-
/**
|
|
46
|
-
* Model id of the virtual catalog row (exact string, spec lock). "Auto" is
|
|
47
|
-
* the hardcoded picker id (not i18n — user decision 2026-08-18). The
|
|
48
|
-
* catalog `name` the host picker renders is dynamic — see
|
|
49
|
-
* {@link pickerDisplayName} (`Auto: <model>[<slot>]`).
|
|
50
|
-
*/
|
|
51
|
-
export declare const FALLBACKS_CHAIN_MODEL = "Auto";
|
|
52
|
-
/**
|
|
53
|
-
* `LlmError` code: the effective chain is empty — the virtual route has no
|
|
54
|
-
* head to delegate to (P1 guard).
|
|
55
|
-
*/
|
|
56
|
-
export declare const EMPTY_EFFECTIVE_CHAIN_CODE = "EMPTY_EFFECTIVE_CHAIN";
|
|
57
|
-
/**
|
|
58
|
-
* `LlmError` code: the effective chain head is not a dispatchable real pair
|
|
59
|
-
* (non-conforming all-day, wildcard selector, malformed selector, or a
|
|
60
|
-
* self-route back to `FallbacksChain/*` — the P1 recursion guard).
|
|
61
|
-
*/
|
|
62
|
-
export declare const UNDISPATCHABLE_HEAD_CODE = "UNDISPATCHABLE_EFFECTIVE_HEAD";
|
|
63
|
-
/** `LlmError` code (defensive): the `llm` runtime disappeared mid-flight. */
|
|
64
|
-
export declare const LLM_UNAVAILABLE_CODE = "LLM_UNAVAILABLE";
|
|
65
36
|
/** One dispatchable exact head: `provider/model`. Wildcards are never seeds (P3). */
|
|
66
37
|
export interface EffectiveHead {
|
|
67
38
|
provider: string;
|
|
@@ -69,10 +40,10 @@ export interface EffectiveHead {
|
|
|
69
40
|
}
|
|
70
41
|
/**
|
|
71
42
|
* The FIRST DISPATCHABLE exact head of a chain — the single definition of
|
|
72
|
-
* "effective head" (F-001) shared by
|
|
73
|
-
*
|
|
74
|
-
* `src/
|
|
75
|
-
* skipping entries that can never
|
|
43
|
+
* "effective head" (F-001) shared by this module's metadata paths
|
|
44
|
+
* (`pickerDisplayName` / `resolveModel` / `imageRequestPricing`) and the
|
|
45
|
+
* walk's head resolution (`resolveWalk` in `src/chain-walk.ts`). Walks the
|
|
46
|
+
* SAME chain `resolveEffectiveChain` produces, skipping entries that can never
|
|
76
47
|
* be dispatched: malformed selectors (config-warning path), `provider/*`
|
|
77
48
|
* `provider/*` wildcards (no real pair), and self-routes back to
|
|
78
49
|
* `FallbacksChain/*` (the P1 recursion guard). `undefined` when the chain
|
|
@@ -80,91 +51,69 @@ export interface EffectiveHead {
|
|
|
80
51
|
*/
|
|
81
52
|
export declare function firstDispatchableExactHead(chain: readonly string[]): EffectiveHead | undefined;
|
|
82
53
|
/**
|
|
83
|
-
* The effective chain head at `now
|
|
84
|
-
* of the SAME `resolveEffectiveChain` the
|
|
85
|
-
*
|
|
86
|
-
*
|
|
87
|
-
* entry is dispatchable (wildcard,
|
|
88
|
-
* malformed selector).
|
|
89
|
-
*
|
|
90
|
-
*
|
|
91
|
-
* conforming (exactly one official model — Flash or Pro)
|
|
92
|
-
* for a successful delegate —
|
|
93
|
-
* a legacy multi-model (or empty) all-day chain earns no primary
|
|
94
|
-
* semantics even though the picker row is visible. `resolveModel` then
|
|
95
|
-
* falls back to the permissive default and `stream()` throws
|
|
96
|
-
* {@link UNDISPATCHABLE_HEAD_CODE}.
|
|
54
|
+
* The effective chain head of ONE named chain at `now`: the first
|
|
55
|
+
* DISPATCHABLE exact head of the SAME `resolveEffectiveChain` the walk uses —
|
|
56
|
+
* thin chain+clock entry into the shared {@link firstDispatchableExactHead}.
|
|
57
|
+
* `undefined` when the entries are empty or non-conforming (the tail must be
|
|
58
|
+
* exactly one official model), or no entry is dispatchable (wildcard,
|
|
59
|
+
* self-route to `FallbacksChain/*`, malformed selector). `resolveModel` then
|
|
60
|
+
* falls back to the permissive default; the delegate side of the conformance
|
|
61
|
+
* gate is the chain walk's `UNDISPATCHABLE_EFFECTIVE_HEAD`.
|
|
97
62
|
*/
|
|
98
|
-
export declare function effectiveHeadOf(
|
|
63
|
+
export declare function effectiveHeadOf(chain: NamedChain, now: Date, tz?: string): EffectiveHead | undefined;
|
|
99
64
|
/**
|
|
100
|
-
* Host picker label:
|
|
101
|
-
*
|
|
102
|
-
*
|
|
103
|
-
* there is no dispatchable head. Slot label from {@link resolveSlotState}.
|
|
104
|
-
* @param modelDisplayName - catalog/resolved name; falls back to the id.
|
|
65
|
+
* Host picker label for one chain: `` `${chain.label}: <head>[<slot>]` ``.
|
|
66
|
+
* Bare `chain.label` when there is no dispatchable head. The label is
|
|
67
|
+
* user-editable and display-only; the model id is the chain id.
|
|
105
68
|
*/
|
|
106
|
-
export declare function pickerDisplayName(
|
|
69
|
+
export declare function pickerDisplayName(chain: NamedChain, now?: Date, modelDisplayName?: string, tz?: string): string;
|
|
107
70
|
/**
|
|
108
|
-
* The virtual adapter (P1/P3). `stream()`
|
|
109
|
-
*
|
|
110
|
-
* or state writes live here — those stay in the `agent/request` /
|
|
111
|
-
* `agent/request-error` listeners. Exported so the defensive guard paths
|
|
112
|
-
* the registration lifecycle cannot reach (a registered route whose `llm`
|
|
113
|
-
* vanished mid-teardown) stay unit-testable by direct construction.
|
|
71
|
+
* The virtual adapter (P1/P3). `stream()` hands the call to the injected walk
|
|
72
|
+
* (see `src/chain-walk.ts`) — registration metadata stays here.
|
|
114
73
|
*/
|
|
115
74
|
export declare class FallbacksChainAdapter extends LlmAdapter {
|
|
116
75
|
private readonly readConfig;
|
|
117
76
|
private readonly getLlm;
|
|
118
|
-
|
|
77
|
+
private readonly walk;
|
|
78
|
+
constructor(readConfig: () => FallbacksConfig, getLlm: () => LlmRuntime | undefined, walk: (options: GenerateOptions) => AsyncIterable<StreamChunk>);
|
|
119
79
|
/** Minimal honest descriptor (P3) — the provider route IS the display name. */
|
|
120
80
|
providerInfo(provider: string): {
|
|
121
81
|
id: string;
|
|
122
82
|
name: string;
|
|
123
83
|
};
|
|
124
|
-
/** Advisory catalog:
|
|
84
|
+
/** Advisory catalog: ONE row per named chain; `name` is the live picker label. */
|
|
125
85
|
listModels(provider: string): Promise<readonly LlmModelInfo[]>;
|
|
126
86
|
/**
|
|
127
|
-
*
|
|
128
|
-
*
|
|
129
|
-
*
|
|
87
|
+
* Model-scoped metadata: resolve the chain FROM the `model` argument (the
|
|
88
|
+
* chain id) and follow its effective head — modalities/context-window/
|
|
89
|
+
* reasoning follow the head, the truthful answer for the CURRENT head.
|
|
90
|
+
* Permissive default for an unknown chain id or an unresolvable head;
|
|
91
|
+
* never throws.
|
|
130
92
|
*/
|
|
131
93
|
resolveModel(provider: string, model: string, signal?: AbortSignal): Promise<LlmResolvedModelInfo>;
|
|
132
94
|
/**
|
|
133
|
-
*
|
|
134
|
-
*
|
|
135
|
-
*
|
|
136
|
-
*
|
|
137
|
-
*
|
|
138
|
-
* (e.g. a user's `llm-deepseek.retryPolicy`, including `mode: 'always'`)
|
|
139
|
-
* keeps retries behaving exactly as they do on the head `stream()`
|
|
140
|
-
* dispatches. Never throws: an unresolvable head, a vanished `llm`, or an
|
|
141
|
-
* unregistered head provider degrades to `undefined` — the host's own
|
|
142
|
-
* default. That last arm matters: the runtime's lookup THROWS `NO_ADAPTER`
|
|
143
|
-
* for an unknown provider, and this call happens inside the plugin's
|
|
144
|
-
* `registerAdapter`, so an escaping throw would take the whole virtual
|
|
145
|
-
* route down instead of just degrading its policy.
|
|
95
|
+
* DOCUMENTED DEGRADATION (named virtual chains): the adapter stays ONE
|
|
96
|
+
* `FallbacksChain` provider carrying N chain rows, but the host captures
|
|
97
|
+
* `adapter.providerRetryPolicy(provider)` ONCE per provider at
|
|
98
|
+
* registration, so the virtual route can no longer mirror its head's
|
|
99
|
+
* retry policy. It returns `undefined` — the host's own default applies.
|
|
146
100
|
*/
|
|
147
101
|
providerRetryPolicy(_provider: string): ResolvedRetryPolicy | undefined;
|
|
148
102
|
/**
|
|
149
|
-
*
|
|
150
|
-
*
|
|
151
|
-
*
|
|
152
|
-
*
|
|
153
|
-
*
|
|
154
|
-
* (including `undefined`). Never throws: an unresolvable head, a
|
|
155
|
-
* vanished `llm`, or a throwing delegate degrades to `undefined` — the
|
|
156
|
-
* token meter's neutral estimate.
|
|
103
|
+
* Image pricing, model-scoped: resolve the chain FROM the `model`
|
|
104
|
+
* argument and delegate through the runtime lookup for its effective head
|
|
105
|
+
* (including `undefined`). Never throws: an unknown chain id, an
|
|
106
|
+
* unresolvable head, a vanished `llm`, or a throwing delegate degrades to
|
|
107
|
+
* `undefined` — the token meter's neutral estimate.
|
|
157
108
|
*/
|
|
158
|
-
imageRequestPricing(_provider: string,
|
|
109
|
+
imageRequestPricing(_provider: string, model: string): LlmImageRequestPricing | undefined;
|
|
159
110
|
/**
|
|
160
|
-
*
|
|
161
|
-
*
|
|
162
|
-
* `
|
|
163
|
-
*
|
|
164
|
-
*
|
|
165
|
-
*
|
|
166
|
-
* documented listener-order degradation stays graceful instead of a hard
|
|
167
|
-
* outage.
|
|
111
|
+
* The virtual route's entry point: `options.model` IS the chain id and the
|
|
112
|
+
* selected chain is WALKED (`src/chain-walk.ts`) — the walk owns the
|
|
113
|
+
* pre-attempt guards (`UNKNOWN_CHAIN` / `EMPTY_EFFECTIVE_CHAIN` /
|
|
114
|
+
* `UNDISPATCHABLE_EFFECTIVE_HEAD` / `LLM_UNAVAILABLE`, thrown synchronously
|
|
115
|
+
* before any chunk, so the runtime normalizes them exactly like an adapter
|
|
116
|
+
* throw).
|
|
168
117
|
*/
|
|
169
118
|
stream(options: GenerateOptions): AsyncIterable<StreamChunk>;
|
|
170
119
|
}
|
|
@@ -174,7 +123,9 @@ export declare class FallbacksChainAdapter extends LlmAdapter {
|
|
|
174
123
|
* @param ctx - the plugin context.
|
|
175
124
|
* @param readConfig - live config reader (the same `source()` the runtime
|
|
176
125
|
* reads, so reconcile always sees COMMITTED composed snapshots).
|
|
126
|
+
* @param walk - the chain walk the adapter's `stream()` runs for one virtual
|
|
127
|
+
* call (built by `apply()` over its live state — see `src/chain-walk.ts`).
|
|
177
128
|
* @returns the reconcile thunk — call it from the settings `onChange` hook
|
|
178
129
|
* (child activation runs one reconcile on its own).
|
|
179
130
|
*/
|
|
180
|
-
export declare function installFallbacksAdapter(ctx: Context, readConfig: () => FallbacksConfig): () => void;
|
|
131
|
+
export declare function installFallbacksAdapter(ctx: Context, readConfig: () => FallbacksConfig, walk: (options: GenerateOptions) => AsyncIterable<StreamChunk>): () => void;
|
package/docs/DETAIL.md
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+

|
|
@@ -0,0 +1 @@
|
|
|
1
|
+

|