dsh-autotier 0.1.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.
Files changed (60) hide show
  1. package/AGENTS.md +93 -0
  2. package/CHANGELOG.md +85 -0
  3. package/LICENSE +201 -0
  4. package/README.es.md +247 -0
  5. package/README.hi.md +241 -0
  6. package/README.md +245 -0
  7. package/README.pt.md +246 -0
  8. package/README.zh.md +221 -0
  9. package/SECURITY.md +55 -0
  10. package/THIRD_PARTY_NOTICES.md +63 -0
  11. package/cordis.patch.yml +125 -0
  12. package/docs/preset-row.md +61 -0
  13. package/docs/supporting-lanes.md +45 -0
  14. package/lib/index.js +2848 -0
  15. package/lib/types/command.d.ts +17 -0
  16. package/lib/types/command.d.ts.map +1 -0
  17. package/lib/types/config.d.ts +94 -0
  18. package/lib/types/config.d.ts.map +1 -0
  19. package/lib/types/guard-rules.d.ts +97 -0
  20. package/lib/types/guard-rules.d.ts.map +1 -0
  21. package/lib/types/guard.d.ts +70 -0
  22. package/lib/types/guard.d.ts.map +1 -0
  23. package/lib/types/index.d.ts +60 -0
  24. package/lib/types/index.d.ts.map +1 -0
  25. package/lib/types/intent.d.ts +179 -0
  26. package/lib/types/intent.d.ts.map +1 -0
  27. package/lib/types/judge.d.ts +50 -0
  28. package/lib/types/judge.d.ts.map +1 -0
  29. package/lib/types/policy.d.ts +109 -0
  30. package/lib/types/policy.d.ts.map +1 -0
  31. package/lib/types/routing.d.ts +135 -0
  32. package/lib/types/routing.d.ts.map +1 -0
  33. package/lib/types/schema.d.ts +134 -0
  34. package/lib/types/schema.d.ts.map +1 -0
  35. package/lib/types/service.d.ts +67 -0
  36. package/lib/types/service.d.ts.map +1 -0
  37. package/lib/types/state.d.ts +46 -0
  38. package/lib/types/state.d.ts.map +1 -0
  39. package/lib/types/tiers.d.ts +103 -0
  40. package/lib/types/tiers.d.ts.map +1 -0
  41. package/lib/types/tools.d.ts +26 -0
  42. package/lib/types/tools.d.ts.map +1 -0
  43. package/lib/types/types.d.ts +96 -0
  44. package/lib/types/types.d.ts.map +1 -0
  45. package/package.json +179 -0
  46. package/src/command.ts +73 -0
  47. package/src/config.ts +358 -0
  48. package/src/guard-rules.ts +303 -0
  49. package/src/guard.ts +285 -0
  50. package/src/index.ts +149 -0
  51. package/src/intent.ts +484 -0
  52. package/src/judge.ts +150 -0
  53. package/src/policy.ts +246 -0
  54. package/src/routing.ts +575 -0
  55. package/src/schema.ts +295 -0
  56. package/src/service.ts +131 -0
  57. package/src/state.ts +134 -0
  58. package/src/tiers.ts +212 -0
  59. package/src/tools.ts +128 -0
  60. package/src/types.ts +120 -0
