dsh-llm-fallbacks 0.2.2 → 0.3.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.
@@ -41,15 +41,61 @@ export declare const zh: {
41
41
  'roleAutoMatch.hint': string;
42
42
  'roleAutoMatch.tooltip': string;
43
43
  'rootChain.label': string;
44
- 'rootChain.firstLine': string;
45
- 'rootChain.hint': string;
46
44
  'rootChain.tooltip': string;
47
- 'rootChain.selector.add': string;
45
+ 'defaultModel.label': string;
48
46
  'chains.selector.remove': string;
49
47
  'chains.selector.providerPlaceholder': string;
50
48
  'chains.selector.modelPlaceholder': string;
51
49
  'chains.selector.wildcardLegacy': string;
52
50
  'chains.selector.noModelsStrict': string;
51
+ 'mainAgent.label': string;
52
+ 'subagents.label': string;
53
+ 'timeSlots.label': string;
54
+ 'timeSlots.hint': string;
55
+ 'timeSlots.tz.label': string;
56
+ 'timeSlots.drag': string;
57
+ 'timeSlots.name': string;
58
+ 'timeSlots.expand': string;
59
+ 'timeSlots.collapse': string;
60
+ 'timeSlots.tooltip': string;
61
+ 'timeSlots.addPreset': string;
62
+ 'timeSlots.addCustom': string;
63
+ 'timeSlots.presetPlaceholder': string;
64
+ 'timeSlots.remove': string;
65
+ 'timeSlots.moveUp': string;
66
+ 'timeSlots.moveDown': string;
67
+ 'timeSlots.start': string;
68
+ 'timeSlots.end': string;
69
+ 'timeSlots.days': string;
70
+ 'timeSlots.days.hint': string;
71
+ 'timeSlots.preset.name': string;
72
+ 'timeSlots.preset.windowLabel': string;
73
+ 'timeSlots.preset.chainsOnly': string;
74
+ 'timeSlots.preset.liang-peak.label': string;
75
+ 'timeSlots.preset.liang-peak.window': string;
76
+ 'timeSlots.preset.liang-valley.label': string;
77
+ 'timeSlots.preset.liang-valley.window': string;
78
+ 'timeSlots.preset.glm-peak.label': string;
79
+ 'timeSlots.preset.glm-peak.window': string;
80
+ 'timeSlots.preset.glm-valley.label': string;
81
+ 'timeSlots.preset.glm-valley.window': string;
82
+ 'timeSlots.preset.glm.note': string;
83
+ 'timeSlots.preset.highCost': string;
84
+ 'timeSlots.preset.multiplier': string;
85
+ 'timeSlots.active': string;
86
+ 'timeSlots.preset.glm.unconfigured': string;
87
+ 'timeSlots.day.sun': string;
88
+ 'timeSlots.day.mon': string;
89
+ 'timeSlots.day.tue': string;
90
+ 'timeSlots.day.wed': string;
91
+ 'timeSlots.day.thu': string;
92
+ 'timeSlots.day.fri': string;
93
+ 'timeSlots.day.sat': string;
94
+ 'timeSlots.selector.add': string;
95
+ 'allDay.hint': string;
96
+ 'allDay.flash': string;
97
+ 'allDay.pro': string;
98
+ 'allDay.nonconforming': string;
53
99
  'roles.list.label': string;
54
100
  'roles.list.hint': string;
55
101
  'roles.list.tooltip': string;
@@ -67,14 +113,12 @@ export declare const zh: {
67
113
  'roles.fallback.none': string;
68
114
  'roles.add': string;
69
115
  'roles.remove': string;
116
+ 'roles.expand': string;
117
+ 'roles.collapse': string;
70
118
  'roles.selector.add': string;
71
119
  'roles.rules': string;
72
120
  'roles.rules.hint': string;
73
121
  'roles.rules.tooltip': string;
74
- 'roles.rule.origin': string;
75
- 'roles.rule.origin.any': string;
76
- 'roles.rule.origin.root': string;
77
- 'roles.rule.origin.subagent': string;
78
122
  'roles.rule.provider': string;
79
123
  'roles.rule.provider.any': string;
80
124
  'roles.rule.model': string;
@@ -92,6 +136,14 @@ export declare const zh: {
92
136
  'validation.ruleRoleUndeclared': string;
93
137
  'validation.ruleRoleRequired': string;
94
138
  'validation.roleChainRequired': string;
139
+ 'validation.allDayRequired': string;
140
+ 'validation.slotChainRequired': string;
141
+ 'validation.slotWindow': string;
142
+ 'validation.slotDays': string;
143
+ 'validation.slotKind': string;
144
+ 'validation.slotPresetUnknown': string;
145
+ 'validation.slotPresetDuplicate': string;
146
+ 'validation.slotPresetFrozen': string;
95
147
  'validation.selector': string;
96
148
  'legacy.banner': string;
97
149
  'catalog.empty': string;
@@ -128,12 +180,6 @@ export declare const zh: {
128
180
  'save.saving': string;
129
181
  'save.error': string;
130
182
  close: string;
131
- reset: string;
132
- 'reset.confirmTitle': string;
133
- 'reset.confirm': string;
134
- 'reset.confirm.cancel': string;
135
- 'reset.confirm.action': string;
136
- 'reset.saving': string;
137
183
  loading: string;
138
184
  unavailable: string;
139
185
  'error.generic': string;
@@ -182,15 +228,61 @@ export declare const en: {
182
228
  'roleAutoMatch.hint': string;
183
229
  'roleAutoMatch.tooltip': string;
184
230
  'rootChain.label': string;
185
- 'rootChain.firstLine': string;
186
- 'rootChain.hint': string;
187
231
  'rootChain.tooltip': string;
188
- 'rootChain.selector.add': string;
232
+ 'defaultModel.label': string;
189
233
  'chains.selector.remove': string;
190
234
  'chains.selector.providerPlaceholder': string;
191
235
  'chains.selector.modelPlaceholder': string;
192
236
  'chains.selector.wildcardLegacy': string;
193
237
  'chains.selector.noModelsStrict': string;
238
+ 'mainAgent.label': string;
239
+ 'subagents.label': string;
240
+ 'timeSlots.label': string;
241
+ 'timeSlots.hint': string;
242
+ 'timeSlots.tz.label': string;
243
+ 'timeSlots.drag': string;
244
+ 'timeSlots.name': string;
245
+ 'timeSlots.expand': string;
246
+ 'timeSlots.collapse': string;
247
+ 'timeSlots.tooltip': string;
248
+ 'timeSlots.addPreset': string;
249
+ 'timeSlots.addCustom': string;
250
+ 'timeSlots.presetPlaceholder': string;
251
+ 'timeSlots.remove': string;
252
+ 'timeSlots.moveUp': string;
253
+ 'timeSlots.moveDown': string;
254
+ 'timeSlots.start': string;
255
+ 'timeSlots.end': string;
256
+ 'timeSlots.days': string;
257
+ 'timeSlots.days.hint': string;
258
+ 'timeSlots.preset.name': string;
259
+ 'timeSlots.preset.windowLabel': string;
260
+ 'timeSlots.preset.chainsOnly': string;
261
+ 'timeSlots.preset.liang-peak.label': string;
262
+ 'timeSlots.preset.liang-peak.window': string;
263
+ 'timeSlots.preset.liang-valley.label': string;
264
+ 'timeSlots.preset.liang-valley.window': string;
265
+ 'timeSlots.preset.glm-peak.label': string;
266
+ 'timeSlots.preset.glm-peak.window': string;
267
+ 'timeSlots.preset.glm-valley.label': string;
268
+ 'timeSlots.preset.glm-valley.window': string;
269
+ 'timeSlots.preset.glm.note': string;
270
+ 'timeSlots.preset.highCost': string;
271
+ 'timeSlots.preset.multiplier': string;
272
+ 'timeSlots.active': string;
273
+ 'timeSlots.preset.glm.unconfigured': string;
274
+ 'timeSlots.day.sun': string;
275
+ 'timeSlots.day.mon': string;
276
+ 'timeSlots.day.tue': string;
277
+ 'timeSlots.day.wed': string;
278
+ 'timeSlots.day.thu': string;
279
+ 'timeSlots.day.fri': string;
280
+ 'timeSlots.day.sat': string;
281
+ 'timeSlots.selector.add': string;
282
+ 'allDay.hint': string;
283
+ 'allDay.flash': string;
284
+ 'allDay.pro': string;
285
+ 'allDay.nonconforming': string;
194
286
  'roles.list.label': string;
195
287
  'roles.list.hint': string;
196
288
  'roles.list.tooltip': string;
@@ -208,14 +300,12 @@ export declare const en: {
208
300
  'roles.fallback.none': string;
209
301
  'roles.add': string;
210
302
  'roles.remove': string;
303
+ 'roles.expand': string;
304
+ 'roles.collapse': string;
211
305
  'roles.selector.add': string;
212
306
  'roles.rules': string;
213
307
  'roles.rules.hint': string;
214
308
  'roles.rules.tooltip': string;
215
- 'roles.rule.origin': string;
216
- 'roles.rule.origin.any': string;
217
- 'roles.rule.origin.root': string;
218
- 'roles.rule.origin.subagent': string;
219
309
  'roles.rule.provider': string;
220
310
  'roles.rule.provider.any': string;
221
311
  'roles.rule.model': string;
@@ -233,6 +323,14 @@ export declare const en: {
233
323
  'validation.ruleRoleUndeclared': string;
234
324
  'validation.ruleRoleRequired': string;
235
325
  'validation.roleChainRequired': string;
326
+ 'validation.allDayRequired': string;
327
+ 'validation.slotChainRequired': string;
328
+ 'validation.slotWindow': string;
329
+ 'validation.slotDays': string;
330
+ 'validation.slotKind': string;
331
+ 'validation.slotPresetUnknown': string;
332
+ 'validation.slotPresetDuplicate': string;
333
+ 'validation.slotPresetFrozen': string;
236
334
  'validation.selector': string;
237
335
  'legacy.banner': string;
238
336
  'catalog.empty': string;
@@ -269,12 +367,6 @@ export declare const en: {
269
367
  'save.saving': string;
270
368
  'save.error': string;
271
369
  close: string;
272
- reset: string;
273
- 'reset.confirmTitle': string;
274
- 'reset.confirm': string;
275
- 'reset.confirm.cancel': string;
276
- 'reset.confirm.action': string;
277
- 'reset.saving': string;
278
370
  loading: string;
279
371
  unavailable: string;
280
372
  'error.generic': string;
@@ -24,6 +24,7 @@ import type { CommandDefinition } from '@deepseek-ai/dsh-commands';
24
24
  import { type FallbacksRole } from './config.ts';
25
25
  import type { Origin } from './roles.ts';
26
26
  import type { FallbacksSwitchEventData } from './events.ts';
27
+ import type { SlotRowConfig } from './time-slots.ts';
27
28
  /** How many recent `fallbacks/switch` events `/fallbacks` shows (newest first). */
28
29
  export declare const RECENT_SWITCHES_LIMIT = 5;
29
30
  /** Minimal command registry surface (satisfied by the dsh `CommandService`). */
@@ -68,7 +69,15 @@ export interface FallbacksCommandSnapshot {
68
69
  * `fallback` is `'inherit-root'` — or the role is unknown — and rootChain
69
70
  * is non-empty; the diagnostic annotation source, spec §7.4). */
70
71
  readonly inherit: boolean;
71
- /** Recent `fallbacks/switch` events, newest first, capped at {@link RECENT_SWITCHES_LIMIT}. */
72
+ /** Current time-slot winner + display label (P5/P7): the 分时切换 side of
73
+ * the status strip. The switches section below is the 降级切换 side —
74
+ * the copy never mixes. */
75
+ readonly slot: {
76
+ readonly winner: SlotRowConfig | 'all-day';
77
+ readonly label: string;
78
+ };
79
+ /** Recent `fallbacks/switch` events (failure walks — 降级切换), newest
80
+ * first, capped at {@link RECENT_SWITCHES_LIMIT}. */
72
81
  readonly switches: readonly FallbacksSwitchEventData[];
73
82
  /** Active cooldown entries for the agent. */
74
83
  readonly cooldown: readonly FallbacksCooldownEntry[];
@@ -118,7 +127,7 @@ export interface FallbacksCommandController {
118
127
  export declare const FALLBACKS_COMMAND_LOCALES: {
119
128
  readonly zh: {
120
129
  readonly title: "当前会话 fallback 诊断(只读)";
121
- readonly description: "查看当前会话的降级链、最近切换与冷却状态(只读)";
130
+ readonly description: "查看当前会话的降级链、最近降级切换与冷却状态(只读)";
122
131
  readonly usageConfig: "查看组合后的 fallbacks 配置(设置回读)";
123
132
  readonly usage: " /fallbacks config 查看组合后的 fallbacks 配置(设置回读)";
124
133
  readonly origin: "会话来源";
@@ -126,7 +135,8 @@ export declare const FALLBACKS_COMMAND_LOCALES: {
126
135
  readonly chain: "链";
127
136
  readonly inheritRoot: "(inherit-root)";
128
137
  readonly chainNone: "未配置";
129
- readonly switches: "最近切换";
138
+ readonly slot: "分时";
139
+ readonly switches: "最近降级切换";
130
140
  readonly switchesNone: "本会话暂无 fallback 切换";
131
141
  readonly switchLine: "{from} → {to}(role={role},reason={reason})";
132
142
  readonly cooldown: "冷却";
@@ -156,7 +166,7 @@ export declare const FALLBACKS_COMMAND_LOCALES: {
156
166
  };
157
167
  readonly en: {
158
168
  readonly title: "Session fallback diagnostics (read-only)";
159
- readonly description: "Inspect fallback chain, recent switches, and cooldown for this session (read-only)";
169
+ readonly description: "Inspect fallback chain, recent fallback switches, and cooldown for this session (read-only)";
160
170
  readonly usageConfig: "show the composed fallbacks config (settings readback)";
161
171
  readonly usage: " /fallbacks config show the composed fallbacks config (settings readback)";
162
172
  readonly origin: "Session origin";
@@ -164,7 +174,8 @@ export declare const FALLBACKS_COMMAND_LOCALES: {
164
174
  readonly chain: "Chain";
165
175
  readonly inheritRoot: " (inherit-root)";
166
176
  readonly chainNone: "not configured";
167
- readonly switches: "Recent switches";
177
+ readonly slot: "Time slot";
178
+ readonly switches: "Recent fallback switches";
168
179
  readonly switchesNone: "No fallback switches in this session";
169
180
  readonly switchLine: "{from} → {to} (role={role}, reason={reason})";
170
181
  readonly cooldown: "Cooldown";
@@ -253,8 +264,8 @@ export declare const FALLBACKS_CONFIG_LIST_CAP = 5;
253
264
  export declare function fallbacksConfigText(summary: FallbacksConfigSummary, locale?: FallbacksCommandLocale): string;
254
265
  /**
255
266
  * Render the `/fallbacks` status surface for one snapshot. Kept minimal and
256
- * truthful: origin → role → chain (+ inherit tail) → recent switches →
257
- * cooldown.
267
+ * truthful: origin → role → chain (+ inherit tail) → current slot (分时) →
268
+ * recent switches (降级切换) → cooldown.
258
269
  */
259
270
  export declare function fallbacksCommandText(snapshot: FallbacksCommandSnapshot, locale?: FallbacksCommandLocale): string;
260
271
  /**
package/dist/config.d.ts CHANGED
@@ -27,10 +27,17 @@
27
27
  *
28
28
  * @module dsh-llm-fallbacks/config
29
29
  */
30
+ import type { SlotRowConfig } from './time-slots.ts';
30
31
  /** How a cooled-down model comes back (spec §4). */
31
32
  export type RevertPolicy = 'cooldown-expiry' | 'never';
32
- /** A single role rule: match on origin/provider/model patterns (spec §3). */
33
+ /** A single role rule: match on provider/model patterns (spec §3). */
33
34
  export interface FallbacksRoleRule {
35
+ /**
36
+ * Legacy persisted wire field (PR #62 feedback): rules are subagent-only,
37
+ * so this constraint is IGNORED at match time — root requests never
38
+ * match rules. Kept in the type/schema so pre-feedback `settings.yaml`
39
+ * files that carry `origin` still parse, validate, and save unchanged.
40
+ */
34
41
  origin?: 'root' | 'subagent';
35
42
  provider?: string;
36
43
  model?: string;
@@ -104,6 +111,20 @@ export interface FallbacksConfig {
104
111
  * for direct constructors that omit it).
105
112
  */
106
113
  roleAutoMatch?: boolean;
114
+ /**
115
+ * Extra time-slot rows (plan fallbacks-timeslots Task 1, P5): the FIRST
116
+ * matching row's chain becomes the effective root chain at request time;
117
+ * `rootChain` (the all-day chain) is always the last row.
118
+ * Optional on purpose, mirroring `presets` — additive, non-breaking for
119
+ * library consumers. Malformed rows warn once and are skipped by the
120
+ * resolver; the gateway rejects them on save (Task 3).
121
+ */
122
+ timeSlots?: SlotRowConfig[];
123
+ /**
124
+ * Config-level timezone for slot matching (default `Asia/Shanghai`,
125
+ * UTC+8). Not per-slot.
126
+ */
127
+ tz?: string;
107
128
  }
108
129
  /**
109
130
  * Spec §4 defaults — `Config({})` must equal this (no-op install).
package/dist/index.d.ts CHANGED
@@ -17,10 +17,13 @@
17
17
  * `{ kind: 'retry' }` (own recovery, no `next()`).
18
18
  * - `agent/request` waterfall: apply a pending switch after `await next()`
19
19
  * (provider/model override, inherited `reasoningEffort` dropped — the
20
- * `installModelSelection` `withoutInheritedEffort` pattern), then the
21
- * always-mode cap check (count `llm/retry` events for the current
22
- * turn/step/provider; ≥ `alwaysModeRetryCap` → same decision path, reason
23
- * `always-cap` — ADR-2).
20
+ * `installModelSelection` `withoutInheritedEffort` pattern); a
21
+ * root-origin `FallbacksChain/Auto` seed then overrides to the
22
+ * effective chain's first exact head (select-is-primary, plan
23
+ * fallbacks-virtual-chain Task 2); then the always-mode cap check (count
24
+ * `llm/retry` events for the current turn/step/provider; ≥
25
+ * `alwaysModeRetryCap` → same decision path, reason `always-cap` —
26
+ * ADR-2).
24
27
  * - Per-agent state (`FallbackStateStore`): `agent/disposed` removes it,
25
28
  * `agent/status` idle prunes per-step state defensively, plugin dispose
26
29
  * clears everything (spec §6 — no residual state).