dsh-llm-fallbacks 0.3.4 → 0.4.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/dist/gateway.d.ts CHANGED
@@ -59,12 +59,73 @@
59
59
  * @module dsh-llm-fallbacks/gateway
60
60
  */
61
61
  import type { Context } from '@deepseek-ai/cordis';
62
+ import type { SettingsNamespace } from '@deepseek-ai/dsh-settings';
62
63
  import { TypertRemoteService } from '@deepseek-ai/dsh-typert-protocol';
63
64
  import type { TypertContribution } from '@deepseek-ai/dsh-typert-registry';
64
65
  import type { FallbacksConfig } from './config';
65
66
  import type { FallbacksSeedManager, SeedRevertOutcome, SeedsWireStatus } from './seeds';
66
- /** The `fallbacks` settings namespace (registered when a settings service exists). */
67
- export declare const FALLBACKS_SETTINGS_NAMESPACE: import("@deepseek-ai/dsh-settings").SettingsNamespace;
67
+ /**
68
+ * The `fallbacks` settings namespace (registered when a settings service
69
+ * exists). 0.1.2 removed the `settingsNamespace` helper: the registered
70
+ * namespace is the lowercase-hyphenated literal itself, branded through the
71
+ * `SettingsNamespace` type the service APIs constrain on.
72
+ */
73
+ export declare const FALLBACKS_SETTINGS_NAMESPACE: SettingsNamespace;
74
+ /** One exact child LLM route on the additive `subagentPolicy` wire field (T5). */
75
+ export type SubagentPolicyRoute = {
76
+ provider: string;
77
+ model: string;
78
+ };
79
+ /**
80
+ * Additive `/api/fallbacks/get` host-policy snapshot (spec D4 / T5).
81
+ * Omitted only when the snapshot is unwired (3-arg constructor) so older
82
+ * clients and gateway unit tests keep a byte-identical `{ config,
83
+ * legacyKeys, seeds }` payload. A wired snapshot always emits the field —
84
+ * `{ state: 'disabled' }` included — so a write after an enabled get cannot
85
+ * keep-last an allowlist. Never written through `set`/`reset`.
86
+ */
87
+ export type SubagentPolicyWire = {
88
+ state: 'enabled';
89
+ allowedModels: SubagentPolicyRoute[];
90
+ head?: {
91
+ route: SubagentPolicyRoute;
92
+ source: 'authorized' | 'injected';
93
+ };
94
+ blockedAttempt?: {
95
+ at: number;
96
+ route: SubagentPolicyRoute;
97
+ reason: string;
98
+ };
99
+ } | {
100
+ state: 'disabled';
101
+ } | {
102
+ state: 'unprovable';
103
+ };
104
+ /**
105
+ * Live host-policy snapshot the gateway projects onto the wire. Built in
106
+ * `apply()` from the SAME T1 reader the override paths use — no second
107
+ * policy source. Optional: the 3-arg constructor (gateway unit tests)
108
+ * omits the field entirely.
109
+ */
110
+ export type SubagentPolicySnapshotFn = () => {
111
+ policy: {
112
+ state: 'disabled';
113
+ } | {
114
+ state: 'enabled';
115
+ allowedModels: readonly SubagentPolicyRoute[];
116
+ } | {
117
+ state: 'unprovable';
118
+ };
119
+ head?: {
120
+ route: SubagentPolicyRoute;
121
+ source: 'authorized' | 'injected';
122
+ };
123
+ blockedAttempt?: {
124
+ at: number;
125
+ route: SubagentPolicyRoute;
126
+ reason: string;
127
+ };
128
+ };
68
129
  /**
69
130
  * The live configuration source for the gateway (guide §7 — the same bridge
70
131
  * shape the runtime reads through). `source()` returns the live composed
@@ -87,6 +148,13 @@ export interface FallbacksReadResult {
87
148
  config: FallbacksConfig;
88
149
  legacyKeys: string[];
89
150
  seeds: SeedsWireStatus[];
151
+ /**
152
+ * Host subagent-model-selection policy (spec D4). Additive — old readers
153
+ * ignore it; omitted only when no snapshot is wired. A wired snapshot
154
+ * always carries the field (`disabled` included) so keep-last cannot
155
+ * retain an allowlist after policy-off.
156
+ */
157
+ subagentPolicy?: SubagentPolicyWire;
90
158
  }