@@ -0,0 +1,109 @@
1
+ /**
2
+ * The routing decision state machine: it turns one classified intent plus the
3
+ * per-agent runtime state into the tier to apply, and owns the TTL semantics of
4
+ * escalation, fallback and the judge cooldown. Pure and synchronous — the
5
+ * asynchronous judge call lives in `judge.ts`.
6
+ *
7
+ * @module dsh-autotier/policy
8
+ */
9
+ import type { ResolvedConfig } from './config.js';
10
+ import type { IntentInput, IntentResult, RuleHit } from './intent.js';
11
+ import { type FallbackRecord } from './tiers.js';
12
+ import type { RouteSource, RoutingMode, TierId } from './types.js';
13
+ /** Mutable per-agent routing state. Never persisted: it is per-process runtime. */
14
+ export interface RouteState {
15
+ /** The decision for the newest user input, reused by every step of its turn. */
16
+ decision: IntentResult | undefined;
17
+ /** The classifier input the decision was computed from. */
18
+ input: IntentInput | undefined;
19
+ /** Session-level override set by `/tier`; `undefined` = follow the configuration. */
20
+ override: RoutingMode | undefined;
21
+ /** The tier actually applied to the last request (hysteresis anchor). */
22
+ appliedTier: TierId | undefined;
23
+ /** The source that produced `appliedTier`; hysteresis only damps classifier-driven changes. */
24
+ appliedSource: RouteSource | undefined;
25
+ /** Plan mode as last observed. */
26
+ planActive: boolean;
27
+ /** Failure escalation. */
28
+ escalation: {
29
+ count: number;
30
+ signature: string;
31
+ until: number;
32
+ rung: number;
33
+ lastAt: number;
34
+ } | undefined;
35
+ /** Fallback-chain position (scoped to one tier). */
36
+ fallback: FallbackRecord | undefined;
37
+ /** Judge resilience. */
38
+ judge: {
39
+ failures: number;
40
+ lastCall: number;
41
+ };
42
+ /** Attempt-first band: the strong review has already run for this input. */
43
+ verified: boolean;
44
+ /** The fingerprint that owes one strong review after a cheap-run signal. */
45
+ reviewOwedFor: string | undefined;
46
+ /** The posterior exploration roll, taken once per user input. */
47
+ probe: 'strong' | 'cheap' | undefined;
48
+ /** How many calls the guard denied for this agent. */
49
+ denials: number;
50
+ /** The last rule the guard fired, for `/tier status`. */
51
+ lastDenial: string;
52
+ }
53
+ /** A fresh per-agent state. */
54
+ export declare function createRouteState(): RouteState;
55
+ /** One routing decision with provenance. */
56
+ export interface Decision {
57
+ readonly tier: TierId;
58
+ readonly source: RouteSource;
59
+ readonly reason: string;
60
+ readonly confidence: number;
61
+ }
62
+ /** Inputs to {@link decideTier}. */
63
+ export interface DecideInput {
64
+ readonly config: ResolvedConfig;
65
+ readonly state: RouteState;
66
+ readonly intent: IntentResult;
67
+ readonly rule: RuleHit | null;
68
+ /** Session/plugin override; `undefined` means the configured routing mode. */
69
+ readonly override: RoutingMode | undefined;
70
+ readonly now: number;
71
+ }
72
+ /** Whether the current failure escalation is still in force. */
73
+ export declare function escalationActive(state: RouteState, now: number): boolean;
74
+ /**
75
+ * Resolve the tier for the current step.
76
+ *
77
+ * Precedence (highest first): explicit override, active failure escalation,
78
+ * plan mode, declarative rule, fingerprint posterior, classifier verdict.
79
+ * Hysteresis applies only to the classifier verdict, so an explicit override
80
+ * or an escalation takes effect immediately.
81
+ *
82
+ * @param input - the live state and the classification.
83
+ * @returns the decision with its provenance.
84
+ */
85
+ export declare function decideTier(input: DecideInput): Decision;
86
+ /** Whether the low-confidence judge should be consulted for this input. */
87
+ export declare function judgeNeeded(config: ResolvedConfig, state: RouteState, intent: IntentResult, rule: RuleHit | null, now: number): boolean;
88
+ /** Whether the middle band should start cheap and verify on a signal. */
89
+ export declare function attemptBandApplies(config: ResolvedConfig, intent: IntentResult): boolean;
90
+ /** Record one judge call attempt. */
91
+ export declare function noteJudgeCall(state: RouteState, now: number, ok: boolean): void;
92
+ /**
93
+ * Record one failure against the escalation counter.
94
+ * @param state - the agent's state.
95
+ * @param signature - the failure signature (`code|fingerprint`); only identical
96
+ * signatures accumulate when `escalation.signature` is enabled.
97
+ * @param config - the resolved configuration.
98
+ * @param now - current epoch millis.
99
+ * @returns whether this failure escalated the tier.
100
+ */
101
+ export declare function noteFailure(state: RouteState, signature: string, config: ResolvedConfig, now: number): boolean;
102
+ /** Clear an expired escalation lazily. A record that never escalated keeps its window count. */
103
+ export declare function clearExpiredEscalation(state: RouteState, now: number): void;
104
+ /**
105
+ * Advance the agent's fallback chain for one tier after an unusable route.
106
+ * @returns whether a chain entry was taken (false = chain exhausted).
107
+ */
108
+ export declare function noteFallback(state: RouteState, tier: TierId, chainLength: number, config: ResolvedConfig, now: number): boolean;
109
+ //# sourceMappingURL=policy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"policy.d.ts","sourceRoot":"","sources":["../../src/policy.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,135 @@
1
+ /**
2
+ * The routing wiring: the listeners that turn a classification into a tier, and
3
+ * the failure/fallback handlers that keep a cheap run alive.
4
+ *
5
+ * Every registration is an effect on the plugin fiber. The request listener is
6
+ * registered at load time on the root scope with `{ prepend: true }` so it wraps
7
+ * the official `installModelSelection` listener (registered later, during agent
8
+ * setup) and its replacement wins. It always awaits `next()` exactly once and
9
+ * never returns `undefined`: the inner listener destructures the result without
10
+ * a guard.
11
+ *
12
+ * @module dsh-autotier/routing
13
+ */
14
+ import type { Context } from '@deepseek-ai/cordis';
15
+ import type { Agent } from '@deepseek-ai/dsh-agent';
16
+ import type { AutotierService } from './service.js';
17
+ import type { AgentStateStore } from './state.js';
18
+ import type { RouteSource, TierId, TierRoute } from './types.js';
19
+ /** One proposed tier, offered to third parties on the `autotier/route` event. */
20
+ export interface RouteProposal {
21
+ readonly agent: Agent;
22
+ readonly turn: number;
23
+ readonly step: number;
24
+ readonly tier: TierId;
25
+ readonly source: RouteSource;
26
+ readonly reason: string;
27
+ readonly confidence: number;
28
+ }
29
+ /** A third party's replacement tier. Returning one from a listener vetoes. */
30
+ export interface RouteVeto {
31
+ readonly tier: TierId;
32
+ readonly reason: string;
33
+ }
34
+ /** Emitted whenever the effective tier changes. */
35
+ export interface TierChange {
36
+ readonly agent: Agent;
37
+ readonly from: TierId | undefined;
38
+ readonly to: TierId;
39
+ readonly source: RouteSource;
40
+ readonly reason: string;
41
+ readonly route: TierRoute;
42
+ }
43
+ declare module '@deepseek-ai/cordis' {
44
+ interface Events {
45
+ /**
46
+ * Serial veto over one proposed tier. Listeners run in order and the first
47
+ * one returning a {@link RouteVeto} replaces the proposal.
48
+ * @mode serial
49
+ */
50
+ 'autotier/route'(proposal: RouteProposal): RouteVeto | void | Promise<RouteVeto | void>;
51
+ /**
52
+ * The effective tier changed for one agent.
53
+ * @mode emit
54
+ */
55
+ 'autotier/tier-changed'(payload: TierChange): void;
56
+ }
57
+ }
58
+ /** Options for {@link AutotierRouter}. */
59
+ export interface RouterOptions {
60
+ readonly ctx: Context;
61
+ readonly service: AutotierService;
62
+ readonly states: AgentStateStore;
63
+ }
64
+ /** The router owns every autotier listener. */
65
+ export declare class AutotierRouter {
66
+ private readonly ctx;
67
+ private readonly service;
68
+ private readonly states;
69
+ private readonly pendingJudges;
70
+ /** Per-session classifier counters, keyed by session so no agent registry is needed. */
71
+ private readonly counters;
72
+ /** Router-owned lifetime signal: aborts in-flight judge calls on unload. */
73
+ private readonly lifetime;
74
+ private disposed;
75
+ /**
76
+ * Register every listener on the plugin fiber.
77
+ * @param options - the plugin context, the service and the state store.
78
+ */
79
+ constructor(options: RouterOptions);
80
+ /** Pending judge calls (diagnostics and tests). */
81
+ get judgeCallsInFlight(): number;
82
+ /** The classifier input for one agent. */
83
+ private inputFor;
84
+ /** The per-session classifier counters, created on first use. */
85
+ private counterFor;
86
+ /** The routing mode in force for one agent. */
87
+ private modeFor;
88
+ /** Capture the newest user input, classify it, and start the judge when needed. */
89
+ private onInboxInserted;
90
+ /** Fire the judge without blocking the emit dispatch. */
91
+ private startJudge;
92
+ /** Open plan mode through the service, or through the log when it is absent. */
93
+ private enterPlanMode;
94
+ /**
95
+ * Offer the proposal to third parties on the `autotier/route` serial event.
96
+ * A listener failure is contained, and a listener that never settles cannot
97
+ * stall the turn: the race resolves with our own decision after the timeout.
98
+ * The timer is owned by `ctx.effect`, so unloading clears it (no HMR leak).
99
+ */
100
+ private serialVeto;
101
+ /** The tier landing for one tier, resolving the vision override, an active
102
+ * fallback record, and the effort-first escalation ladder.
103
+ *
104
+ * The ladder is the point of escalation: raise the current model's effort one
105
+ * step at a time (the KV prefix survives and the official notice stays quiet
106
+ * for an effort-only change) before paying for a model switch. `rung` counts
107
+ * how many times escalation has triggered for this agent, so repeated failures
108
+ * walk the ladder instead of jumping to the strongest landing.
109
+ */
110
+ private routeFor;
111
+ /**
112
+ * The configured landing of one tier. `followSession` means the session's own
113
+ * effort wins when it has one; when it has none, the tier's configured effort
114
+ * is the floor (an omitted effort would fall through to the adapter default,
115
+ * which is the strongest level).
116
+ */
117
+ private tierRoute;
118
+ /** Resolve the tier for this step and apply it to the proposed configuration. */
119
+ private onRequest;
120
+ /** The routing body, separated so one try/catch guards the whole seam. */
121
+ private routeRequest;
122
+ /** Count failures and escalate on the configured signature recurrence. */
123
+ private onAgentError;
124
+ /**
125
+ * Walk the tier's fallback chain. Permanent codes switch immediately;
126
+ * transient codes wait for `dsh-llm-retry` to exhaust its own retries first
127
+ * (this listener is registered after it on purpose).
128
+ */
129
+ private onRequestError;
130
+ /** Maintain the classifier counters and the plan-mode fallback fold. */
131
+ private onSessionEvent;
132
+ /** Resolve the agent that owns one session, when the registry is reachable. */
133
+ private agentOf;
134
+ }
135
+ //# sourceMappingURL=routing.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"routing.d.ts","sourceRoot":"","sources":["../../src/routing.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,134 @@
1
+ /**
2
+ * The raw (possibly partial) configuration surface of dsh-autotier: the
3
+ * Schemastery schema the Loader validates and the settings UI renders, plus the
4
+ * interfaces it resolves to. The judgement that turns a raw config into a
5
+ * resolved one lives in `config.ts`, so this module stays free of executable
6
+ * logic (a schema module must not mix function values into its declarations).
7
+ *
8
+ * @module dsh-autotier/schema
9
+ */
10
+ import z from '@deepseek-ai/schemastery';
11
+ import { type CostMode, type EffortId, type RoutingMode, type Scenario } from './types.js';
12
+ /** One fallback landing in a tier's chain (provider/model only; effort follows the target tier). */
13
+ export interface FallbackEntry {
14
+ provider?: string;
15
+ model?: string;
16
+ }
17
+ /** One tier's landing plus its fallback chain. */
18
+ export interface TierConfig {
19
+ provider?: string;
20
+ model?: string;
21
+ effort?: EffortId;
22
+ followSession?: boolean;
23
+ fallback?: FallbackEntry[];
24
+ }
25
+ /** The image-capable landing used when a turn carries images. */
26
+ export interface VisionConfig {
27
+ provider?: string;
28
+ model?: string;
29
+ }
30
+ /** One declarative intent rule: highest priority match wins. */
31
+ export interface IntentRule {
32
+ id?: string;
33
+ when?: {
34
+ patterns?: string[];
35
+ tools?: string[];
36
+ cwd?: string;
37
+ };
38
+ tier?: 'cheap' | 'strong';
39
+ priority?: number;
40
+ }
41
+ /** Low-confidence judge (a cheap model classifies intent only). */
42
+ export interface JudgeConfig {
43
+ enabled?: boolean;
44
+ /** Empty = pick the first catalog model whose id contains `flash`. */
45
+ model?: string;
46
+ temperature?: number;
47
+ maxTokens?: number;
48
+ cooldownMs?: number;
49
+ timeoutMs?: number;
50
+ /** Consecutive judge failures after which this turn skips the judge. */
51
+ unavailableSkip?: number;
52
+ }
53
+ /** Per-scenario switches; a disabled scenario never routes itself. */
54
+ export type ScenarioToggles = {
55
+ [K in Scenario]?: boolean;
56
+ };
57
+ /** Intent classification and arbitration. */
58
+ export interface IntentConfig {
59
+ /** Confidence at or above which the rule layer decides without the judge. */
60
+ ruleThreshold?: number;
61
+ /** Attempt-first middle band; disabled until calibration lands. */
62
+ attemptBand?: {
63
+ enabled?: boolean;
64
+ tauLow?: number;
65
+ };
66
+ /** Application-side double threshold that stops tier flapping. */
67
+ hysteresis?: {
68
+ toStrong?: number;
69
+ toCheap?: number;
70
+ };
71
+ rules?: IntentRule[];
72
+ judge?: JudgeConfig;
73
+ scenarios?: ScenarioToggles;
74
+ costMode?: CostMode;
75
+ }
76
+ /** High-risk guard switches. */
77
+ export interface GuardConfig {
78
+ enabled?: boolean;
79
+ /** Tiers whose execution the guard protects (only `cheap` is meaningful). */
80
+ tiers?: ('cheap')[];
81
+ /** Command/tool names or path prefixes that never trip the guard. */
82
+ whitelist?: string[];
83
+ /** Self-modification surfaces that force strong-tier review. */
84
+ protectedPaths?: string[];
85
+ /** Relationship with dsh-defend: `auto` audits coexistence, `none` stays silent. */
86
+ interopDefend?: 'auto' | 'none';
87
+ }
88
+ /** Failure escalation and TTL fallback. */
89
+ export interface EscalationConfig {
90
+ threshold?: number;
91
+ windowMs?: number;
92
+ ttlMs?: number;
93
+ fallbackTtlMs?: number;
94
+ /** Count same-signature recurrences instead of every failure. */
95
+ signature?: boolean;
96
+ }
97
+ /**
98
+ * Raw (possibly partial) plugin configuration. Every field is optional because
99
+ * the resolver supplies the defaults; {@link resolveConfig} turns it into the
100
+ * fully-resolved {@link ResolvedConfig}.
101
+ */
102
+ export interface Config {
103
+ tiers?: {
104
+ strong?: TierConfig;
105
+ cheap?: TierConfig;
106
+ vision?: VisionConfig;
107
+ };
108
+ intent?: IntentConfig;
109
+ guard?: GuardConfig;
110
+ escalation?: EscalationConfig;
111
+ routingMode?: RoutingMode;
112
+ }
113
+ /** The default strong tier: the catalog's quality-critical model at high effort. */
114
+ export declare const DEFAULT_STRONG: {
115
+ provider: string;
116
+ model: string;
117
+ effort: "high";
118
+ followSession: boolean;
119
+ };
120
+ /** The default cheap tier: the catalog's routine/parallel model at low effort. */
121
+ export declare const DEFAULT_CHEAP: {
122
+ provider: string;
123
+ model: string;
124
+ effort: "low";
125
+ followSession: boolean;
126
+ };
127
+ /** The default vision landing: the catalog's only image-capable model. */
128
+ export declare const DEFAULT_VISION: {
129
+ provider: string;
130
+ model: string;
131
+ };
132
+ /** Schemastery schema: the loader validates and fills defaults before `apply`. */
133
+ export declare const Config: z<Config>;
134
+ //# sourceMappingURL=schema.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../src/schema.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,67 @@
1
+ /**
2
+ * `ctx.autotier`: the Service Provider for autotier's public read surface. The
3
+ * service owns the live resolved configuration, the compiled rule table and the
4
+ * fingerprint posteriors, and serves the status snapshot that `/tier status`,
5
+ * the `tier_status` tool and any third-party consumer read. Routing decisions
6
+ * themselves live in `policy.ts`/`routing.ts`; this class is the stable contract
7
+ * other plugins may depend on.
8
+ * @module dsh-autotier/service
9
+ */
10
+ import { Service, type Context } from '@deepseek-ai/cordis';
11
+ import type { SettingsScope } from '@deepseek-ai/dsh-settings';
12
+ import { type Config, type ResolvedConfig } from './config.js';
13
+ import { PosteriorTable, type CompiledRule } from './intent.js';
14
+ import type { AutotierStatus } from './types.js';
15
+ declare module '@deepseek-ai/cordis' {
16
+ interface Context {
17
+ /** The autotier routing service (absent when the plugin is not composed). */
18
+ autotier: AutotierService;
19
+ }
20
+ }
21
+ /** Dependencies the service needs from the plugin's `apply`. */
22
+ export interface AutotierServiceOptions {
23
+ /** The live settings scope; its value is re-resolved on every committed change. */
24
+ scope: SettingsScope<Config>;
25
+ /** The configuration resolved at mount time (the composition base layer). */
26
+ config: ResolvedConfig;
27
+ }
28
+ /**
29
+ * Service Provider for `ctx.autotier`. Registration rides the owning fiber: the
30
+ * plugin unloading removes the service with every listener it owns.
31
+ */
32
+ export declare class AutotierService extends Service {
33
+ private readonly scope;
34
+ private readonly posteriorTable;
35
+ private resolved;
36
+ private compiled;
37
+ /**
38
+ * Register the service as `ctx.autotier` and start following the settings
39
+ * namespace.
40
+ * @param ctx - the owning plugin context.
41
+ * @param options - the live settings scope and the mount-time configuration.
42
+ */
43
+ constructor(ctx: Context, options: AutotierServiceOptions);
44
+ /** The live resolved configuration. */
45
+ config(): ResolvedConfig;
46
+ /** The compiled declarative rule table, ordered by descending priority. */
47
+ rules(): readonly CompiledRule[];
48
+ /** The per-fingerprint win-rate posteriors. */
49
+ posteriors(): PosteriorTable;
50
+ /**
51
+ * The registered provider/model catalog, as the minimal serializable subset a
52
+ * configuration UI needs. Never hardcoded: it reads the live `ctx.llm`
53
+ * registry, so a model the adapter does not advertise cannot be selected.
54
+ * @returns one entry per registered provider with its models.
55
+ */
56
+ catalog(): Promise<{
57
+ provider: string;
58
+ models: {
59
+ id: string;
60
+ name: string;
61
+ inputModalities: readonly string[];
62
+ }[];
63
+ }[]>;
64
+ /** Read-only status snapshot. */
65
+ status(): AutotierStatus;
66
+ }
67
+ //# sourceMappingURL=service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../src/service.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,OAAO,EAAE,KAAK,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAC3D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAA;AAC9D,OAAO,EAAiB,KAAK,MAAM,EAAE,KAAK,cAAc,EAAE,MAAM,aAAa,CAAA;AAC7E,OAAO,EAAgB,cAAc,EAAE,KAAK,YAAY,EAAE,MAAM,aAAa,CAAA;AAC7E,OAAO,KAAK,EAAE,cAAc,EAAuB,MAAM,YAAY,CAAA;AAErE,OAAO,QAAQ,qBAAqB,CAAC;IACnC,UAAU,OAAO;QACf,6EAA6E;QAC7E,QAAQ,EAAE,eAAe,CAAA;KAC1B;CACF;AAED,gEAAgE;AAChE,MAAM,WAAW,sBAAsB;IACrC,mFAAmF;IACnF,KAAK,EAAE,aAAa,CAAC,MAAM,CAAC,CAAA;IAC5B,6EAA6E;IAC7E,MAAM,EAAE,cAAc,CAAA;CACvB;AAQD;;;GAGG;AACH,qBAAa,eAAgB,SAAQ,OAAO;IAC1C,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAuB;IAC7C,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAuB;IACtD,OAAO,CAAC,QAAQ,CAAgB;IAChC,OAAO,CAAC,QAAQ,CAAgB;IAEhC;;;;;OAKG;gBACS,GAAG,EAAE,OAAO,EAAE,OAAO,EAAE,sBAAsB;IAezD,uCAAuC;IACvC,MAAM,IAAI,cAAc;IAIxB,2EAA2E;IAC3E,KAAK,IAAI,SAAS,YAAY,EAAE;IAIhC,+CAA+C;IAC/C,UAAU,IAAI,cAAc;IAI5B;;;;;OAKG;IACG,OAAO,IAAI,OAAO,CAAC;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE;YAAE,EAAE,EAAE,MAAM,CAAC;YAAC,IAAI,EAAE,MAAM,CAAC;YAAC,eAAe,EAAE,SAAS,MAAM,EAAE,CAAA;SAAE,EAAE,CAAA;KAAE,EAAE,CAAC;IAqB5H,iCAAiC;IACjC,MAAM,IAAI,cAAc;CAmBzB"}
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Per-agent routing state and the replayable tier projection.
3
+ *
4
+ * Two different kinds of state live here, on purpose:
5
+ *
6
+ * - **Runtime state** (escalation counters, fallback position, judge cooldown,
7
+ * the per-input decision cache, the hysteresis anchor) is mutable and NOT
8
+ * derivable from the session log, so it lives in a `WeakMap<Agent, RouteState>`.
9
+ * `ctx.sessionProjections` is a read-only fold registry — it exposes
10
+ * `register`/`stateOf`/`snapshot` and has no setter — so runtime state cannot
11
+ * live there; the earlier design note that said otherwise is corrected here.
12
+ * - **Derived state** (which route the last request actually used, and whether
13
+ * plan mode is active) IS a pure fold over `request/header` and `plan/mode`,
14
+ * so it is registered as a host+wire projection key. That makes the effective
15
+ * tier replayable from the log and visible to clients.
16
+ *
17
+ * @module dsh-autotier/state
18
+ */
19
+ import type { Context } from '@deepseek-ai/cordis';
20
+ import type { Agent } from '@deepseek-ai/dsh-agent';
21
+ import { type RouteState } from './policy.js';
22
+ /** The projection key autotier owns. */
23
+ export declare const TIER_PROJECTION_KEY = "autotier";
24
+ /** Host fold state for the tier projection (plain JSON by contract). */
25
+ export interface TierProjectionState {
26
+ provider: string;
27
+ model: string;
28
+ /** Empty string = the route carries no explicit effort. */
29
+ effort: string;
30
+ plan: boolean;
31
+ }
32
+ /**
33
+ * Register the tier projection when the registry is composed.
34
+ * @param ctx - the plugin context; the registration rides its fiber.
35
+ * @returns the registration disposer, or undefined when the registry is absent.
36
+ */
37
+ export declare function registerTierProjection(ctx: Context): (() => void) | undefined;
38
+ /** The per-agent runtime state store. */
39
+ export declare class AgentStateStore {
40
+ private readonly states;
41
+ /** The state for one agent, created on first use. */
42
+ for(agent: Agent): RouteState;
43
+ /** Whether one agent already has state (diagnostics). */
44
+ has(agent: Agent): boolean;
45
+ }
46
+ //# sourceMappingURL=state.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../../src/state.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAClD,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,wBAAwB,CAAA;AAKnD,OAAO,EAAoB,KAAK,UAAU,EAAE,MAAM,aAAa,CAAA;AAE/D,wCAAwC;AACxC,eAAO,MAAM,mBAAmB,aAAa,CAAA;AAE7C,wEAAwE;AACxE,MAAM,WAAW,mBAAmB;IAClC,QAAQ,EAAE,MAAM,CAAA;IAChB,KAAK,EAAE,MAAM,CAAA;IACb,2DAA2D;IAC3D,MAAM,EAAE,MAAM,CAAA;IACd,IAAI,EAAE,OAAO,CAAA;CACd;AAoCD;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,OAAO,GAAG,CAAC,MAAM,IAAI,CAAC,GAAG,SAAS,CAmC7E;AAED,yCAAyC;AACzC,qBAAa,eAAe;IAC1B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAmC;IAE1D,qDAAqD;IACrD,GAAG,CAAC,KAAK,EAAE,KAAK,GAAG,UAAU;IAS7B,yDAAyD;IACzD,GAAG,CAAC,KAAK,EAAE,KAAK,GAAG,OAAO;CAG3B"}
@@ -0,0 +1,103 @@
1
+ /**
2
+ * Pure tier arithmetic: the adapter-owned effort ladder, tier-route
3
+ * application, the effort-first escalation ladder, and the fallback-chain
4
+ * classifier/advance helpers.
5
+ *
6
+ * The fallback vocabulary is ported from `dsh-tier-router`'s `lib/pure.js`
7
+ * (MIT; see `THIRD_PARTY_NOTICES.md`), with two corrections: the effort ladder
8
+ * is DeepSeek's `off | low | high | max` (upstream's `medium` does not exist and
9
+ * would fail every request with `UNSUPPORTED_REASONING_EFFORT`), and the
10
+ * classification is split into permanent/transient so the request-error handler
11
+ * can honour the division of labour with `dsh-llm-retry` (permanent codes switch
12
+ * the chain immediately; transient codes wait for retry exhaustion).
13
+ *
14
+ * @module dsh-autotier/tiers
15
+ */
16
+ import type { LlmCallConfig } from '@deepseek-ai/dsh-llm';
17
+ import type { EffortId, TierId, TierRoute } from './types.js';
18
+ /** The adapter-owned effort ladder, cheapest to strongest. */
19
+ export declare const EFFORT_LADDER: readonly ["off", "low", "high", "max"];
20
+ /** Position of one effort on the ladder (0..3); unknown ids rank lowest. */
21
+ export declare function effortRank(effort: string): number;
22
+ /**
23
+ * The next effort step above `current`, never above `ceiling`.
24
+ * @param current - the effort currently in force.
25
+ * @param ceiling - the strongest effort to consider (default `max`).
26
+ * @returns the next effort id, or null when already at or above the ceiling.
27
+ */
28
+ export declare function nextEffortStep(current: EffortId, ceiling?: EffortId): EffortId | null;
29
+ /** Whether two routes land on the same provider/model/effort triple. */
30
+ export declare function routeEquals(a: TierRoute, b: TierRoute): boolean;
31
+ /**
32
+ * Apply one tier route to a request configuration. The sampling scalars the
33
+ * session already chose (`temperature`, `maxTokens`, `stop`) are preserved
34
+ * exactly; the provider/model/effort triple is replaced. Returns the input
35
+ * object unchanged when the route already matches, so the caller can skip a
36
+ * logged header change.
37
+ *
38
+ * @param base - the configuration the loop proposed.
39
+ * @param target - the tier landing to apply.
40
+ * @returns the replacement configuration (or `base` when identical).
41
+ */
42
+ export declare function resolveRoute(base: LlmCallConfig, target: TierRoute): LlmCallConfig;
43
+ /** One rung of the effort-first escalation ladder. */
44
+ export interface EscalationRung {
45
+ /** The landing this rung applies. */
46
+ readonly route: TierRoute;
47
+ /** The tier the rung belongs to (an effort rung on the cheap model is still cheap). */
48
+ readonly tier: TierId;
49
+ /** Why this rung exists, for logs and `/tier status`. */
50
+ readonly note: string;
51
+ }
52
+ /**
53
+ * Build the effort-first escalation ladder: raise the current model's effort
54
+ * one step at a time (the KV prefix survives, and the official model-selection
55
+ * notice is not emitted for an effort-only change) before paying for a model
56
+ * switch. When both tiers share one model the ladder collapses to a single
57
+ * effort-only rung.
58
+ *
59
+ * @param base - the configuration the loop proposed for the failing step.
60
+ * @param cheap - the cheap tier landing.
61
+ * @param strong - the strong tier landing.
62
+ * @returns the ordered rungs; empty when escalation cannot change anything.
63
+ */
64
+ export declare function escalationLadder(base: LlmCallConfig, cheap: TierRoute, strong: TierRoute): EscalationRung[];
65
+ /** Failure codes that mean the route itself is unusable: switch the chain now. */
66
+ export declare const FALLBACK_PERMANENT_CODES: readonly ["UNKNOWN_MODEL", "MISSING_CREDENTIAL", "INVALID_CREDENTIAL", "QUOTA"];
67
+ /** Failure codes owned by `dsh-llm-retry` first: switch the chain only after retries are exhausted. */
68
+ export declare const FALLBACK_TRANSIENT_CODES: readonly ["RATE_LIMIT", "SERVER", "TIMEOUT", "TRANSPORT"];
69
+ /** Failure codes that must never switch the model. */
70
+ export declare const FALLBACK_IGNORE_CODES: readonly ["CONTEXT_WINDOW_EXCEEDED", "UNSUPPORTED_REASONING_EFFORT", "ABORTED", "EMPTY_RESPONSE"];
71
+ /** How one failure relates to the fallback chain. */
72
+ export type FallbackClass = 'permanent' | 'transient' | 'ignore' | 'unknown';
73
+ /**
74
+ * Classify one failed model request for the fallback machinery.
75
+ * @param failure - the normalized failure facts (`code` and optional `status`).
76
+ * @returns the chain verdict.
77
+ */
78
+ export declare function classifyFallback(failure: {
79
+ code?: unknown;
80
+ status?: unknown;
81
+ } | undefined): FallbackClass;
82
+ /** One agent's position in one tier's fallback chain. */
83
+ export interface FallbackRecord {
84
+ /** The tier whose chain this record belongs to. */
85
+ tier: TierId;
86
+ /** Index in that tier's chain; -1 means the tier's own landing. */
87
+ index: number;
88
+ /** Epoch millis until which the record stays in force. */
89
+ until: number;
90
+ }
91
+ /** Whether a fallback record is currently pinning the agent to a chain entry. */
92
+ export declare function fallbackActive(record: FallbackRecord | undefined, now: number): boolean;
93
+ /**
94
+ * Advance a fallback record one step down one tier's chain.
95
+ * @param record - the current record (absent or from another tier = start of this chain).
96
+ * @param tier - the tier whose chain is being walked.
97
+ * @param chainLength - the number of configured fallback entries.
98
+ * @param now - current epoch millis.
99
+ * @param ttlMs - how long the new entry stays in force.
100
+ * @returns the next record, or null when the chain is exhausted.
101
+ */
102
+ export declare function advanceFallback(record: FallbackRecord | undefined, tier: TierId, chainLength: number, now: number, ttlMs: number): FallbackRecord | null;
103
+ //# sourceMappingURL=tiers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tiers.d.ts","sourceRoot":"","sources":["../../src/tiers.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAA;AACzD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,YAAY,CAAA;AAE7D,8DAA8D;AAC9D,eAAO,MAAM,aAAa,wCAAuE,CAAA;AAEjG,4EAA4E;AAC5E,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAGjD;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,QAAQ,EAAE,OAAO,GAAE,QAAgB,GAAG,QAAQ,GAAG,IAAI,CAK5F;AAED,wEAAwE;AACxE,wBAAgB,WAAW,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,SAAS,GAAG,OAAO,CAE/D;AASD;;;;;;;;;;GAUG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,aAAa,EAAE,MAAM,EAAE,SAAS,GAAG,aAAa,CAalF;AAED,sDAAsD;AACtD,MAAM,WAAW,cAAc;IAC7B,qCAAqC;IACrC,QAAQ,CAAC,KAAK,EAAE,SAAS,CAAA;IACzB,uFAAuF;IACvF,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,yDAAyD;IACzD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CACtB;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,aAAa,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,GAAG,cAAc,EAAE,CAkC3G;AAED,kFAAkF;AAClF,eAAO,MAAM,wBAAwB,iFAK3B,CAAA;AAEV,uGAAuG;AACvG,eAAO,MAAM,wBAAwB,2DAA4D,CAAA;AAEjG,sDAAsD;AACtD,eAAO,MAAM,qBAAqB,mGAKxB,CAAA;AAEV,qDAAqD;AACrD,MAAM,MAAM,aAAa,GAAG,WAAW,GAAG,WAAW,GAAG,QAAQ,GAAG,SAAS,CAAA;AAE5E;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE;IAAE,IAAI,CAAC,EAAE,OAAO,CAAC;IAAC,MAAM,CAAC,EAAE,OAAO,CAAA;CAAE,GAAG,SAAS,GAAG,aAAa,CAUzG;AAED,yDAAyD;AACzD,MAAM,WAAW,cAAc;IAC7B,mDAAmD;IACnD,IAAI,EAAE,MAAM,CAAA;IACZ,mEAAmE;IACnE,KAAK,EAAE,MAAM,CAAA;IACb,0DAA0D;IAC1D,KAAK,EAAE,MAAM,CAAA;CACd;AAED,iFAAiF;AACjF,wBAAgB,cAAc,CAAC,MAAM,EAAE,cAAc,GAAG,SAAS,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAEvF;AAED;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAC7B,MAAM,EAAE,cAAc,GAAG,SAAS,EAClC,IAAI,EAAE,MAAM,EACZ,WAAW,EAAE,MAAM,EACnB,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,MAAM,GACZ,cAAc,GAAG,IAAI,CAKvB"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * The two read-only tools: `tier_status` reports the live routing state, and
3
+ * `tier_route` dry-runs the classifier on one intent string without sending a
4
+ * model request.
5
+ * @module dsh-autotier/tools
6
+ */
7
+ import type { Context } from '@deepseek-ai/cordis';
8
+ import { type ToolDefinition } from '@deepseek-ai/dsh-tools';
9
+ import type { AutotierService } from './service.js';
10
+ import type { AgentStateStore } from './state.js';
11
+ /** Services the tools read. */
12
+ export interface ToolServices {
13
+ readonly service: AutotierService;
14
+ readonly states: AgentStateStore;
15
+ }
16
+ /** Build the `tier_status` tool. */
17
+ export declare function tierStatusTool({ service, states }: ToolServices): ToolDefinition;
18
+ /** Build the `tier_route` tool. */
19
+ export declare function tierRouteTool({ service }: ToolServices): ToolDefinition;
20
+ /**
21
+ * Register both tools on the plugin fiber.
22
+ * @param ctx - the plugin context (must have `tools`).
23
+ * @param services - the service and the state store.
24
+ */
25
+ export declare function registerTierTools(ctx: Context, services: ToolServices): void;
26
+ //# sourceMappingURL=tools.d.ts.map