dsh-llm-fallbacks 0.6.1 → 0.6.2

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.
@@ -1,18 +1,9 @@
1
1
  import type { FallbackSwitchReason } from '../events.ts';
2
2
  /** Simplified Chinese dictionary (the key-set source of truth). */
3
3
  export declare const zh: {
4
- title: string;
5
- intro: string;
6
- collapse: string;
7
- expand: string;
8
- unsaved: string;
9
4
  discard: string;
10
5
  retry: string;
11
6
  readOnly: string;
12
- 'enabled.label': string;
13
- 'enabled.hint': string;
14
- 'enabled.tooltip': string;
15
- 'enabled.off': string;
16
7
  'triggerCodes.label': string;
17
8
  'triggerCodes.hint': string;
18
9
  'triggerCodes.tooltip': string;
@@ -35,8 +26,6 @@ export declare const zh: {
35
26
  'alwaysModeRetryCap.hint': string;
36
27
  'alwaysModeRetryCap.tooltip': string;
37
28
  'advanced.label': string;
38
- 'advanced.expand': string;
39
- 'advanced.collapse': string;
40
29
  'roleAutoMatch.label': string;
41
30
  'roleAutoMatch.hint': string;
42
31
  'roleAutoMatch.tooltip': string;
@@ -199,18 +188,9 @@ export declare const zh: {
199
188
  export type FallbacksKey = keyof typeof zh;
200
189
  /** English dictionary, checked complete against the zh key set. */
201
190
  export declare const en: {
202
- title: string;
203
- intro: string;
204
- collapse: string;
205
- expand: string;
206
- unsaved: string;
207
191
  discard: string;
208
192
  retry: string;
209
193
  readOnly: string;
210
- 'enabled.label': string;
211
- 'enabled.hint': string;
212
- 'enabled.tooltip': string;
213
- 'enabled.off': string;
214
194
  'triggerCodes.label': string;
215
195
  'triggerCodes.hint': string;
216
196
  'triggerCodes.tooltip': string;
@@ -233,8 +213,6 @@ export declare const en: {
233
213
  'alwaysModeRetryCap.hint': string;
234
214
  'alwaysModeRetryCap.tooltip': string;
235
215
  'advanced.label': string;
236
- 'advanced.expand': string;
237
- 'advanced.collapse': string;
238
216
  'roleAutoMatch.label': string;
239
217
  'roleAutoMatch.hint': string;
240
218
  'roleAutoMatch.tooltip': string;
@@ -109,7 +109,12 @@ export interface FallbacksCommandSnapshot {
109
109
  * runtime) is summarized as `''` and rendered as `*`.
110
110
  */
111
111
  export interface FallbacksConfigSummary {
112
- readonly enabled: boolean;
112
+ /**
113
+ * Content-presence gate (`isFallbackActive`, plan fallbacks-web-ux-alignment
114
+ * T2 — the removed config-level `enabled` switch re-keyed): the plugin
115
+ * intervenes exactly when a chain/time-slot/role is configured.
116
+ */
117
+ readonly active: boolean;
113
118
  readonly triggerCodes: readonly string[];
114
119
  readonly rootChain: readonly string[];
115
120
  /** Summarized time-slot rows (preset rows carry `preset`, custom rows carry `start`/`end`; both may carry a day mask). */
package/dist/config.d.ts CHANGED
@@ -17,8 +17,14 @@
17
17
  * Spec §4 is authoritative for field names and default values — notably
18
18
  * `triggerCodes` defaults to dsh's stable failure codes `['AUTH', 'QUOTA',
19
19
  * 'RATE_LIMIT']` (there is no `QUOTA_EXCEEDED` code in dsh), and an
20
- * unconfigured install (`enabled: false`, empty `rootChain`, empty roles)
21
- * is a no-op pass-through exactly like an uninstalled plugin (AC-8).
20
+ * unconfigured install (empty `rootChain`, no time slots, empty roles) is a
21
+ * no-op pass-through exactly like an uninstalled plugin (AC-8 —
22
+ * {@link isFallbackActive}). There is NO config-level `enabled` switch
23
+ * (plan fallbacks-web-ux-alignment T2): the Plugins-page row toggle is the
24
+ * master switch (row disable = fiber destroy), and the runtime gates re-key
25
+ * to content presence. A stored profile still carrying the removed
26
+ * `enabled:` key loads cleanly — the gateway tolerates and strips it (the
27
+ * advisor LEGACY_KEYS mechanism), it is never read and never re-persisted.
22
28
  *
23
29
  * This module is pure logic: it must not import any `@deepseek-ai/*` package
24
30
  * (types included) — `FallbacksConfig` is the plugin's own type. Task 3
@@ -82,7 +88,6 @@ export interface FallbacksRoles {
82
88
  * field names).
83
89
  */
84
90
  export interface FallbacksConfig {
85
- enabled: boolean;
86
91
  triggerCodes: string[];
87
92
  rootChain: string[];
88
93
  roles: FallbacksRoles;
@@ -142,10 +147,10 @@ export interface FallbacksConfig {
142
147
  }
143
148
  /**
144
149
  * Spec §4 defaults — `Config({})` must equal this (no-op install).
145
- * `enabled` defaults to `false` (readme-settings spec §1.2): the feature
146
- * switch is off until the user turns it on in the settings page; an
147
- * unconfigured install (`enabled: false`, empty rootChain, empty roles)
148
- * behaves exactly like an uninstalled plugin (AC-3 / no-op invariant).
150
+ * There is no `enabled` default (the key is removed — the Plugins-page row
151
+ * toggle is the master switch): an unconfigured install (empty rootChain,
152
+ * no time slots, empty roles) behaves exactly like an uninstalled plugin
153
+ * (AC-3 / no-op invariant, {@link isFallbackActive}).
149
154
  */
150
155
  export declare const defaultFallbacksConfig: FallbacksConfig;
151
156
  /**
@@ -153,6 +158,18 @@ export declare const defaultFallbacksConfig: FallbacksConfig;
153
158
  * the no-rule-match fallback, but FORBIDDEN in `roles.list[].id`.
154
159
  */
155
160
  export declare const INHERIT_ROLE_ID = "inherit";
161
+ /**
162
+ * The no-op gate (AC-8), re-keyed from the removed `enabled` switch to
163
+ * CONTENT PRESENCE (plan fallbacks-web-ux-alignment T2): the plugin
164
+ * intervenes exactly when something is configured — a non-empty `rootChain`
165
+ * (the all-day chain), at least one time-slot row, or at least one declared
166
+ * role. An inactive config is a pass-through exactly like an uninstalled
167
+ * plugin; the Plugins-page row toggle remains the master switch (row
168
+ * disable = fiber destroy). ONE helper for every runtime gate — the former
169
+ * `config.enabled` sites (request waterfalls, picker-row registration, TUI
170
+ * summary, General-row badge) all read through this.
171
+ */
172
+ export declare function isFallbackActive(config: FallbacksConfig): boolean;
156
173
  /** Role id format (aligned with yet-another-subagent `isValidProfileId`). */
157
174
  export declare const ROLE_ID_PATTERN: RegExp;
158
175
  /**
package/dist/gateway.d.ts CHANGED
@@ -28,7 +28,12 @@
28
28
  * profile patch). There is NO hard-gate resolver (unlike advisor's
29
29
  * `resolveAdvisorConfig`): the fallbacks decision path runs at
30
30
  * `agent/request` time in `src/index.ts`, so the gateway returns the raw
31
- * composed config — `enabled` is a plain config field, not a gate output.
31
+ * composed config. There is NO config-level `enabled` key on the contract
32
+ * (plan fallbacks-web-ux-alignment T2): the Plugins-page row toggle is the
33
+ * master switch, the runtime gates read content presence
34
+ * (`isFallbackActive` in `src/config.ts`), and a stored `enabled:` line is
35
+ * tolerated-and-stripped ({@link LEGACY_KEYS} — never read, never
36
+ * re-persisted).
32
37
  * `set` validates the patch against the `Config` schema first (unknown-key
33
38
  * rejection unchanged — the settings service itself is non-strict and would
34
39
  * merge the unknown key through), then writes the plugin's profile-entry
@@ -213,7 +218,8 @@ export declare class FallbacksConfigGateway extends TypertRemoteService {
213
218
  /**
214
219
  * Read the current composed config (schema defaults → entry base → profile
215
220
  * patch). No hard-gate resolver (ADR-2): the raw composed config is
216
- * the wire value — `enabled` is a plain field, not a gate output.
221
+ * the wire value. The removed `enabled` key never crosses the wire (the
222
+ * read whitelist drops it — the snapshot-strip half of LEGACY_KEYS).
217
223
  * @returns the wire-normalized composed config plus `legacyKeys` — legacy
218
224
  * two-block-era fields (`chains` / `roles.default` / undeclared rule
219
225
  * role refs) detected on the composed source (schemastery retains them,
package/dist/index.d.ts CHANGED
@@ -11,7 +11,8 @@
11
11
  * `apply` reads the Loader's live config reference, and the
12
12
  * `settings/document-updated` listener re-derives the runtime caches —
13
13
  * the old `installSection` setSource/onChange contract, spec §4).
14
- * - `agent/request-error` waterfall: `!enabled` / code ∉ `triggerCodes`
14
+ * - `agent/request-error` waterfall: inactive config (`isFallbackActive`) /
15
+ * code ∉ `triggerCodes`
15
16
  * (**always mode included**) → `next()`; otherwise resolve role + chain,
16
17
  * and when a candidate survives the filter (current / cooldown /
17
18
  * step-failed / `provider/*`-missing-id) write the pending switch +
package/dist/index.js CHANGED
@@ -323,7 +323,6 @@ var RecoveryStore = class {
323
323
  //#endregion
324
324
  //#region .build/host/config.js
325
325
  const defaultFallbacksConfig = {
326
- enabled: false,
327
326
  triggerCodes: [
328
327
  "AUTH",
329
328
  "QUOTA",
@@ -345,6 +344,9 @@ const defaultFallbacksConfig = {
345
344
  recovery: "timer"
346
345
  };
347
346
  const INHERIT_ROLE_ID = "inherit";
347
+ function isFallbackActive(config) {
348
+ return config.rootChain.length > 0 || (config.timeSlots?.length ?? 0) > 0 || config.roles.list.length > 0;
349
+ }
348
350
  const ROLE_ID_PATTERN = /^[a-z0-9-]{1,32}$/;
349
351
  function validateFallbacksConfig(config, logger) {
350
352
  const declaredIds = new Set();
@@ -412,7 +414,6 @@ function isRecordLike(value) {
412
414
  return typeof value === "object" && value !== null && !Array.isArray(value);
413
415
  }
414
416
  const Config = z.object({
415
- enabled: z.boolean().default(false),
416
417
  triggerCodes: z.array(z.string()).default([
417
418
  "AUTH",
418
419
  "QUOTA",
@@ -874,7 +875,7 @@ const ROLE_STATE_SCHEMA = { parse(value) {
874
875
  };
875
876
  }
876
877
  }
877
- throw new TypeError(`role projection: expected null or a non-blank role id with its fork boundary, got ${describeValue(value)}`);
878
+ return null;
878
879
  } };
879
880
  function isInheritedEventCount(value) {
880
881
  return typeof value === "number" && Number.isSafeInteger(value) && value >= 0;
@@ -1515,7 +1516,6 @@ function overrideConfigWithRouteRule(seed, to, explicitEffort) {
1515
1516
  //#region .build/host/gateway.js
1516
1517
  const FALLBACKS_PROFILE_ENTRY = "llm-fallbacks";
1517
1518
  const CONFIG_KEYS = {
1518
- enabled: true,
1519
1519
  triggerCodes: true,
1520
1520
  rootChain: true,
1521
1521
  roles: true,
@@ -1533,6 +1533,7 @@ const ROLES_KEYS = {
1533
1533
  list: true,
1534
1534
  rules: true
1535
1535
  };
1536
+ const LEGACY_KEYS = new Set(["enabled"]);
1536
1537
  const SLOT_ROW_KEYS = {
1537
1538
  kind: true,
1538
1539
  preset: true,
@@ -1568,7 +1569,7 @@ var FallbacksConfigGateway = class extends TypertRemoteService {
1568
1569
  if (Object.keys(patch).length === 0) return this.readResult();
1569
1570
  const settings = this.settings;
1570
1571
  if (settings === void 0) throw new Error("fallbacks: settings service is unavailable — configuration cannot be written");
1571
- const normalized = Object.fromEntries(Object.entries(patch).filter(([, value]) => value !== null));
1572
+ const normalized = Object.fromEntries(Object.entries(patch).filter(([key, value]) => !LEGACY_KEYS.has(key) && value !== null));
1572
1573
  if (Object.keys(normalized).length === 0) return this.readResult();
1573
1574
  await settings.update(FALLBACKS_PROFILE_ENTRY, normalized);
1574
1575
  return this.readResult();
@@ -1665,7 +1666,7 @@ function normalizeRoles(value) {
1665
1666
  function validateConfigPatch(patch) {
1666
1667
  if (patch === null || typeof patch !== "object" || Array.isArray(patch)) throw new TypeError("dsh-llm-fallbacks: configuration patch must be a plain object");
1667
1668
  for (const key of Object.keys(patch)) {
1668
- if (!Object.hasOwn(CONFIG_KEYS, key)) throw new Error(`dsh-llm-fallbacks: unknown config key "${key}"`);
1669
+ if (!Object.hasOwn(CONFIG_KEYS, key) && !LEGACY_KEYS.has(key)) throw new Error(`dsh-llm-fallbacks: unknown config key "${key}"`);
1669
1670
  if (key === "roles") {
1670
1671
  const roles = patch[key];
1671
1672
  if (roles !== null && typeof roles === "object" && !Array.isArray(roles)) {
@@ -2021,7 +2022,7 @@ function formatConfigRules(rules, t) {
2021
2022
  function fallbacksConfigText(summary, locale = "zh") {
2022
2023
  const t = FALLBACKS_COMMAND_LOCALES[locale];
2023
2024
  return [
2024
- `${t.configTitle}: ${summary.enabled ? t.configEnabled : t.configDisabled}`,
2025
+ `${t.configTitle}: ${summary.active ? t.configEnabled : t.configDisabled}`,
2025
2026
  `${t.configTriggerCodes}: ${summary.triggerCodes.length === 0 ? t.configEmpty : formatConfigList(summary.triggerCodes)}`,
2026
2027
  `${t.configRootChain}: ${summary.rootChain.length === 0 ? t.configEmpty : formatConfigList(summary.rootChain)}`,
2027
2028
  `${t.configTimeSlots}: ${summary.timeSlots.length === 0 ? t.configEmpty : formatConfigTimeSlots(summary.timeSlots, t)}`,
@@ -2513,16 +2514,6 @@ function buildFallbacksTuiSection() {
2513
2514
  }
2514
2515
  ],
2515
2516
  fields: [
2516
- {
2517
- path: ["enabled"],
2518
- label: "Enabled",
2519
- descriptions: {
2520
- zh: "启用回退",
2521
- en: "Enabled"
2522
- },
2523
- group: "general",
2524
- kind: "boolean"
2525
- },
2526
2517
  {
2527
2518
  path: ["roleAutoMatch"],
2528
2519
  label: "LLM role auto-match",
@@ -2886,7 +2877,7 @@ function installFallbacksAdapter(ctx, readConfig) {
2886
2877
  const logger = ctx.logger("llm-fallbacks");
2887
2878
  const adapter = new FallbacksChainAdapter(readConfig, () => llm);
2888
2879
  const reconcile = () => {
2889
- const shouldRegister = readConfig().enabled;
2880
+ const shouldRegister = isFallbackActive(readConfig());
2890
2881
  if (shouldRegister && !registered) {
2891
2882
  if (llm === void 0) return;
2892
2883
  try {
@@ -3296,7 +3287,7 @@ function apply(ctx, config = defaultFallbacksConfig) {
3296
3287
  }
3297
3288
  ctx.on("agent/request-error", async ({ agent, turn, step, provider, failure }, next) => {
3298
3289
  const config = source();
3299
- if (!config.enabled || !config.triggerCodes.includes(failure.code)) return next();
3290
+ if (!isFallbackActive(config) || !config.triggerCodes.includes(failure.code)) return next();
3300
3291
  const current = currentModel(agent, provider, config, new Date());
3301
3292
  if (!current.model) return next();
3302
3293
  try {
@@ -3322,7 +3313,7 @@ function apply(ctx, config = defaultFallbacksConfig) {
3322
3313
  const applied = state === void 0 ? void 0 : states.applyPending(state, turn, step);
3323
3314
  if (applied !== void 0) return overrideConfig(seed, applied.to);
3324
3315
  const config = source();
3325
- if (config.enabled && isAllDayConforming(config.rootChain) && (config.timeSlots?.length ?? 0) > 0 && agent.session?.header?.origin !== "subagent") {
3316
+ if (isFallbackActive(config) && isAllDayConforming(config.rootChain) && (config.timeSlots?.length ?? 0) > 0 && agent.session?.header?.origin !== "subagent") {
3326
3317
  const slot = resolveSlotState(config, new Date(), config.tz ?? "Asia/Shanghai");
3327
3318
  const key = slotWinnerKey(slot.winner);
3328
3319
  const previous = slotWinners.get(agent.id);
@@ -3332,7 +3323,7 @@ function apply(ctx, config = defaultFallbacksConfig) {
3332
3323
  label: slot.label
3333
3324
  });
3334
3325
  }
3335
- if (config.enabled && hasChains && agent.session?.header?.origin === "subagent" && !dispatchInjected.has(agent.id)) {
3326
+ if (isFallbackActive(config) && hasChains && agent.session?.header?.origin === "subagent" && !dispatchInjected.has(agent.id)) {
3336
3327
  dispatchInjected.add(agent.id);
3337
3328
  try {
3338
3329
  const settingsRead = readGuardedPolicySettings(ctx, agent.id, lastKnownPolicySettings, logger.warn);
@@ -3390,7 +3381,7 @@ function apply(ctx, config = defaultFallbacksConfig) {
3390
3381
  logger.warn("llm-fallbacks: dispatch role-injection failed, proceeding with the request unchanged: %s", error?.message ?? String(error));
3391
3382
  }
3392
3383
  }
3393
- if (hasChains && config.enabled && config.alwaysModeRetryCap > 0 && countRetryEvents(agent.session, turn, step, seed.provider) >= config.alwaysModeRetryCap) {
3384
+ if (hasChains && isFallbackActive(config) && config.alwaysModeRetryCap > 0 && countRetryEvents(agent.session, turn, step, seed.provider) >= config.alwaysModeRetryCap) {
3394
3385
  const decisionState = states.peek(agent.id);
3395
3386
  const capRoute = anchorServedRoute(config, {
3396
3387
  provider: seed.provider,
@@ -3469,7 +3460,7 @@ function apply(ctx, config = defaultFallbacksConfig) {
3469
3460
  getConfig() {
3470
3461
  const config = source();
3471
3462
  return {
3472
- enabled: config.enabled,
3463
+ active: isFallbackActive(config),
3473
3464
  triggerCodes: config.triggerCodes,
3474
3465
  rootChain: config.rootChain,
3475
3466
  timeSlots: (config.timeSlots ?? []).map((row) => row.kind === "preset" ? {
@@ -114,9 +114,12 @@ export declare const FALLBACKS_TUI_SECTION_NS = "fallbacks";
114
114
  */
115
115
  export declare const JSON_FIELD_MAX_DRAFT_BYTES: number;
116
116
  /**
117
- * The `fallbacks` /settings section: 13 fields covering all 15 web-card
117
+ * The `fallbacks` /settings section: 12 fields covering all 14 web-card
118
118
  * capabilities (the default-model choice rides `rootChain`'s last entry and
119
- * the per-role fallback strategy rides `roles.list` JSON). Scalar
119
+ * the per-role fallback strategy rides `roles.list` JSON; the config-level
120
+ * `enabled` switch is REMOVED — plan fallbacks-web-ux-alignment T2, the
121
+ * Plugins-page row toggle is the master switch and the runtime gates read
122
+ * content presence). Scalar
120
123
  * capabilities use native kinds (boolean/number/select); complex structures
121
124
  * use `text` fields with custom `format`/`parse` that mirror the gateway's
122
125
  * validation. Built fresh per call — the host deep-freezes whatever it
@@ -9,15 +9,20 @@
9
9
  * `ctx.inject(['llm'])` child — absent `llm` service (test harness) is a
10
10
  * clean no-op, and fiber unload ⇒ the child's disposer unregisters the
11
11
  * route. Registration is an idempotent transition-reconcile on COMMITTED
12
- * config snapshots: register on `enabled` false→true, unregister on
13
- * true→false, driven by the settings `onChange` hook (the returned
14
- * reconcile thunk, wired by `apply()`) plus child activation. The row is
15
- * visible whenever the plugin is enabled — a non-conforming all-day chain
16
- * does NOT hide it (PR #62 feedback); conformance still gates a
17
- * successful delegate (`effectiveHeadOf` below refuses a
18
- * non-conforming all-day). The condition deliberately ignores `timeSlots`
19
- * and conformance, so slot-row edits and chain edits never churn
20
- * registration.
12
+ * config snapshots: register when nothing is configured → something is
13
+ * (`isFallbackActive` — content presence, plan fallbacks-web-ux-alignment
14
+ * T2), unregister on the reverse, driven by the settings `onChange` hook
15
+ * (the returned reconcile thunk, wired by `apply()`) plus child activation.
16
+ * The row is visible whenever something is configured — a non-conforming
17
+ * all-day chain does NOT hide it (PR #62 feedback); conformance still gates
18
+ * a successful delegate (`effectiveHeadOf` below refuses a non-conforming
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).
21
26
  *
22
27
  * Adapter behavior (P1/P3): `listModels` advertises exactly the one virtual
23
28
  * row; `stream()` is a THIN single-hop delegate to the effective chain head
@@ -34,7 +39,7 @@
34
39
  */
35
40
  import type { Context } from '@deepseek-ai/cordis';
36
41
  import { LlmAdapter, type GenerateOptions, type LlmImageRequestPricing, type LlmModelInfo, type LlmResolvedModelInfo, type LlmRuntime, type ResolvedRetryPolicy, type StreamChunk } from '@deepseek-ai/dsh-llm';
37
- import type { FallbacksConfig } from './config.ts';
42
+ import { type FallbacksConfig } from './config.ts';
38
43
  /** Provider route of the virtual adapter (exact string, spec lock). */
39
44
  export declare const FALLBACKS_PROVIDER = "FallbacksChain";
40
45
  /**
package/icon.svg ADDED
@@ -0,0 +1,16 @@
1
+ <svg width="36" height="36" viewBox="0 0 36 36" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <defs>
3
+ <linearGradient id="dsh-llm-fallbacks-icon-a" x1="14.9894" y1="9.0697" x2="14.9894" y2="21.3063" gradientUnits="userSpaceOnUse">
4
+ <stop stop-color="#69B9FF"/>
5
+ <stop offset="1" stop-color="#324DE2"/>
6
+ </linearGradient>
7
+ <linearGradient id="dsh-llm-fallbacks-icon-b" x1="21.1075" y1="15.1877" x2="21.1075" y2="27.4243" gradientUnits="userSpaceOnUse">
8
+ <stop stop-color="#45E7A4"/>
9
+ <stop offset="1" stop-color="#05909D"/>
10
+ </linearGradient>
11
+ </defs>
12
+ <rect x="8.87109" y="9.0697" width="12.2365" height="12.2365" rx="2" fill="url(#dsh-llm-fallbacks-icon-a)" fill-opacity="0.8"/>
13
+ <rect x="14.9893" y="15.1877" width="12.2365" height="12.2365" rx="2" fill="url(#dsh-llm-fallbacks-icon-b)" fill-opacity="0.8"/>
14
+ <path d="M13.3 13.3L19.4 19.4" stroke="#F9FAFB" stroke-opacity="0.95" stroke-width="1.7" stroke-linecap="round"/>
15
+ <path d="M19.4 15.9V19.4H15.9" stroke="#F9FAFB" stroke-opacity="0.95" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"/>
16
+ </svg>
package/locale/en.json ADDED
@@ -0,0 +1,6 @@
1
+ {
2
+ "meta": {
3
+ "title": "Fallbacks",
4
+ "description": "Automatic provider/model fallback chains that keep agent steps running when LLM requests keep failing (auth, quota, rate limit)."
5
+ }
6
+ }
package/locale/zh.json ADDED
@@ -0,0 +1,6 @@
1
+ {
2
+ "meta": {
3
+ "title": "故障降级",
4
+ "description": "模型请求持续失败(认证、配额、限流)时自动切换备用模型链,保持 agent 步骤继续运行。"
5
+ }
6
+ }
package/package.json CHANGED
@@ -5,10 +5,11 @@
5
5
  "dsh",
6
6
  "dsh-plugin"
7
7
  ],
8
- "version": "0.6.1",
8
+ "version": "0.6.2",
9
9
  "type": "module",
10
10
  "main": "./dist/index.js",
11
11
  "types": "./dist/index.d.ts",
12
+ "icon": "./icon.svg",
12
13
  "exports": {
13
14
  ".": {
14
15
  "types": "./dist/index.d.ts",
@@ -18,12 +19,15 @@
18
19
  "types": "./dist/client/index.d.ts",
19
20
  "default": "./dist/client/index.js"
20
21
  },
22
+ "./locale/*.json": "./locale/*.json",
21
23
  "./bundle/cordis.patch.yml": "./bundle/cordis.patch.yml",
22
24
  "./package.json": "./package.json"
23
25
  },
24
26
  "files": [
25
27
  "dist",
26
28
  "bundle",
29
+ "locale",
30
+ "icon.svg",
27
31
  "scripts"
28
32
  ],
29
33
  "dsh": {
@@ -71,7 +75,6 @@
71
75
  "@deepseek-ai/dsh-client-ui-chat": "^0.1.7-rc.2",
72
76
  "@deepseek-ai/dsh-client-ui-conversation": "^0.1.7-rc.2",
73
77
  "@deepseek-ai/dsh-client-ui-plugin-manager": "^0.1.7-rc.2",
74
- "@deepseek-ai/dsh-client-ui-primitives": "^0.1.7-rc.2",
75
78
  "@deepseek-ai/dsh-client-ui-renderer": "^0.1.7-rc.2",
76
79
  "@deepseek-ai/dsh-client-ui-settings": "^0.1.7-rc.2",
77
80
  "@deepseek-ai/dsh-client-ui-slots": "^0.1.7-rc.2",
@@ -74,7 +74,6 @@ export const CLIENT_EXTERNALS: readonly string[] = [
74
74
  '@deepseek-ai/cordis',
75
75
  '@deepseek-ai/dsh-client-store',
76
76
  '@deepseek-ai/dsh-client-ui-slots',
77
- '@deepseek-ai/dsh-client-ui-primitives',
78
77
  ]
79
78
 
80
79
  /**