91
159
  /** The `fallbacks/revert-seed` response — a read result plus the revert outcome. */
92
160
  export interface FallbacksRevertResult extends FallbacksReadResult {
@@ -110,6 +178,12 @@ export declare class FallbacksConfigGateway extends TypertRemoteService {
110
178
  private readonly seeds;
111
179
  /** The live settings service once the optional inject child activates. */
112
180
  private settings;
181
+ /**
182
+ * Optional host-policy snapshot (T5). When omitted the additive
183
+ * `subagentPolicy` field is absent on every read — the 3-arg constructor
184
+ * used by gateway unit tests stays byte-identical to the pre-T5 payload.
185
+ */
186
+ private readonly subagentPolicy;
113
187
  /**
114
188
  * @param ctx - owning context (the plugin fiber's ctx inside `apply`).
115
189
  * @param bridge - the same `FallbacksSettingsBridge` the runtime reads, so
@@ -117,8 +191,10 @@ export declare class FallbacksConfigGateway extends TypertRemoteService {
117
191
  * @param seeds - the per-apply `FallbacksSeedManager` constructed in
118
192
  * `apply()` — the gateway delegates badge state and revert to it (no
119
193
  * copied manager logic), through the io seam built over this bridge.
194
+ * @param subagentPolicy - live host-policy snapshot from `apply()`; omit
195
+ * to leave the additive field off the wire.
120
196
  */
121
- constructor(ctx: Context, bridge: FallbacksSettingsBridge, seeds: FallbacksSeedManager);
197
+ constructor(ctx: Context, bridge: FallbacksSettingsBridge, seeds: FallbacksSeedManager, subagentPolicy?: SubagentPolicySnapshotFn);
122
198
  /**
123
199
  * Read the current composed config (schema defaults → entry base → settings
124
200
  * user layer). No hard-gate resolver (ADR-2): the raw composed config is
package/dist/index.d.ts CHANGED
@@ -16,8 +16,9 @@
16
16
  * cooldown + failure bookkeeping, then return
17
17
  * `{ kind: 'retry' }` (own recovery, no `next()`).
18
18
  * - `agent/request` waterfall: apply a pending switch after `await next()`
19
- * (provider/model override, inherited `reasoningEffort` dropped — the
20
- * `installModelSelection` `withoutInheritedEffort` pattern); a
19
+ * (provider/model override; the inherited `reasoningEffort` follows the
20
+ * upstream routeChanged rule — dropped on a route change unless explicitly
21
+ * named, preserved on a same-route override; spec D3); a
21
22
  * root-origin `FallbacksChain/Auto` seed then overrides to the
22
23
  * effective chain's first exact head (select-is-primary, plan
23
24
  * fallbacks-virtual-chain Task 2); then the always-mode cap check (count
@@ -36,7 +37,7 @@ import { detectLegacyKeys, validateFallbacksConfig, type FallbacksConfig } from
36
37
  import { Config } from './schema.ts';
37
38
  import { resolveChain } from './chains.ts';
38
39
  import { resolveRole } from './roles.ts';
39
- import { FallbackStateStore } from './state.ts';
40
+ import { FallbackStateStore, type BlockedSwitchAttempt, type EffectiveChainHead } from './state.ts';
40
41
  import { type EffectiveRolesReadback, type SeedDeclaration, type SeedDeclareOutcome, type SeedRevertOutcome } from './seeds.ts';
41
42
  /** The plugin row id mounted by the profile bundle patch. */
42
43
  export declare const name = "llm-fallbacks";
@@ -82,10 +83,12 @@ export { Config };
82
83
  /** The plugin's composition config — the `fallbacks` settings schema (spec §4). */
83
84
  export type Config = FallbacksConfig;
84
85
  export type { FallbackSwitchReason, FallbacksSwitchEventData } from './events.ts';
85
- export type { AgentFallbackState, FallbackStateStore, PendingSwitch, StepFailures } from './state.ts';
86
+ export type { AgentFallbackState, BlockedSwitchAttempt, FallbackStateStore, PendingSwitch, StepFailures } from './state.ts';
87
+ /** @internal T5 test-seam types (mirrors `BlockedSwitchAttempt`; not public API). */
88
+ export type { ChainHeadSource, EffectiveChainHead } from './state.ts';
86
89
  export { resolveRole, type AgentLike, type Origin, } from './roles.ts';
87
90
  export { annotateCandidates, createCandidateFilter, hasWildcardEntry, resolveCandidate, resolveChain, resolveChainViews, selectCandidates, type AnnotatedCandidate, type CandidateFilterOptions, type CandidateSkipReason, type FailingModel, } from './chains.ts';
88
- export { defaultFallbacksConfig, detectLegacyKeys, INHERIT_ROLE_ID, ROLE_ID_PATTERN, validateFallbacksConfig, type FallbacksConfig, type FallbacksConfigLogger, type FallbacksRole, type FallbacksRoles, type FallbacksRoleRule, type FallbackStrategy, type RevertPolicy, } from './config.ts';
91
+ export { defaultFallbacksConfig, detectLegacyKeys, INHERIT_ROLE_ID, ROLE_ID_PATTERN, validateFallbacksConfig, type FallbacksConfig, type FallbacksConfigLogger, type FallbacksRole, type FallbacksRoles, type FallbacksRoleRule, type FallbackStrategy, type RevertPolicy, type RecoveryPolicy, } from './config.ts';
89
92
  export { parseSelector, SelectorError, type Selector, } from './selectors.ts';
90
93
  export { FallbacksSeedManager, type EffectiveRole, type EffectiveRolesReadback, type SeedConflict, type SeedDeclaration, type SeedDeclareOutcome, type SeedRevertFailReason, type SeedRevertOutcome, type SeedSkipReason, type SeedsIo, type SeedsWireStatus, } from './seeds.ts';
91
94
  export { presetRoles } from './presets.ts';
@@ -96,6 +99,23 @@ export { presetRoles } from './presets.ts';
96
99
  * request must not grow the store) without reaching into the closure.
97
100
  */
98
101
  export declare function stateStore(ctx: Context): FallbackStateStore | undefined;
102
+ /**
103
+ * @internal Test seam (mirrors `stateStore`): the per-agent blocked-switch
104
+ * attempts recorded by the T3 allowlist gate for the plugin applied to `ctx`
105
+ * (spec D1; in-memory only, issue #52). Not part of the plugin's public
106
+ * surface; lets tests (and the T5 gateway projection) read blocked attempts
107
+ * without reaching into the closure. `undefined` when no plugin is applied.
108
+ */
109
+ export declare function blockedAttempts(ctx: Context): ReadonlyMap<string, BlockedSwitchAttempt> | undefined;
110
+ /**
111
+ * @internal Test seam (mirrors `blockedAttempts`): the per-agent effective
112
+ * chain heads recorded by the T2 inject path (source `authorized` |
113
+ * `injected`) for the plugin applied to `ctx` (spec D4 / T2 M3). Not part
114
+ * of the plugin's public surface; lets tests and the T5 gateway projection
115
+ * read the head without reaching into the closure. `undefined` when no
116
+ * plugin is applied.
117
+ */
118
+ export declare function chainHeads(ctx: Context): ReadonlyMap<string, EffectiveChainHead> | undefined;
99
119
  /**
100
120
  * Count durable `llm/retry` events for the current (turn, step, provider) in
101
121
  * **always mode** (ADR-2; spec §2 clause 5). Normal-mode retries belong to