dsh-llm-fallbacks 0.1.0-alpha.1
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/LICENSE +21 -0
- package/README.md +124 -0
- package/README.zh-CN.md +119 -0
- package/bundle/cordis.patch.yml +19 -0
- package/dist/chains.d.ts +167 -0
- package/dist/client/ConversationFallbackSwitch.d.ts +87 -0
- package/dist/client/FallbacksCard.d.ts +86 -0
- package/dist/client/GeneralFallbacksRow.d.ts +19 -0
- package/dist/client/fallbacks-store.d.ts +379 -0
- package/dist/client/index.d.ts +56 -0
- package/dist/client/index.js +3916 -0
- package/dist/client/locales.d.ts +281 -0
- package/dist/client/switch-guard.d.ts +17 -0
- package/dist/commands.d.ts +176 -0
- package/dist/config.d.ts +136 -0
- package/dist/cooldown.d.ts +48 -0
- package/dist/events.d.ts +36 -0
- package/dist/gateway.d.ts +176 -0
- package/dist/index.d.ts +62 -0
- package/dist/index.js +1853 -0
- package/dist/roles.d.ts +70 -0
- package/dist/selectors.d.ts +35 -0
- package/dist/state.d.ts +112 -0
- package/package.json +91 -0
- package/scripts/build-client.ts +374 -0
- package/scripts/verify-dist.mjs +68 -0
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
import type { PropsLocale, PropsRuntime } from '@deepseek-ai/dsh-client-ui-slots';
|
|
3
|
+
import type { SnapshotSelectorHook } from '@deepseek-ai/dsh-client-web-react';
|
|
4
|
+
import type { FallbacksSettingsController, FallbacksSettingsState } from './fallbacks-store.ts';
|
|
5
|
+
/** Injected dependencies of {@link GeneralFallbacksRow} (slot `inject`). */
|
|
6
|
+
export interface GeneralFallbacksRowInjected {
|
|
7
|
+
/** The shared controller (loaded on first mount, refreshed on pushed invalidations). */
|
|
8
|
+
controller: FallbacksSettingsController;
|
|
9
|
+
/** uSES subscription hook bound to the store (inject face — advisor pattern). */
|
|
10
|
+
useSnapshot: SnapshotSelectorHook<FallbacksSettingsState>;
|
|
11
|
+
}
|
|
12
|
+
/** Props delivered by the slot outlet: runtime share + locale seat + inject face. */
|
|
13
|
+
export type GeneralFallbacksRowProps = PropsRuntime<'settings.general.item'> & PropsLocale<'fallbacks'> & GeneralFallbacksRowInjected;
|
|
14
|
+
/**
|
|
15
|
+
* Render the Fallbacks status row.
|
|
16
|
+
* @param props - composed slot props.
|
|
17
|
+
* @returns the row element tree.
|
|
18
|
+
*/
|
|
19
|
+
export declare function GeneralFallbacksRow({ controller, useSnapshot, t }: GeneralFallbacksRowProps): ReactNode;
|
|
@@ -0,0 +1,379 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fallbacks settings controller — the client half's own store (slot owner
|
|
3
|
+
* props are empty; data rides this store, per the `settings.plugin.item`
|
|
4
|
+
* card contract).
|
|
5
|
+
*
|
|
6
|
+
* Read path: the fallbacks config rides the plugin's own gateway channel —
|
|
7
|
+
* `connection.rpc.call('/api', 'fallbacks/get', { args: {} })` — NOT the
|
|
8
|
+
* apiproxy wire: after the settings-exposure patches are gone the
|
|
9
|
+
* `fallbacks` namespace is absent from `settings.describe` on every host
|
|
10
|
+
* (like `advisor` is). `settings.describe({})` is still called, but only
|
|
11
|
+
* for the top-level `writable` flag (host read-only mode) and the namespace
|
|
12
|
+
* directory (the configured-provider join reads model-provider namespaces).
|
|
13
|
+
* A `get` that does not resolve (transport down / gateway not ready / no
|
|
14
|
+
* settings service on the host) is NOT a page error — `state.present` goes
|
|
15
|
+
* false and the section keeps the usable defaults skeleton (KD-G5).
|
|
16
|
+
*
|
|
17
|
+
* Write path: `save(next)` → `rpc.call('/api', 'fallbacks/set', { args: {
|
|
18
|
+
* patch: next } })` (the full edited config is the patch — a merge with all
|
|
19
|
+
* keys present is a full overwrite); `resetToDefaults()` →
|
|
20
|
+
* `rpc.call('/api', 'fallbacks/reset', { args: {} })` (the host clears the
|
|
21
|
+
* user layer via `settings.replace(ns, {})` — the removal path a merge
|
|
22
|
+
* cannot express). The gateway channel has NO revision guard: any
|
|
23
|
+
* `set`/`reset` failure (business rejection or transport) surfaces its
|
|
24
|
+
* message in `state.error` for the section's error banner (KD-G3 — the old
|
|
25
|
+
* `settings-conflict` branch is gone).
|
|
26
|
+
*/
|
|
27
|
+
import type { ClientConnectionRpc, ConfigurableProviderView, HistoryEntry, IApiClient, ModelProviderGroup, SessionId, SettingsNamespaceView } from '@deepseek-ai/dsh-client-connection/client';
|
|
28
|
+
import { type SnapshotStore } from '@deepseek-ai/dsh-client-runtime/client';
|
|
29
|
+
import { type FallbackStrategy, type FallbacksConfig, type FallbacksRole, type FallbacksRoleRule, type FallbacksRoles } from '../config.ts';
|
|
30
|
+
import type { FallbacksSwitchEventData } from '../events.ts';
|
|
31
|
+
/** The plugin's settings namespace on the host wire (settings/document-updated ns filter). */
|
|
32
|
+
export declare const FALLBACKS_SETTINGS_NS = "fallbacks";
|
|
33
|
+
/** Single-page history read for the status block (spec §2.5 D-5: `HISTORY_PAGE_MESSAGES`-sized). */
|
|
34
|
+
export declare const SWITCHES_HISTORY_PAGE = 50;
|
|
35
|
+
/** How many recent switches the status block renders (spec §2.5 D-5: N=5). */
|
|
36
|
+
export declare const RECENT_SWITCH_LIMIT = 5;
|
|
37
|
+
/**
|
|
38
|
+
* One recent `fallbacks/switch` event as the status block renders it: the
|
|
39
|
+
* durable payload plus the raw event's ordering key and time (the payload
|
|
40
|
+
* itself carries no seq/time — spec §5 table).
|
|
41
|
+
*/
|
|
42
|
+
export interface FallbacksSwitchSnapshot extends FallbacksSwitchEventData {
|
|
43
|
+
/** Event seq within the session (newest-first ordering key). */
|
|
44
|
+
seq: number;
|
|
45
|
+
/** Event time, Unix epoch milliseconds. */
|
|
46
|
+
time: number;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* The status block's derived "current effective model" (spec §2.5 D-6) — a
|
|
50
|
+
* **display value** derived from configuration + recent switches, never a
|
|
51
|
+
* live route probe.
|
|
52
|
+
*/
|
|
53
|
+
export type EffectiveModelView =
|
|
54
|
+
/** ① `enabled: false` or an empty rootChain. */
|
|
55
|
+
{
|
|
56
|
+
kind: 'unavailable';
|
|
57
|
+
}
|
|
58
|
+
/** ② The most recent switch's target (`to`). */
|
|
59
|
+
| {
|
|
60
|
+
kind: 'switched';
|
|
61
|
+
provider: string;
|
|
62
|
+
model: string;
|
|
63
|
+
}
|
|
64
|
+
/** ③ No switches yet: the config's primary target (first chain entry). */
|
|
65
|
+
| {
|
|
66
|
+
kind: 'config';
|
|
67
|
+
provider: string;
|
|
68
|
+
model: string;
|
|
69
|
+
};
|
|
70
|
+
/** Fallbacks settings-row snapshot. */
|
|
71
|
+
export interface FallbacksSettingsState {
|
|
72
|
+
status: 'idle' | 'loading' | 'ready' | 'saving' | 'error';
|
|
73
|
+
error: string | null;
|
|
74
|
+
/** Whether the provider allows writes at all (describe top-level flag). */
|
|
75
|
+
writable: boolean;
|
|
76
|
+
/** The resolved configuration (last accepted gateway response, or the defaults skeleton). */
|
|
77
|
+
config: FallbacksConfig;
|
|
78
|
+
/**
|
|
79
|
+
* Whether the `fallbacks/get` gateway channel resolved on the last load.
|
|
80
|
+
* `false` = channel unreachable (transport down / gateway not ready / no
|
|
81
|
+
* settings service) → the section keeps the usable skeleton (KD-G5).
|
|
82
|
+
*/
|
|
83
|
+
present: boolean;
|
|
84
|
+
/**
|
|
85
|
+
* Legacy (two-block-era) config keys the gateway detected on the composed
|
|
86
|
+
* source (`get().legacyKeys` / the post-write `set`/`reset` response,
|
|
87
|
+
* spec §9): non-empty → the migration banner renders. The wire field is
|
|
88
|
+
* authoritative — the client never guesses legacy status on its own
|
|
89
|
+
* (detectLegacyClientKeys is a test-only fallback). A `set`/`reset`
|
|
90
|
+
* response WITHOUT the field (older gateway) keeps the last accepted
|
|
91
|
+
* value — only a `get` may settle legacy truth (W-1/F-1: a save merges
|
|
92
|
+
* over the user layer, so it cannot delete legacy keys).
|
|
93
|
+
*/
|
|
94
|
+
legacyKeys: string[];
|
|
95
|
+
/** Provider/model directory snapshot (spec §2.5 D-4). */
|
|
96
|
+
catalogStatus: 'idle' | 'loading' | 'ready' | 'error';
|
|
97
|
+
/** Catalog read diagnostic: whole-load failure or per-provider lookups. */
|
|
98
|
+
catalogError: string | null;
|
|
99
|
+
/** Configurable-provider directory (`llm.providers`). */
|
|
100
|
+
providers: ConfigurableProviderView[];
|
|
101
|
+
/**
|
|
102
|
+
* The provider dropdown's offer set: catalog providers whose settings
|
|
103
|
+
* profile resolves, with the Models page's `configured` join semantics
|
|
104
|
+
* (spec §2.5 — see {@link configuredProvidersOf}). Unconfigured directory
|
|
105
|
+
* providers never appear as options.
|
|
106
|
+
*/
|
|
107
|
+
configuredProviders: ConfigurableProviderView[];
|
|
108
|
+
/** Model catalog groups (`llm.models`). */
|
|
109
|
+
groups: ModelProviderGroup[];
|
|
110
|
+
/** Bumped on every accepted catalog read; drives row re-classification. */
|
|
111
|
+
catalogEpoch: number;
|
|
112
|
+
/** Recent-switch summary (spec §2.4 R-4a / §2.5 D-5). */
|
|
113
|
+
switchesStatus: 'idle' | 'loading' | 'ready' | 'error';
|
|
114
|
+
/** Switch-read diagnostic (wire message); null when none. */
|
|
115
|
+
switchesError: string | null;
|
|
116
|
+
/** Most recent `fallbacks/switch` events of the current session, newest first. */
|
|
117
|
+
switches: FallbacksSwitchSnapshot[];
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* The provider dropdown's offer set (spec §2.5 D-4): catalog providers whose
|
|
121
|
+
* settings profile resolves in the describe namespaces — the Models page's
|
|
122
|
+
* `configured` predicate (`ui-models` store.ts): a provider is configured
|
|
123
|
+
* when its settings namespace exists AND either it addresses the whole
|
|
124
|
+
* section (`settingsPath` empty) or its profile path resolves in the resolved
|
|
125
|
+
* value. Directory-only (unconfigured) providers never become options; the
|
|
126
|
+
* section still renders existing values for them (read-back + annotation) so
|
|
127
|
+
* nothing is lost on save.
|
|
128
|
+
*/
|
|
129
|
+
export declare function configuredProvidersOf(providers: readonly ConfigurableProviderView[], namespaces: ReadonlyMap<string, SettingsNamespaceView>): ConfigurableProviderView[];
|
|
130
|
+
/**
|
|
131
|
+
* Fold the redacted descriptor value into a complete {@link FallbacksConfig}:
|
|
132
|
+
* missing optional fields take spec §4 defaults; gross type mismatches throw
|
|
133
|
+
* so the UI can surface a broken descriptor instead of mis-rendering.
|
|
134
|
+
*/
|
|
135
|
+
export declare function parseFallbacksConfig(value: unknown): FallbacksConfig;
|
|
136
|
+
/**
|
|
137
|
+
* Row-level selection state of one provider/model cell (spec §2.5 D-3):
|
|
138
|
+
* a catalog id, an out-of-catalog raw value read back from the server, or
|
|
139
|
+
* nothing (empty / "any"). Serialization always writes the raw string, so an
|
|
140
|
+
* outside value is preserved verbatim — round-trip lossless.
|
|
141
|
+
*/
|
|
142
|
+
export type CatalogSelection = {
|
|
143
|
+
kind: 'catalog';
|
|
144
|
+
id: string;
|
|
145
|
+
} | {
|
|
146
|
+
kind: 'outside';
|
|
147
|
+
raw: string;
|
|
148
|
+
} | null;
|
|
149
|
+
/** The catalog faces row conversions classify raw values against (D-4). */
|
|
150
|
+
export interface CatalogLookup {
|
|
151
|
+
providers: readonly ConfigurableProviderView[];
|
|
152
|
+
groups: readonly ModelProviderGroup[];
|
|
153
|
+
}
|
|
154
|
+
/** The raw selector string a selection serializes to ('' when empty). */
|
|
155
|
+
export declare function selectionToRaw(selection: CatalogSelection): string;
|
|
156
|
+
/**
|
|
157
|
+
* Classify a raw provider value against the catalog: a catalog route id is a
|
|
158
|
+
* catalog selection, anything else is an outside value kept verbatim.
|
|
159
|
+
*/
|
|
160
|
+
export declare function classifyProvider(raw: string, catalog: CatalogLookup | undefined): CatalogSelection;
|
|
161
|
+
/**
|
|
162
|
+
* Classify a raw model value under its provider against the catalog: a model
|
|
163
|
+
* id advertised by that provider is a catalog selection, anything else is an
|
|
164
|
+
* outside value kept verbatim.
|
|
165
|
+
*/
|
|
166
|
+
export declare function classifyModel(provider: string, raw: string, catalog: CatalogLookup | undefined): CatalogSelection;
|
|
167
|
+
/**
|
|
168
|
+
* Extract the most recent `fallbacks/switch` events from one history page
|
|
169
|
+
* (spec §2.5 D-5): filter by event type, order by `seq` descending, take at
|
|
170
|
+
* most `limit`. Single-page read — fewer than `limit` events show as-is; no
|
|
171
|
+
* multi-page backfill (Non-Goal).
|
|
172
|
+
*/
|
|
173
|
+
export declare function extractRecentSwitches(entries: readonly HistoryEntry[], limit?: number): FallbacksSwitchSnapshot[];
|
|
174
|
+
/**
|
|
175
|
+
* Derive the status block's "current effective model" (spec §2.5 D-6): ①
|
|
176
|
+
* disabled / empty rootChain → unavailable; ② a recent switch exists → the
|
|
177
|
+
* latest one's `to`; ③ otherwise → the config's primary target. A **display
|
|
178
|
+
* value** — never a live route probe (the section appends the non-probing
|
|
179
|
+
* note inline right after the derived value, available case only; the
|
|
180
|
+
* unavailable 空态 renders its own copy without the note).
|
|
181
|
+
*/
|
|
182
|
+
export declare function deriveEffectiveModel(config: FallbacksConfig, switches: readonly FallbacksSwitchSnapshot[]): EffectiveModelView;
|
|
183
|
+
/** One chain selector row: provider + model (or wildcard). */
|
|
184
|
+
export interface ChainSelectorRow {
|
|
185
|
+
/** `provider/*` wildcard entry: the model part is absent. */
|
|
186
|
+
wildcard: boolean;
|
|
187
|
+
provider: CatalogSelection;
|
|
188
|
+
/** Null when wildcard (or the entry carries no model part). */
|
|
189
|
+
model: CatalogSelection;
|
|
190
|
+
}
|
|
191
|
+
/** Serialize one selector row to its wire string (`provider/model` | `provider/*`). */
|
|
192
|
+
export declare function selectorRowToRaw(row: ChainSelectorRow): string;
|
|
193
|
+
/**
|
|
194
|
+
* One rootChain row in the editor: the root agent's single fallback chain
|
|
195
|
+
* (block 1 of the two-block model) as an ordered selector list. There is no
|
|
196
|
+
* key input — the row IS the chain.
|
|
197
|
+
*/
|
|
198
|
+
export interface RootChainRow {
|
|
199
|
+
selectors: ChainSelectorRow[];
|
|
200
|
+
}
|
|
201
|
+
/** Project the rootChain entries into editable rows (one flat chain row). */
|
|
202
|
+
export declare function rootChainToRows(rootChain: readonly string[], catalog?: CatalogLookup): RootChainRow[];
|
|
203
|
+
/** Rebuild the rootChain from edited rows; rows with no usable selector drop out. */
|
|
204
|
+
export declare function rowsToRootChain(rows: readonly RootChainRow[]): string[];
|
|
205
|
+
/**
|
|
206
|
+
* One declared-role row in the editor (block 2 `roles.list`): identity
|
|
207
|
+
* fields + the role's own chain selector list + its append strategy.
|
|
208
|
+
* `prompt`/`permissions` are schema-reserved for the next iteration
|
|
209
|
+
* (fallbacks-explicit-role-tool) — they never enter row editing this round.
|
|
210
|
+
*/
|
|
211
|
+
export interface RoleRow {
|
|
212
|
+
id: string;
|
|
213
|
+
label: string;
|
|
214
|
+
description: string;
|
|
215
|
+
selectors: ChainSelectorRow[];
|
|
216
|
+
fallback: FallbackStrategy;
|
|
217
|
+
}
|
|
218
|
+
/** Project the declared roles into editable rows (chain selectors classified). */
|
|
219
|
+
export declare function rolesToRows(roles: readonly FallbacksRole[], catalog?: CatalogLookup): RoleRow[];
|
|
220
|
+
/** Rebuild the declared roles from edited rows; empty selectors drop out. */
|
|
221
|
+
export declare function rowsToRoles(rows: readonly RoleRow[]): FallbacksRole[];
|
|
222
|
+
/**
|
|
223
|
+
* Rebuild the declared roles from edited rows, re-attaching the
|
|
224
|
+
* schema-reserved `prompt`/`permissions` fields from the last accepted
|
|
225
|
+
* config by role id — they never round-trip through rows this round, so
|
|
226
|
+
* without the merge a save would silently drop them (T2 reviewer minor
|
|
227
|
+
* #2). The id trim matches {@link rowsToRoles}; a row whose id matches no
|
|
228
|
+
* original role (a freshly added one) keeps no extras. Key order mirrors
|
|
229
|
+
* `parseFallbacksConfig` so a clean draft's JSON dirty comparison never
|
|
230
|
+
* flags it.
|
|
231
|
+
*/
|
|
232
|
+
export declare function mergeRoleExtras(rows: readonly RoleRow[], originalRoles: readonly FallbacksRole[]): FallbacksRole[];
|
|
233
|
+
/**
|
|
234
|
+
* The `roles.rules` role dropdown's offer set — the ONLY data source for the
|
|
235
|
+
* rule rows' role selector: the built-in `'inherit'` target plus every
|
|
236
|
+
* declared `roles.list` id, in declaration order (a role added/removed on
|
|
237
|
+
* the same page is reflected immediately).
|
|
238
|
+
*/
|
|
239
|
+
export declare function ruleRoleOptions(roles: Pick<FallbacksRoles, 'list'>): string[];
|
|
240
|
+
/**
|
|
241
|
+
* Client-side legacy fallback detection (spec §9). The gateway's
|
|
242
|
+
* `legacyKeys` wire field is authoritative for the migration banner; this is
|
|
243
|
+
* a defensive fallback for configs that already passed wire normalization
|
|
244
|
+
* yet still carry a `roles.rules` reference to an undeclared role id — the
|
|
245
|
+
* only two-block-era leftover that can survive the wire (the removed
|
|
246
|
+
* `chains`/`roles.default` keys never ride it).
|
|
247
|
+
*/
|
|
248
|
+
export declare function detectLegacyClientKeys(config: FallbacksConfig): string[];
|
|
249
|
+
/** One role-rule row in the editor; empty origin means "any". */
|
|
250
|
+
export interface RoleRuleRow {
|
|
251
|
+
origin: string;
|
|
252
|
+
provider: CatalogSelection;
|
|
253
|
+
model: CatalogSelection;
|
|
254
|
+
role: string;
|
|
255
|
+
}
|
|
256
|
+
/** Project the role rules into editable rows (provider/model classified). */
|
|
257
|
+
export declare function rulesToRows(rules: readonly FallbacksRoleRule[], catalog?: CatalogLookup): RoleRuleRow[];
|
|
258
|
+
/** Rebuild the role rules from edited rows; empty origin/provider/model drop out. */
|
|
259
|
+
export declare function rowsToRules(rows: readonly RoleRuleRow[]): FallbacksRoleRule[];
|
|
260
|
+
/** Controller joining Settings reads, writes, and pushed invalidations. */
|
|
261
|
+
export declare class FallbacksSettingsController {
|
|
262
|
+
private readonly api;
|
|
263
|
+
private readonly rpc;
|
|
264
|
+
/** Snapshot consumed by the section through `useSyncExternalStore`. */
|
|
265
|
+
readonly store: SnapshotStore<FallbacksSettingsState>;
|
|
266
|
+
private generation;
|
|
267
|
+
private catalogGeneration;
|
|
268
|
+
private switchesGeneration;
|
|
269
|
+
/** Every settings namespace from the last describe, keyed by ns — the configured-provider join's other input. */
|
|
270
|
+
private namespaces;
|
|
271
|
+
private currentSession;
|
|
272
|
+
/**
|
|
273
|
+
* @param api - Settings / Llm / Sessions wire faces (describe `writable` +
|
|
274
|
+
* namespace directory, provider/model catalog, session history).
|
|
275
|
+
* @param rpc - the connection's generic RPC caller for the host gateway
|
|
276
|
+
* channel (`/api`), injected from the connection handle.
|
|
277
|
+
*/
|
|
278
|
+
constructor(api: Pick<IApiClient, 'settings' | 'llm' | 'sessions'>, rpc: ClientConnectionRpc);
|
|
279
|
+
/**
|
|
280
|
+
* Refresh the page snapshot. Latest request wins. `settings.describe`
|
|
281
|
+
* still runs — it supplies the top-level `writable` flag (host read-only
|
|
282
|
+
* mode) and the namespace directory (the configured-provider join's other
|
|
283
|
+
* input) — but the fallbacks config itself rides the gateway channel:
|
|
284
|
+
* `rpc.call('/api', 'fallbacks/get', { args: {} })`. The two reads are
|
|
285
|
+
* independent and run in PARALLEL (Promise.all — one round trip per
|
|
286
|
+
* refresh, not two). The `fallbacks` namespace is NOT expected in describe
|
|
287
|
+
* anymore (it is off the apiproxy boundary post-patch); a describe failure
|
|
288
|
+
* remains a hard `error` (the form cannot render provider/model options
|
|
289
|
+
* without the directory), while a get failure is NOT a page error —
|
|
290
|
+
* `present` goes false and the section keeps the usable skeleton (KD-G5).
|
|
291
|
+
* @returns nothing; {@link store} carries success or failure.
|
|
292
|
+
*/
|
|
293
|
+
load(): Promise<void>;
|
|
294
|
+
/**
|
|
295
|
+
* Refresh the provider/model catalog (`llm.providers` + `llm.models`), an
|
|
296
|
+
* independent read path with its own generation guard so it can run
|
|
297
|
+
* parallel to {@link load} without clobbering it (spec §2.5 D-4).
|
|
298
|
+
* Per-provider lookup failures ride `catalogError` as a diagnostic without
|
|
299
|
+
* failing the sound groups; a whole-load failure lands `catalogStatus:
|
|
300
|
+
* 'error'` and never blocks the rest of the form.
|
|
301
|
+
* @returns nothing; {@link store} carries success or failure.
|
|
302
|
+
*/
|
|
303
|
+
loadCatalog(): Promise<void>;
|
|
304
|
+
/**
|
|
305
|
+
* Record the current session the status block reads (spec §2.5 D-5). Once
|
|
306
|
+
* the block has been read once, its summary follows session switches
|
|
307
|
+
* immediately; an idle block only records the id — the section's mount
|
|
308
|
+
* effect performs the first read.
|
|
309
|
+
* @param sessionId - the session whose history is summarized; undefined
|
|
310
|
+
* (no current session) resolves to the empty state.
|
|
311
|
+
*/
|
|
312
|
+
setCurrentSession(sessionId: SessionId | undefined): void;
|
|
313
|
+
/**
|
|
314
|
+
* Read the recent-switch summary for the current session (spec §2.5 D-5):
|
|
315
|
+
* one `sessions.history` page (`maxMessages` = {@link SWITCHES_HISTORY_PAGE}),
|
|
316
|
+
* `fallbacks/switch` events extracted newest-first capped at
|
|
317
|
+
* {@link RECENT_SWITCH_LIMIT}. No current session → honest empty ready
|
|
318
|
+
* state (no RPC); a read failure lands `switchesStatus: 'error'` and never
|
|
319
|
+
* touches the settings state (the form keeps editing/saving normally).
|
|
320
|
+
* @returns nothing; {@link store} carries success or failure.
|
|
321
|
+
*/
|
|
322
|
+
loadSwitches(): Promise<void>;
|
|
323
|
+
/**
|
|
324
|
+
* Persist the full edited configuration through the gateway channel
|
|
325
|
+
* (`/api/fallbacks/set`). The full config is sent as a MERGE patch (guide
|
|
326
|
+
* §9) — keys the new schema cannot express (legacy `chains` /
|
|
327
|
+
* `roles.default` in the user layer) survive the write, which is why the
|
|
328
|
+
* gateway returns POST-WRITE `legacyKeys` and the banner stays honest
|
|
329
|
+
* (W-1/F-1). The merge has no revision guard: any failure (business
|
|
330
|
+
* rejection or transport) surfaces its message in `state.error` for the
|
|
331
|
+
* section's error banner and the form stays editable for retry (KD-G3).
|
|
332
|
+
* @param next - the complete edited configuration.
|
|
333
|
+
*/
|
|
334
|
+
save(next: FallbacksConfig): Promise<void>;
|
|
335
|
+
/**
|
|
336
|
+
* Reset to composition defaults through the gateway channel
|
|
337
|
+
* (`/api/fallbacks/reset` — the fallbacks-specific third method; the host
|
|
338
|
+
* clears the user layer via `settings.replace(ns, {})`, the removal path a
|
|
339
|
+
* merge cannot express). Same error handling as {@link save} (KD-G3).
|
|
340
|
+
*/
|
|
341
|
+
resetToDefaults(): Promise<void>;
|
|
342
|
+
/** Stop in-flight responses from publishing after plugin disposal. */
|
|
343
|
+
dispose(): void;
|
|
344
|
+
/**
|
|
345
|
+
* Publish a settled load: `status` ready, `writable` from describe, and —
|
|
346
|
+
* only when the gateway returned a REAL config — `present` true and
|
|
347
|
+
* `state.config` replaced with the parsed value. A get that did not
|
|
348
|
+
* resolve (`config === undefined`) lands `present` false and keeps the
|
|
349
|
+
* last accepted config (the defaults skeleton on a first load) — the
|
|
350
|
+
* draft seed invariant (I-1): a transient channel-down must never seed
|
|
351
|
+
* the form with defaults over real server truth. `legacyKeys` rides the
|
|
352
|
+
* same publish: the wire field drives the migration banner. save/reset
|
|
353
|
+
* pass the POST-WRITE value (W-1/F-1) — or the previous value when the
|
|
354
|
+
* response omits the field, so a write can never clear the banner
|
|
355
|
+
* against server truth; only a real `get` may.
|
|
356
|
+
*/
|
|
357
|
+
private accept;
|
|
358
|
+
private fail;
|
|
359
|
+
}
|
|
360
|
+
/**
|
|
361
|
+
* Refetch after reconnect / settings change only when the section has already
|
|
362
|
+
* opened once.
|
|
363
|
+
* @param controller - the fallbacks settings controller.
|
|
364
|
+
*/
|
|
365
|
+
export declare function refreshFallbacksIfLoaded(controller: FallbacksSettingsController): void;
|
|
366
|
+
/**
|
|
367
|
+
* Refetch the catalog after `llm/adapters-updated` only when it has already
|
|
368
|
+
* been opened once (the catalog twin of {@link refreshFallbacksIfLoaded}).
|
|
369
|
+
* @param controller - the fallbacks settings controller.
|
|
370
|
+
*/
|
|
371
|
+
export declare function refreshCatalogIfLoaded(controller: FallbacksSettingsController): void;
|
|
372
|
+
/**
|
|
373
|
+
* Refetch the recent-switch summary after `settings/document-updated`
|
|
374
|
+
* (fallbacks ns) / `connection/reset` only when the status block has already
|
|
375
|
+
* been read once
|
|
376
|
+
* (the switches twin of {@link refreshFallbacksIfLoaded}).
|
|
377
|
+
* @param controller - the fallbacks settings controller.
|
|
378
|
+
*/
|
|
379
|
+
export declare function refreshSwitchesIfLoaded(controller: FallbacksSettingsController): void;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* dsh-llm-fallbacks client half: registers the Fallbacks card into the
|
|
3
|
+
* plugin-config page's `settings.plugin.item` slot (the official "插件配置"
|
|
4
|
+
* settings page — id `fallbacks`, order 30, alongside the upstream bash /
|
|
5
|
+
* agent-loop / web-search cards and the advisor card).
|
|
6
|
+
*
|
|
7
|
+
* Wiring (mirrors dsh-advisor):
|
|
8
|
+
* - Registers the `fallbacks` locale dictionaries (zh/en).
|
|
9
|
+
* - Constructs the card's own store over the connection: the fallbacks
|
|
10
|
+
* config rides the plugin's gateway channel (`connection.rpc` →
|
|
11
|
+
* `/api/fallbacks/get|set|reset`), while `settings.describe` (writable +
|
|
12
|
+
* namespace directory) and the provider/model catalog stay on
|
|
13
|
+
* `connection.api` (see `fallbacks-store.ts`).
|
|
14
|
+
* - Registers the `settings.plugin.item` card `id: 'fallbacks'` (order 30)
|
|
15
|
+
* with a business-only inject face ({@link FallbacksSettingsController} +
|
|
16
|
+
* the snapshot-selector hook); the old Settings-nav section registration
|
|
17
|
+
* is removed — deleting the section registration deletes the nav entry.
|
|
18
|
+
* - Refreshes the store on pushed invalidations — the forwarded remote
|
|
19
|
+
* events `settings/document-updated` (ns-filtered to the fallbacks
|
|
20
|
+
* namespace; refetches the descriptor + recent-switch summary) and
|
|
21
|
+
* `llm/adapters-updated` (refetches only the provider/model catalog), plus
|
|
22
|
+
* the client `connection/reset` (refetches all three) — and follows the
|
|
23
|
+
* current session (`sessions.list`) so the status block's recent-switch
|
|
24
|
+
* summary tracks the session being viewed (spec §2.5 D-5). `sessions` is
|
|
25
|
+
* an optional reflection read (S-g): a host without the session service
|
|
26
|
+
* leaves the switches face in its empty ready state.
|
|
27
|
+
*
|
|
28
|
+
* @module dsh-llm-fallbacks/client
|
|
29
|
+
*/
|
|
30
|
+
import type { ClientContext } from '@deepseek-ai/dsh-client-runtime/client';
|
|
31
|
+
export type { FallbacksCardInjected, FallbacksCardProps } from './FallbacksCard.tsx';
|
|
32
|
+
export type { GeneralFallbacksRowInjected, GeneralFallbacksRowProps } from './GeneralFallbacksRow.tsx';
|
|
33
|
+
export type { ConversationFallbackSwitchProps, FallbacksSwitchChatData, } from './ConversationFallbackSwitch.tsx';
|
|
34
|
+
export type { FallbacksSettingsState } from './fallbacks-store.ts';
|
|
35
|
+
export { FallbacksSettingsController, FALLBACKS_SETTINGS_NS } from './fallbacks-store.ts';
|
|
36
|
+
/**
|
|
37
|
+
* Required services (cordis fiber inject); registrations wait on the slot
|
|
38
|
+
* declaration. `conversationEvents` is declared because the D1 Definition
|
|
39
|
+
* registration reads the service directly (`ctx.conversationEvents.register`
|
|
40
|
+
* at the bottom of `apply` — explicit fiber-ordering parity with the
|
|
41
|
+
* ui-workflow-run precedent, whose inject list includes it for the same
|
|
42
|
+
* direct read). The runtime would still provide the service synchronously
|
|
43
|
+
* on apply, but the declaration makes the dependency honest. `sessions` is
|
|
44
|
+
* deliberately NOT injected (S-g): a non-web host without the dsh-session
|
|
45
|
+
* client service must not hang the fiber waiting for it — the wiring reads
|
|
46
|
+
* it reflectively and degrades to the switches empty state when absent
|
|
47
|
+
* (`setCurrentSession` never called, `loadSwitches` ready with an empty
|
|
48
|
+
* array, which the store already supports).
|
|
49
|
+
*/
|
|
50
|
+
export declare const inject: string[];
|
|
51
|
+
/**
|
|
52
|
+
* Register the `fallbacks` dictionaries and the plugin-config card once the
|
|
53
|
+
* `settings.plugin.item` declaration is on the ledger.
|
|
54
|
+
* @param ctx - client root context.
|
|
55
|
+
*/
|
|
56
|
+
export declare function apply(ctx: ClientContext): void;
|