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.
- package/README.md +65 -7
- package/README.zh-CN.md +65 -7
- package/dist/client/FallbacksCard.d.ts +26 -12
- package/dist/client/fallbacks-store.d.ts +48 -4
- package/dist/client/index.js +2187 -935
- package/dist/client/locales.d.ts +118 -26
- package/dist/commands.d.ts +18 -7
- package/dist/config.d.ts +22 -1
- package/dist/index.d.ts +7 -4
- package/dist/index.js +467 -15
- package/dist/roles.d.ts +12 -5
- package/dist/time-slots.d.ts +104 -0
- package/dist/virtual-adapter.d.ts +90 -0
- package/package.json +1 -1
package/dist/roles.d.ts
CHANGED
|
@@ -9,8 +9,13 @@
|
|
|
9
9
|
* `session.header.agentPreset?` carrier for that explicit stage.
|
|
10
10
|
*
|
|
11
11
|
* Precedence (first hit wins):
|
|
12
|
-
* 1. the first `rules` entry whose specified
|
|
13
|
-
*
|
|
12
|
+
* 1. the first `rules` entry whose specified provider/model patterns match
|
|
13
|
+
* the agent — rules are SUBAGENT-ONLY (PR #62 feedback): a root-origin
|
|
14
|
+
* agent never matches rules and resolves straight to the built-in
|
|
15
|
+
* `'inherit'` (→ `rootChain`). The legacy per-rule `origin` field (a
|
|
16
|
+
* pre-feedback config may still carry `origin: root|subagent`) is
|
|
17
|
+
* IGNORED at match time — every rule applies to subagents regardless
|
|
18
|
+
* of the stored origin value;
|
|
14
19
|
* 2. the built-in `'inherit'` role (no-rule-match default, spec §7.1 / D4).
|
|
15
20
|
*
|
|
16
21
|
* A matched rule must target a declared role id (`roleIds`, derived from
|
|
@@ -27,8 +32,9 @@
|
|
|
27
32
|
* (`' coder '`) with a trimmed rule reference (`'coder'`) resolves to the
|
|
28
33
|
* same role instead of silently degrading to `'inherit'`.
|
|
29
34
|
*
|
|
30
|
-
* A missing agent origin is treated as `'root'
|
|
31
|
-
*
|
|
35
|
+
* A missing agent origin is treated as `'root'` — and root agents never
|
|
36
|
+
* match rules (rules are subagent-only, PR #62 feedback). Origin is read
|
|
37
|
+
* from `session.header.origin` — a native `SessionHeader` field the store folds
|
|
32
38
|
* from `CreateSessionOptions.meta.origin` (`packages/core/session/src/
|
|
33
39
|
* index.ts:884`); subagent children set it via `childSessionMeta`
|
|
34
40
|
* (`packages/subagent/subagent/src/child-agent.ts:115`), root agents carry
|
|
@@ -42,7 +48,8 @@
|
|
|
42
48
|
*/
|
|
43
49
|
import { type FallbacksRoleRule } from './config.ts';
|
|
44
50
|
export type { FallbacksRoleRule } from './config.ts';
|
|
45
|
-
/** Agent origins
|
|
51
|
+
/** Agent origins (spec §3) — an agent property, not a rule constraint:
|
|
52
|
+
* rules are subagent-only (PR #62 feedback). */
|
|
46
53
|
export type Origin = 'root' | 'subagent';
|
|
47
54
|
/** Loose agent shape sufficient for role resolution (spec §3 / brief). */
|
|
48
55
|
export interface AgentLike {
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Time-slot rows for `fallbacks` (plan fallbacks-timeslots Task 1, pins
|
|
3
|
+
* P4–P6): frozen preset windows, the official-V4 all-day conformance
|
|
4
|
+
* guard, and the pure `resolveEffectiveChain` / `resolveSlotState`
|
|
5
|
+
* resolver.
|
|
6
|
+
*
|
|
7
|
+
* Pure module — no `@deepseek-ai/*` runtime imports: the client card
|
|
8
|
+
* imports the row types type-only (mirroring `config.ts`) and the runtime
|
|
9
|
+
* wires these helpers at request time (Task 2). Malformed rows NEVER
|
|
10
|
+
* throw: they warn ONCE per row instance (through `console.warn` — the
|
|
11
|
+
* resolver's 3-argument contract has no logger parameter) and are
|
|
12
|
+
* skipped; a legacy non-empty non-conforming `rootChain` keeps the
|
|
13
|
+
* v0.2.2 failure walk verbatim (P6).
|
|
14
|
+
*
|
|
15
|
+
* @module dsh-llm-fallbacks/time-slots
|
|
16
|
+
*/
|
|
17
|
+
import type { FallbacksConfig } from './config.ts';
|
|
18
|
+
/** Official V4 models — the ONLY legal all-day selectors (length 1, XOR). */
|
|
19
|
+
export declare const OFFICIAL_V4_FLASH = "deepseek-official/deepseek-v4-flash";
|
|
20
|
+
export declare const OFFICIAL_V4_PRO = "deepseek-official/deepseek-v4-pro";
|
|
21
|
+
/** The four frozen preset ids (exact strings, spec lock). */
|
|
22
|
+
export declare const PRESET_IDS: readonly ["liang-peak", "liang-valley", "glm-peak", "glm-valley"];
|
|
23
|
+
export type PresetId = (typeof PRESET_IDS)[number];
|
|
24
|
+
/** A frozen UTC+8 window: `start ≤ t < end`, wrap-midnight when `start > end`. */
|
|
25
|
+
export interface SlotWindow {
|
|
26
|
+
/** Window start, `HH:mm` (24h). */
|
|
27
|
+
start: string;
|
|
28
|
+
/** Window end, `HH:mm` — EXCLUSIVE (a window contains `t` iff the day
|
|
29
|
+
* matches AND (`start ≤ end` ? `start ≤ t < end` : `start ≤ t || t < end`)). */
|
|
30
|
+
end: string;
|
|
31
|
+
/** Day mask: 0=Sunday … 6=Saturday. Omitted/empty = every day. */
|
|
32
|
+
days?: number[];
|
|
33
|
+
}
|
|
34
|
+
/** One extra time-slot row (P4 storage shape; `chain` is always editable). */
|
|
35
|
+
export interface SlotRowConfig {
|
|
36
|
+
kind: 'preset' | 'custom';
|
|
37
|
+
/** Preset id — required for `kind: 'preset'`; windows live in
|
|
38
|
+
* {@link PRESETS}, never stored. */
|
|
39
|
+
preset?: PresetId;
|
|
40
|
+
/** Custom-only: window start `HH:mm`. */
|
|
41
|
+
start?: string;
|
|
42
|
+
/** Custom-only: window end `HH:mm` (exclusive; may wrap midnight). */
|
|
43
|
+
end?: string;
|
|
44
|
+
/** Custom-only: day mask 0=Sunday…6=Saturday; omitted/empty = all days. */
|
|
45
|
+
days?: number[];
|
|
46
|
+
/** Custom-only display name (PR #62 feedback round, collapsed rows). */
|
|
47
|
+
name?: string;
|
|
48
|
+
/** Models for this row (editable even on preset rows). */
|
|
49
|
+
chain: string[];
|
|
50
|
+
}
|
|
51
|
+
/** Frozen preset definition (P4): windows are code constants, never stored. */
|
|
52
|
+
export interface PresetDefinition {
|
|
53
|
+
windows: readonly SlotWindow[];
|
|
54
|
+
/** `true` = matches iff the peak windows do NOT match (valley derives
|
|
55
|
+
* from its peak — no duplicated window enumerations that can drift). */
|
|
56
|
+
complement: boolean;
|
|
57
|
+
/** Display label for the status strip / settings card. */
|
|
58
|
+
label: string;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Frozen preset windows (UTC+8). `liang-*` presets have NO day mask (they
|
|
62
|
+
* apply every day, weekends included); `glm-peak` is Monday–Friday only.
|
|
63
|
+
* The two valleys are `complement: true` of their peak.
|
|
64
|
+
*/
|
|
65
|
+
export declare const PRESETS: Record<PresetId, PresetDefinition>;
|
|
66
|
+
/**
|
|
67
|
+
* All-day conformance (P6): the all-day chain is conforming when its LAST
|
|
68
|
+
* entry (the tail — the card's 默认模型 panel) is exactly one official V4
|
|
69
|
+
* model — Flash XOR Pro. Leading entries (the card's 默认降级链 block) are
|
|
70
|
+
* the ordered walk before that last-resort fallback. An empty chain or a
|
|
71
|
+
* chain whose tail is not an official V4 model keeps slot rows inert and
|
|
72
|
+
* refuses the virtual-row override/delegate; the v0.2.2 failure walk over
|
|
73
|
+
* the raw chain stays verbatim.
|
|
74
|
+
*/
|
|
75
|
+
export declare function isAllDayConforming(chain: readonly string[]): boolean;
|
|
76
|
+
/**
|
|
77
|
+
* Effective chain for a root request at `now` (P5): the FIRST extra row
|
|
78
|
+
* whose descriptor contains `now` (stored order) — that row's `chain`
|
|
79
|
+
* REPLACES the all-day chain (never concatenated); no match ⇒ `rootChain`
|
|
80
|
+
* (the all-day row, always last and required). Malformed rows warn once
|
|
81
|
+
* and are skipped; never throws.
|
|
82
|
+
*
|
|
83
|
+
* P6 (qc1 F-001): without a conforming all-day the slot rows are inert, so
|
|
84
|
+
* this IS the raw `rootChain` — the gate lives in {@link resolveSlotState},
|
|
85
|
+
* the single source every slot surface (this, the 分时切换 log, the
|
|
86
|
+
* `/fallbacks` strip, select-is-primary, the virtual adapter delegate) reads.
|
|
87
|
+
*/
|
|
88
|
+
export declare function resolveEffectiveChain(config: FallbacksConfig, now: Date, tz: string): string[];
|
|
89
|
+
/**
|
|
90
|
+
* Slot winner + display label (P5): drives 分时切换 detection (per-root-agent
|
|
91
|
+
* last-winner marker, in-process only) and the card / `/fallbacks` status
|
|
92
|
+
* strip. `winner` is the matching row or `'all-day'`; `label` names the
|
|
93
|
+
* slot (frozen preset label or `custom HH:mm-HH:mm`).
|
|
94
|
+
*
|
|
95
|
+
* P6 gate (qc1 F-001): without a conforming all-day
|
|
96
|
+
* (`isAllDayConforming(config.rootChain)`) the winner is ALWAYS `'all-day'`
|
|
97
|
+
* — a legacy multi-model (or empty) chain earns no slot rows, so every
|
|
98
|
+
* surface fed by this resolver reports the inert state and routing stays on
|
|
99
|
+
* the raw `rootChain` (the v0.2.2 walk verbatim).
|
|
100
|
+
*/
|
|
101
|
+
export declare function resolveSlotState(config: FallbacksConfig, now: Date, tz: string): {
|
|
102
|
+
winner: SlotRowConfig | 'all-day';
|
|
103
|
+
label: string;
|
|
104
|
+
};
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Virtual `FallbacksChain/Auto` LLM adapter (plan fallbacks-virtual-chain
|
|
3
|
+
* Task 1, technical pins P1–P3; PR #62 feedback round): a mount-only
|
|
4
|
+
* catalog row that makes the configured effective chain selectable as the
|
|
5
|
+
* session **primary** in the host model picker, without patching dsh or
|
|
6
|
+
* dsh-TUI (web and TUI share the adapter catalog).
|
|
7
|
+
*
|
|
8
|
+
* Wiring (P2): `installFallbacksAdapter` installs ONE conditional
|
|
9
|
+
* `ctx.inject(['llm'])` child — absent `llm` service (test harness) is a
|
|
10
|
+
* clean no-op, and fiber unload ⇒ the child's disposer unregisters the
|
|
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 override/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.
|
|
21
|
+
*
|
|
22
|
+
* Adapter behavior (P1/P3): `listModels` advertises exactly the one virtual
|
|
23
|
+
* row; `stream()` is a THIN single-hop delegate to the effective chain head
|
|
24
|
+
* through the host LLM runtime — no chain walk, no cooldown/caps/revert
|
|
25
|
+
* bookkeeping, no state writes (a failure inside the delegate surfaces at
|
|
26
|
+
* `agent/request-error`, where the existing engine walks from there).
|
|
27
|
+
* `resolveModel` proxies the current effective head's metadata when
|
|
28
|
+
* resolvable (modalities/context-window/reasoning follow the head) with a
|
|
29
|
+
* permissive default otherwise — never throws.
|
|
30
|
+
*
|
|
31
|
+
* @module dsh-llm-fallbacks/virtual-adapter
|
|
32
|
+
*/
|
|
33
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
34
|
+
import type { FallbacksConfig } from './config.ts';
|
|
35
|
+
/** Provider route of the virtual adapter (exact string, spec lock). */
|
|
36
|
+
export declare const FALLBACKS_PROVIDER = "FallbacksChain";
|
|
37
|
+
/**
|
|
38
|
+
* Model id of the virtual catalog row (exact string, spec lock). "Auto" is
|
|
39
|
+
* the hardcoded picker id (not i18n — user decision 2026-08-18). The
|
|
40
|
+
* catalog `name` the host picker renders is dynamic — see
|
|
41
|
+
* {@link pickerDisplayName} (`Auto: <model>[<slot>]`).
|
|
42
|
+
*/
|
|
43
|
+
export declare const FALLBACKS_CHAIN_MODEL = "Auto";
|
|
44
|
+
/**
|
|
45
|
+
* `LlmError` code: the effective chain is empty — the virtual route has no
|
|
46
|
+
* head to delegate to (P1 guard).
|
|
47
|
+
*/
|
|
48
|
+
export declare const EMPTY_EFFECTIVE_CHAIN_CODE = "EMPTY_EFFECTIVE_CHAIN";
|
|
49
|
+
/**
|
|
50
|
+
* `LlmError` code: the effective chain head is not a dispatchable real pair
|
|
51
|
+
* (non-conforming all-day, wildcard selector, malformed selector, or a
|
|
52
|
+
* self-route back to `FallbacksChain/*` — the P1 recursion guard).
|
|
53
|
+
*/
|
|
54
|
+
export declare const UNDISPATCHABLE_HEAD_CODE = "UNDISPATCHABLE_EFFECTIVE_HEAD";
|
|
55
|
+
/** `LlmError` code (defensive): the `llm` runtime disappeared mid-flight. */
|
|
56
|
+
export declare const LLM_UNAVAILABLE_CODE = "LLM_UNAVAILABLE";
|
|
57
|
+
/** One dispatchable exact head: `provider/model`. Wildcards are never seeds (P3). */
|
|
58
|
+
export interface EffectiveHead {
|
|
59
|
+
provider: string;
|
|
60
|
+
model: string;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* The FIRST DISPATCHABLE exact head of a chain — the single definition of
|
|
64
|
+
* "effective head" (F-001) shared by the root select-is-primary override
|
|
65
|
+
* (`src/index.ts`) and the virtual adapter's delegate paths. Walks the SAME
|
|
66
|
+
* chain `resolveEffectiveChain` produces, skipping entries that can never
|
|
67
|
+
* be dispatched: malformed selectors (config-warning path), `provider/*`
|
|
68
|
+
* `provider/*` wildcards (no real pair), and self-routes back to
|
|
69
|
+
* `FallbacksChain/*` (the P1 recursion guard). `undefined` when the chain
|
|
70
|
+
* is empty or no entry is dispatchable.
|
|
71
|
+
*/
|
|
72
|
+
export declare function firstDispatchableExactHead(chain: readonly string[]): EffectiveHead | undefined;
|
|
73
|
+
/**
|
|
74
|
+
* Host picker label: `Auto: <displayName>[<slot>]`.
|
|
75
|
+
* Display name first so the trigger stays readable and platforms stay
|
|
76
|
+
* distinguishable (catalog `name`, not the model id). Bare `Auto` when
|
|
77
|
+
* there is no dispatchable head. Slot label from {@link resolveSlotState}.
|
|
78
|
+
* @param modelDisplayName - catalog/resolved name; falls back to the id.
|
|
79
|
+
*/
|
|
80
|
+
export declare function pickerDisplayName(config: FallbacksConfig, now?: Date, modelDisplayName?: string): string;
|
|
81
|
+
/**
|
|
82
|
+
* Install the virtual adapter registration lifecycle (P2).
|
|
83
|
+
*
|
|
84
|
+
* @param ctx - the plugin context.
|
|
85
|
+
* @param readConfig - live config reader (the same `source()` the runtime
|
|
86
|
+
* reads, so reconcile always sees COMMITTED composed snapshots).
|
|
87
|
+
* @returns the reconcile thunk — call it from the settings `onChange` hook
|
|
88
|
+
* (child activation runs one reconcile on its own).
|
|
89
|
+
*/
|
|
90
|
+
export declare function installFallbacksAdapter(ctx: Context, readConfig: () => FallbacksConfig): () => void;
|