dsh-model-switch 0.4.24 → 0.4.26
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/CHANGELOG.md +25 -0
- package/PRODUCT.md +6 -4
- package/README.md +7 -13
- package/README.zh.md +6 -12
- package/cordis.patch.yml +9 -0
- package/lib/auto-review.js +57 -14
- package/lib/client.js +208 -139
- package/lib/compaction.js +97 -2
- package/lib/index.js +1 -301
- package/lib/{provider-group-CsZi7H29.js → provider-group-CwadImhH.js} +3 -9
- package/lib/{session-route-h9SAqajc.js → session-route-BCQFzqRP.js} +1 -1
- package/lib/session-route-BjNPlliu.js +172 -0
- package/lib/session-title.js +387 -34
- package/lib/subagent-runtime.js +26 -3
- package/lib/types/adapter-registry.d.ts +1 -1
- package/lib/types/auto-review.d.ts +38 -11
- package/lib/types/client/ModelSwitchSettings.d.ts +0 -1
- package/lib/types/client/locales.d.ts +2 -5
- package/lib/types/client-contract.d.ts +0 -1
- package/lib/types/compaction.d.ts +50 -6
- package/lib/types/host-settings.d.ts +0 -2
- package/lib/types/provider-group.d.ts +4 -10
- package/lib/types/session-title.d.ts +194 -14
- package/lib/types/subagent-runtime.d.ts +10 -0
- package/package.json +3 -2
- package/lib/types/client/derived-settings-scope.d.ts +0 -4
- package/lib/types/client/picker/main-default-restore.d.ts +0 -56
- package/lib/types/client/picker/provider-group-watch.d.ts +0 -48
- package/lib/types/client/remote-settings-scope.d.ts +0 -45
- package/lib/types/switch-compact.d.ts +0 -72
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { Context } from '@deepseek-ai/cordis';
|
|
2
2
|
import type { Entry, Loader } from '@deepseek-ai/cordis-plugin-loader';
|
|
3
3
|
import type { BasicCompactionConfig } from '@deepseek-ai/dsh-compaction-basic';
|
|
4
|
+
import type { GenerateOptions, StreamChunk } from '@deepseek-ai/dsh-llm';
|
|
4
5
|
/** Cordis plugin identity; matches the cordis.patch.yml insert row id. */
|
|
5
6
|
export declare const name = "model-switch-compaction";
|
|
6
7
|
/** The loader is awaited at row activation; settings and the official row are still read structurally so stock compaction survives a disabled Model Switch row. */
|
|
@@ -8,17 +9,21 @@ export declare const inject: string[];
|
|
|
8
9
|
/**
|
|
9
10
|
* Both identifiers trimmed and non-empty; undefined means "official default".
|
|
10
11
|
*
|
|
11
|
-
*
|
|
12
|
-
* compaction
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
12
|
+
* Each summarization call derives its route per session (the session's provider
|
|
13
|
+
* group → the flat compaction card → the official row's `modelPolicies` /
|
|
14
|
+
* conversation-target fallback) and mutates `options.provider`/`options.model`
|
|
15
|
+
* in place before `ctx.llm.stream(options)` so the official `summarizeWithLlm`
|
|
16
|
+
* returns and durably records the exact route that wrote the summary in
|
|
17
|
+
* `compaction/summary`.
|
|
17
18
|
*/
|
|
18
19
|
export interface CompactionRoute {
|
|
19
20
|
readonly provider: string;
|
|
20
21
|
readonly model: string;
|
|
21
22
|
}
|
|
23
|
+
/** Public llm face the official compaction engine uses (`stream` + `resolveModelInfo`). */
|
|
24
|
+
export interface CompactionLlm {
|
|
25
|
+
stream(options: GenerateOptions): AsyncIterable<StreamChunk>;
|
|
26
|
+
}
|
|
22
27
|
/**
|
|
23
28
|
* Resolve the configurable summarization route from live settings.
|
|
24
29
|
* @param settings - Model Switch settings carrying the optional compaction pair.
|
|
@@ -48,6 +53,45 @@ export declare function officialCompactionEntry(loader: Loader | undefined): Ent
|
|
|
48
53
|
* @returns A plain object spread; missing or invalid configs become `{}`.
|
|
49
54
|
*/
|
|
50
55
|
export declare function forwardedConfig(entry: Entry): BasicCompactionConfig;
|
|
56
|
+
/**
|
|
57
|
+
* Resolve the compaction summarization route for one session id.
|
|
58
|
+
*
|
|
59
|
+
* Looks up the session from `ctx.sessions` when available, derives its current
|
|
60
|
+
* provider (`pending` selection preferred over `lastUsed`, then logged routes),
|
|
61
|
+
* and resolves the provider group's compaction pair before falling back to the
|
|
62
|
+
* deployment-wide compaction pair.
|
|
63
|
+
* @param ctx - this row's context.
|
|
64
|
+
* @param sessionId - the session id carried on `GenerateOptions.sessionId`.
|
|
65
|
+
* @returns The derived compaction route, or undefined for the engine's own route.
|
|
66
|
+
*/
|
|
67
|
+
export declare function resolveSessionCompactionRoute(ctx: Context, sessionId: string | undefined): CompactionRoute | undefined;
|
|
68
|
+
/**
|
|
69
|
+
* Wrap the real llm service so `purpose === 'compaction'` calls resolve their
|
|
70
|
+
* summarization route per session while keeping `compaction/summary` truthful.
|
|
71
|
+
*
|
|
72
|
+
* `summarizeWithLlm` builds a mutable `options` literal with `purpose: 'compaction'`
|
|
73
|
+
* and `sessionId: agent.session.id`, calls `ctx.llm.stream(options)`, and then
|
|
74
|
+
* returns `{ provider: options.provider, model: options.model }` to `commitCompactionBody`.
|
|
75
|
+
* Mutating `options.provider` and `options.model` in place before delegating to
|
|
76
|
+
* `target.stream(options)` ensures the durable `compaction/summary` event
|
|
77
|
+
* records the exact provider/model that wrote the summary. All other members
|
|
78
|
+
* (such as `resolveModelInfo`) pass through bound to `real`.
|
|
79
|
+
* @param real - the host's `ctx.llm`.
|
|
80
|
+
* @param resolve - per-session route resolver; undefined keeps `options` untouched.
|
|
81
|
+
* @param onError - optional error sink when the resolver throws.
|
|
82
|
+
* @returns A transparent Proxy over `real`.
|
|
83
|
+
*/
|
|
84
|
+
export declare function compactionLlm<T extends CompactionLlm>(real: T, resolve: (sessionId: string) => CompactionRoute | undefined, onError?: (cause: unknown) => void): T;
|
|
85
|
+
/**
|
|
86
|
+
* Build the child context the compaction engine mounts under.
|
|
87
|
+
*
|
|
88
|
+
* When `ctx.llm` is present, shadows it with {@link compactionLlm} on an
|
|
89
|
+
* extended context so the child engine fiber resolves the per-session wrapper
|
|
90
|
+
* while registering `ctx.compaction` on the shared context tree.
|
|
91
|
+
* @param ctx - this row's context.
|
|
92
|
+
* @returns A context shadowing `llm` when available, else `ctx`.
|
|
93
|
+
*/
|
|
94
|
+
export declare function compactionScope(ctx: Context): Context;
|
|
51
95
|
/**
|
|
52
96
|
* Whether the compaction capability is actually served from this context.
|
|
53
97
|
*
|
|
@@ -12,7 +12,6 @@ export interface ModelSwitchSettings {
|
|
|
12
12
|
searchModel?: string;
|
|
13
13
|
imageProvider?: string;
|
|
14
14
|
imageModel?: string;
|
|
15
|
-
compactOnSwitch: boolean;
|
|
16
15
|
/** Reviewer provider for the Auto preset; both fields unset = follow the session model. */
|
|
17
16
|
autoReviewProvider?: string;
|
|
18
17
|
/** Reviewer model for the Auto preset; set together with `autoReviewProvider`. */
|
|
@@ -38,7 +37,6 @@ export interface Config {
|
|
|
38
37
|
searchModel: Volatile<string | undefined>;
|
|
39
38
|
imageProvider: Volatile<string | undefined>;
|
|
40
39
|
imageModel: Volatile<string | undefined>;
|
|
41
|
-
compactOnSwitch: Volatile<boolean>;
|
|
42
40
|
autoReviewProvider: Volatile<string | undefined>;
|
|
43
41
|
autoReviewModel: Volatile<string | undefined>;
|
|
44
42
|
compactProvider: Volatile<string | undefined>;
|
|
@@ -1,23 +1,17 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Provider configuration groups: per-provider presets for the
|
|
3
|
-
* and subagent routes.
|
|
2
|
+
* Provider configuration groups: per-provider presets for the compaction,
|
|
3
|
+
* auto-review, session-naming, and subagent routes.
|
|
4
4
|
*
|
|
5
5
|
* A group is a DERIVED policy, not a write: `src/session-route.ts` resolves the
|
|
6
6
|
* routes one session should use from its own provider plus this stored table, so
|
|
7
7
|
* switching a session's provider never rewrites deployment-wide settings and two
|
|
8
8
|
* sessions on different providers cannot overwrite each other. The field names
|
|
9
9
|
* below are the flat settings field names a group pins, which keeps the stored
|
|
10
|
-
* shape identical
|
|
11
|
-
*
|
|
12
|
-
* Legacy entries may still carry `compactProvider`/`compactModel`/
|
|
13
|
-
* `autoReviewProvider`/`autoReviewModel`: normalization preserves them so an
|
|
14
|
-
* older stored document is never silently rewritten into a different meaning,
|
|
15
|
-
* while the consumption side ignores them (a group save from the current UI
|
|
16
|
-
* writes '' for every unsupported field, which normalization drops).
|
|
10
|
+
* shape identical across releases.
|
|
17
11
|
*
|
|
18
12
|
* All functions here are pure and never throw on malformed storage.
|
|
19
13
|
*/
|
|
20
|
-
/** Flat settings fields a provider group carries
|
|
14
|
+
/** Flat settings fields a provider group carries across all four per-session capabilities. */
|
|
21
15
|
export type ProviderGroupRouteField = 'compactProvider' | 'compactModel' | 'autoReviewProvider' | 'autoReviewModel' | 'subagentProvider' | 'subagentModel' | 'subagentReasoningEffort' | 'titleProvider' | 'titleModel';
|
|
22
16
|
/** Stored entry: the owning provider plus every route field; '' means the capability stays at its default. */
|
|
23
17
|
export interface ProviderGroupEntry {
|
|
@@ -8,25 +8,40 @@
|
|
|
8
8
|
* saved group is named through that group's pair while every other session keeps
|
|
9
9
|
* following its own model.
|
|
10
10
|
*
|
|
11
|
-
* The call itself stays inside the official implementation: the
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
* without a registered provider.
|
|
11
|
+
* The call itself stays inside the official implementation: the auxiliary-LLM
|
|
12
|
+
* package records exactly the route that was called in `session/title-llm-request`,
|
|
13
|
+
* so the durable record and the actual request can never disagree. Nothing is
|
|
14
|
+
* remounted when settings change — the route is read through on every naming
|
|
15
|
+
* request — so a settings save can neither interrupt an in-flight naming request
|
|
16
|
+
* nor leave the profile without a registered provider.
|
|
18
17
|
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
18
|
+
* Two official auxiliary-LLM lines are supported, selected at runtime from the
|
|
19
|
+
* module surface, because the 0.2.1 release replaced the shared title call:
|
|
20
|
+
* - Up to DSH 0.2.0 (`generateSessionTitleWithLlm`): the module owns the system
|
|
21
|
+
* prompt, input framing, and output validation; the shared policy carries the
|
|
22
|
+
* title-length targets.
|
|
23
|
+
* - DSH 0.2.1+ (`executeSessionTitleLlm`): the provider owns the system prompt,
|
|
24
|
+
* the input, the reasoning-effort selection, and the output interpretation;
|
|
25
|
+
* the shared policy carries execution controls only. This row mirrors the
|
|
26
|
+
* official provider's wording and interpretation so a configured route keeps
|
|
27
|
+
* the official behavior.
|
|
28
|
+
*
|
|
29
|
+
* A naming request that fails is retried once with a widened output budget
|
|
30
|
+
* (max-token failures only) and then falls through the remaining route
|
|
31
|
+
* candidates — the session group's pair, the deployment-wide pair, the row's own
|
|
32
|
+
* pair, then the session's logged route — so one unavailable model or provider
|
|
33
|
+
* cannot leave the session on its deterministic fallback title forever.
|
|
34
|
+
*
|
|
35
|
+
* `cordis.patch.yml` disables the official rows (the seam allows one registered
|
|
36
|
+
* provider per context), and this row mirrors the cadence a disabled row
|
|
21
37
|
* declared, so a profile that restated the row as all-prompts keeps its cadence.
|
|
22
38
|
*
|
|
23
39
|
* @module dsh-model-switch/session-title
|
|
24
40
|
*/
|
|
25
41
|
import type { Context } from '@deepseek-ai/cordis';
|
|
26
42
|
import type { Entry, Loader } from '@deepseek-ai/cordis-plugin-loader';
|
|
27
|
-
import type { SessionTitleAutomaticMode, SessionTitleProviderId, SessionTitleUserMessage } from '@deepseek-ai/dsh-session-title';
|
|
28
|
-
import type
|
|
29
|
-
import { type CapabilityRoute } from './session-route.js';
|
|
43
|
+
import type { SessionTitleAutomaticMode, SessionTitleProviderId, SessionTitleProviderRequest, SessionTitleUserMessage } from '@deepseek-ai/dsh-session-title';
|
|
44
|
+
import { type CapabilityRoute, type RouteBearingSettings } from './session-route.js';
|
|
30
45
|
/** Cordis plugin identity; matches the cordis.patch.yml insert row id. */
|
|
31
46
|
export declare const name = "model-switch-session-title";
|
|
32
47
|
/** The loader names the disabled row, and the seam services the call needs are awaited before the first naming request. */
|
|
@@ -44,6 +59,57 @@ export interface TitleCadence {
|
|
|
44
59
|
}
|
|
45
60
|
/** Both official cadence packages, in the order a profile may declare them. */
|
|
46
61
|
export declare const TITLE_CADENCES: readonly TitleCadence[];
|
|
62
|
+
/** Title-length targets that shape the system instruction. */
|
|
63
|
+
export interface TitleLengthTargets {
|
|
64
|
+
readonly targetWords: number;
|
|
65
|
+
readonly targetCjkCharacters: number;
|
|
66
|
+
}
|
|
67
|
+
/** Route-bearing execution policy shared by both official auxiliary-LLM lines. */
|
|
68
|
+
export interface TitleLlmPolicy {
|
|
69
|
+
readonly maxInputBytes: number;
|
|
70
|
+
readonly maxOutputTokens: number;
|
|
71
|
+
readonly timeoutMs: number;
|
|
72
|
+
readonly provider?: string;
|
|
73
|
+
readonly model?: string;
|
|
74
|
+
}
|
|
75
|
+
/** The model metadata `executeSessionTitleLlm` hands its reasoning selector. */
|
|
76
|
+
export interface TitleModelMetadata {
|
|
77
|
+
readonly reasoning?: {
|
|
78
|
+
readonly efforts?: readonly {
|
|
79
|
+
readonly id: string;
|
|
80
|
+
}[];
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
/** Provider-owned preparation for one 0.2.1+ auxiliary title request. */
|
|
84
|
+
export interface PreparedTitleCall {
|
|
85
|
+
readonly system: string;
|
|
86
|
+
readonly input: string;
|
|
87
|
+
readonly messageSeqs: readonly SessionTitleUserMessage['seq'][];
|
|
88
|
+
readonly selectReasoningEffort: (model: TitleModelMetadata) => string | undefined;
|
|
89
|
+
}
|
|
90
|
+
/** One content block of the assembled 0.2.1+ auxiliary response. */
|
|
91
|
+
export interface TitleResponseBlock {
|
|
92
|
+
readonly type: string;
|
|
93
|
+
readonly text?: string;
|
|
94
|
+
}
|
|
95
|
+
/** The assembled 0.2.1+ auxiliary response this row interprets. */
|
|
96
|
+
export interface TitleLlmResponse {
|
|
97
|
+
readonly blocks: readonly TitleResponseBlock[];
|
|
98
|
+
readonly finish: {
|
|
99
|
+
readonly kind: string;
|
|
100
|
+
};
|
|
101
|
+
readonly model: {
|
|
102
|
+
readonly provider: string;
|
|
103
|
+
readonly model: string;
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
/** The auxiliary-LLM module surface; the call entry point differs per DSH line. */
|
|
107
|
+
type TitleLlmModule = typeof import('@deepseek-ai/dsh-session-title-llm');
|
|
108
|
+
/** The untrusted policy split both lines consume. */
|
|
109
|
+
export interface SplitTitlePolicy {
|
|
110
|
+
readonly execution: Record<string, unknown>;
|
|
111
|
+
readonly targets: TitleLengthTargets;
|
|
112
|
+
}
|
|
47
113
|
/**
|
|
48
114
|
* The cadence one official package name declares.
|
|
49
115
|
* @param pkg - the disabled row's package name.
|
|
@@ -61,7 +127,7 @@ export declare function titleCadence(pkg: string | undefined): TitleCadence | un
|
|
|
61
127
|
* @param route - session-resolved naming route, or undefined for the row's own policy.
|
|
62
128
|
* @returns A detached config for one naming request.
|
|
63
129
|
*/
|
|
64
|
-
export declare function composeTitleRoute(config:
|
|
130
|
+
export declare function composeTitleRoute(config: TitleLlmPolicy, route: CapabilityRoute | undefined): TitleLlmPolicy;
|
|
65
131
|
/**
|
|
66
132
|
* Frame the exact human messages one naming revision represents.
|
|
67
133
|
* @param messages - every eligible human message of the revision.
|
|
@@ -84,13 +150,126 @@ export declare function officialTitleEntry(loader: Loader | undefined): Entry |
|
|
|
84
150
|
* result is untrusted: the profile may be hand-edited, so the official policy
|
|
85
151
|
* validator runs over it before any naming request is served.
|
|
86
152
|
*/
|
|
87
|
-
export declare function forwardedConfig(entry: Entry):
|
|
153
|
+
export declare function forwardedConfig(entry: Entry): Record<string, unknown>;
|
|
88
154
|
/**
|
|
89
155
|
* The official package name this row mounts (either cadence).
|
|
90
156
|
* @param entry - the official session-title provider entry.
|
|
91
157
|
* @returns The package name, or undefined when the row declares none.
|
|
92
158
|
*/
|
|
93
159
|
export declare function officialTitlePackage(entry: Entry): string | undefined;
|
|
160
|
+
/**
|
|
161
|
+
* Split one untrusted stored policy into the halves both official lines accept.
|
|
162
|
+
*
|
|
163
|
+
* Execution controls pass through untouched (an invalid value still fails the
|
|
164
|
+
* official validator). Absent execution fields fall back to the shipped
|
|
165
|
+
* official defaults, because a profile that mounts no official row has no
|
|
166
|
+
* policy to forward and this row must still run. Title-length targets are read
|
|
167
|
+
* here for the system instruction: the pre-0.2.1 line wants them in its shared
|
|
168
|
+
* config, while 0.2.1 moved them into each provider.
|
|
169
|
+
* @param forwarded - the disabled official row's stored config.
|
|
170
|
+
* @returns The execution subset and the title-length targets.
|
|
171
|
+
*/
|
|
172
|
+
export declare function splitTitlePolicy(forwarded: Record<string, unknown>): SplitTitlePolicy;
|
|
173
|
+
/**
|
|
174
|
+
* Detect the 0.2.1+ auxiliary-LLM line.
|
|
175
|
+
* @param module - the loaded auxiliary-LLM package.
|
|
176
|
+
* @returns Whether the module exposes the provider-prepared call.
|
|
177
|
+
*/
|
|
178
|
+
export declare function isModernTitleModule(module: TitleLlmModule): boolean;
|
|
179
|
+
/** One validated naming policy: the execution config plus the targets the system instruction needs. */
|
|
180
|
+
export interface ResolvedNamingPolicy {
|
|
181
|
+
readonly config: TitleLlmPolicy;
|
|
182
|
+
readonly targets: TitleLengthTargets;
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Validate the stored policy through the official validator of the installed line.
|
|
186
|
+
* @param module - the loaded auxiliary-LLM package.
|
|
187
|
+
* @param forwarded - the disabled official row's stored config.
|
|
188
|
+
* @returns The validated execution config and title-length targets.
|
|
189
|
+
* @throws when the official validator rejects the stored policy.
|
|
190
|
+
*/
|
|
191
|
+
export declare function resolveNamingPolicy(module: TitleLlmModule, forwarded: Record<string, unknown>): ResolvedNamingPolicy;
|
|
192
|
+
/**
|
|
193
|
+
* Candidate routes for one naming request, most specific first and deduplicated.
|
|
194
|
+
*
|
|
195
|
+
* The stored session group's pair wins, then the deployment-wide pair, then the
|
|
196
|
+
* row's own configured pair, then the session's logged route. The list is also
|
|
197
|
+
* the fallback order: a failing candidate falls through to the next one.
|
|
198
|
+
* @param settings - live Model Switch settings; undefined skips the stored pairs.
|
|
199
|
+
* @param provider - the delegating session's provider, when one is observable.
|
|
200
|
+
* @param policy - the validated row policy (its own pair is the third candidate).
|
|
201
|
+
* @param requestRoute - the session's logged main-request route, when one exists.
|
|
202
|
+
* @returns The ordered, deduplicated candidates; empty when only the row policy applies.
|
|
203
|
+
*/
|
|
204
|
+
export declare function titleRouteCandidates(settings: RouteBearingSettings | undefined, provider: string | undefined, policy: TitleLlmPolicy, requestRoute: CapabilityRoute | undefined): readonly CapabilityRoute[];
|
|
205
|
+
/**
|
|
206
|
+
* Whether a failure may be retried on another candidate.
|
|
207
|
+
* A superseded or disposed request keeps no budget, and a deadline that fired is
|
|
208
|
+
* the caller's bound, not the route's fault: both end the attempt loop.
|
|
209
|
+
* @param error - the failure thrown by the auxiliary call.
|
|
210
|
+
* @param request - the service-owned request whose signal bounds the work.
|
|
211
|
+
* @returns Whether another candidate may be tried.
|
|
212
|
+
*/
|
|
213
|
+
export declare function shouldTryNextCandidate(error: unknown, request: SessionTitleProviderRequest): boolean;
|
|
214
|
+
/**
|
|
215
|
+
* Whether the failure is the model filling its output budget before finishing.
|
|
216
|
+
* Official lines report this as `title output reached maxOutputTokens`; a widened
|
|
217
|
+
* budget is the only retry that can succeed for it.
|
|
218
|
+
* @param error - the failure thrown by the auxiliary call.
|
|
219
|
+
* @returns Whether one widened-budget retry is worth trying.
|
|
220
|
+
*/
|
|
221
|
+
export declare function isMaxTokensFailure(error: unknown): boolean;
|
|
222
|
+
/**
|
|
223
|
+
* A widened output budget for the same route.
|
|
224
|
+
* @param maxOutputTokens - the policy's configured budget.
|
|
225
|
+
* @returns Four times the budget, capped at 4096 tokens.
|
|
226
|
+
*/
|
|
227
|
+
export declare function widerTitleBudget(maxOutputTokens: number): number;
|
|
228
|
+
/**
|
|
229
|
+
* Normalize one accepted title exactly like the official service.
|
|
230
|
+
* @param input - untrusted title text.
|
|
231
|
+
* @returns A terminal-safe, whitespace-normalized one-line title, possibly empty.
|
|
232
|
+
*/
|
|
233
|
+
export declare function normalizeTitleText(input: string): string;
|
|
234
|
+
/**
|
|
235
|
+
* Take the title from model output: the first non-empty line, without asterisk
|
|
236
|
+
* emphasis wrapping that whole line. Models that disregard the one-line
|
|
237
|
+
* instruction put the title first and commentary after it.
|
|
238
|
+
* @param text - joined text blocks of the auxiliary response.
|
|
239
|
+
* @returns The candidate title line.
|
|
240
|
+
*/
|
|
241
|
+
export declare function titleFromOutput(text: string): string;
|
|
242
|
+
/**
|
|
243
|
+
* Interpret one assembled 0.2.1+ response as a title.
|
|
244
|
+
* Rejects terminal tool-call and max-token outcomes exactly like the official
|
|
245
|
+
* provider, so the row keeps the official acceptance rules.
|
|
246
|
+
* @param response - the assembled auxiliary response.
|
|
247
|
+
* @returns A non-empty normalized title.
|
|
248
|
+
* @throws when the finish reason, a tool-call block, or empty text makes the response unusable.
|
|
249
|
+
*/
|
|
250
|
+
export declare function titleFromResponse(response: TitleLlmResponse): string;
|
|
251
|
+
/**
|
|
252
|
+
* Select the route's least supported reasoning effort for a title call, as the
|
|
253
|
+
* official 0.2.1 provider does: naming is a short auxiliary task, and a full
|
|
254
|
+
* reasoning budget can consume the whole output allowance.
|
|
255
|
+
* @param model - the prepared model metadata.
|
|
256
|
+
* @returns The first declared effort id, or undefined when the model has none.
|
|
257
|
+
*/
|
|
258
|
+
export declare function selectTitleReasoningEffort(model: TitleModelMetadata): string | undefined;
|
|
259
|
+
/**
|
|
260
|
+
* The official 0.2.1+ system instruction, including the optional current-title anchor.
|
|
261
|
+
* @param targets - title-length targets.
|
|
262
|
+
* @param hasCurrentTitle - whether the request is anchored to an existing provider title.
|
|
263
|
+
* @returns The system prompt text.
|
|
264
|
+
*/
|
|
265
|
+
export declare function titleSystemPrompt(targets: TitleLengthTargets, hasCurrentTitle: boolean): string;
|
|
266
|
+
/**
|
|
267
|
+
* Frame the exact messages as JSON so user text cannot break structural delimiters.
|
|
268
|
+
* @param messages - the selected human messages.
|
|
269
|
+
* @param currentTitle - the accepted provider title to anchor on, when there is one.
|
|
270
|
+
* @returns The framed user input.
|
|
271
|
+
*/
|
|
272
|
+
export declare function frameTitleInput(messages: readonly SessionTitleUserMessage[], currentTitle: string | undefined): string;
|
|
94
273
|
/**
|
|
95
274
|
* Mount the Model Switch session-naming row for this profile.
|
|
96
275
|
*
|
|
@@ -102,3 +281,4 @@ export declare function officialTitlePackage(entry: Entry): string | undefined;
|
|
|
102
281
|
* @param ctx - this row's context.
|
|
103
282
|
*/
|
|
104
283
|
export declare function apply(ctx: Context): Promise<void>;
|
|
284
|
+
export {};
|
|
@@ -48,6 +48,16 @@ export declare function routeSubagentRequest<T extends RoutableSubagentRequest>(
|
|
|
48
48
|
* @throws the fallback startup error when fallback startup fails.
|
|
49
49
|
*/
|
|
50
50
|
export declare function mountWithStartupFallback<T>(candidate: (track: StartupCleanupTracker) => Promise<T>, fallback: (track: StartupCleanupTracker) => Promise<T>): Promise<MountedStartup<T>>;
|
|
51
|
+
/**
|
|
52
|
+
* Operator-facing notice for a Host whose Subagent runtime cannot be routed.
|
|
53
|
+
*
|
|
54
|
+
* DSH 0.2.1 replaced `start()`/`startContinuable()` with the activation API, so
|
|
55
|
+
* this adapter's override point is gone; the row then mounts the untouched
|
|
56
|
+
* official runtime instead of guessing a new seam.
|
|
57
|
+
* @param error - the typed startup incompatibility that rejected the candidate.
|
|
58
|
+
* @returns The notice logged once at startup.
|
|
59
|
+
*/
|
|
60
|
+
export declare function routedRuntimeUnavailableNotice(error: StartupIncompatibilityError): string;
|
|
51
61
|
/** Profile replacement that selects the routed runtime or the untouched official runtime. */
|
|
52
62
|
export declare const profileSubagentRuntime: ((ctx: Context) => Promise<() => Promise<void>>) & {
|
|
53
63
|
inject: string[];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-model-switch",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.26",
|
|
4
4
|
"description": "Explicit model routing plus composer/Plan picker for DeepSeek Harness",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -106,7 +106,8 @@
|
|
|
106
106
|
"0.1.7-alpha.2": "compatible",
|
|
107
107
|
"0.1.7-rc.1": "compatible",
|
|
108
108
|
"0.1.7-rc.2": "compatible",
|
|
109
|
-
"0.2.0-rc.2": "compatible"
|
|
109
|
+
"0.2.0-rc.2": "compatible",
|
|
110
|
+
"0.2.1-rc.2": "compatible"
|
|
110
111
|
}
|
|
111
112
|
}
|
|
112
113
|
},
|
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
import type { SettingsScope } from '@deepseek-ai/dsh-client-ui-settings/client';
|
|
2
|
-
export type SettingsFieldMap<View> = Readonly<Partial<Record<keyof View & string, string>>>;
|
|
3
|
-
/** Projection over one shared SettingsScope controller/store, with explicit view-to-owner field mapping. */
|
|
4
|
-
export declare function deriveSettingsScope<Source, View>(source: SettingsScope<Source>, project: (value: Source) => View, fields?: SettingsFieldMap<View>): SettingsScope<View>;
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Compensate the Host's own deployment-default write after a Session-only
|
|
3
|
-
* model switch.
|
|
4
|
-
*
|
|
5
|
-
* `session.selectModel` installs the Session selection and, on Hosts that
|
|
6
|
-
* persist a selection as the deployment default, also writes that default.
|
|
7
|
-
* The plugin switches a Session only, so the captured Main default is restored
|
|
8
|
-
* afterwards.
|
|
9
|
-
*
|
|
10
|
-
* That Host write is fenced by a settings revision, and its timing is not part
|
|
11
|
-
* of the released contract: the 0.1.x generation awaited the default write
|
|
12
|
-
* before its RPC resolved, while the 0.2.x generation fires it without
|
|
13
|
-
* awaiting. A fixed `captured + 1` fence therefore either refuses the restore
|
|
14
|
-
* or silently leaves the default switched. Poll-by-revision is used instead:
|
|
15
|
-
* wait for the observed revision to leave the captured one, then fence on the
|
|
16
|
-
* revision actually observed.
|
|
17
|
-
*/
|
|
18
|
-
import type { SettingsPathOpView } from '@deepseek-ai/dsh-api-remotes/client';
|
|
19
|
-
import type { ConfigFormSnapshot } from '@deepseek-ai/dsh-client-ui-settings/client';
|
|
20
|
-
import type { MainSettingsView } from '../../client-contract.ts';
|
|
21
|
-
/** The Main Settings namespace surface this module needs. */
|
|
22
|
-
export interface MainDefaultForm {
|
|
23
|
-
getSnapshot(): ConfigFormSnapshot<MainSettingsView>;
|
|
24
|
-
subscribe(listener: () => void): () => void;
|
|
25
|
-
mutate(ops: readonly SettingsPathOpView[], expectedRevision?: number): Promise<boolean>;
|
|
26
|
-
}
|
|
27
|
-
/** Outcome of one compensation attempt. */
|
|
28
|
-
export interface MainDefaultRestore {
|
|
29
|
-
/** The captured Main default is the effective one again (or no write occurred). */
|
|
30
|
-
restored: boolean;
|
|
31
|
-
/** A newer revision won instead; the concurrent edit is left untouched. */
|
|
32
|
-
conflict: boolean;
|
|
33
|
-
}
|
|
34
|
-
export interface MainDefaultRestoreOptions {
|
|
35
|
-
/** Timeout primitive; tests inject a deterministic one. */
|
|
36
|
-
wait?: (ms: number) => Promise<void>;
|
|
37
|
-
/** How long to await the unawaited Host default write. */
|
|
38
|
-
timeoutMs?: number;
|
|
39
|
-
/** Total fences, including one retry after a concurrent revision change. */
|
|
40
|
-
attempts?: number;
|
|
41
|
-
}
|
|
42
|
-
/** Field writes restoring one complete Main selection; the Host replaces the section. */
|
|
43
|
-
export declare function mainDefaultOps(selection: MainSettingsView): SettingsPathOpView[];
|
|
44
|
-
/**
|
|
45
|
-
* Restore the Main default captured before a Session-only model switch.
|
|
46
|
-
*
|
|
47
|
-
* Never throws and never blocks a Plan answer: a failed compensation is
|
|
48
|
-
* reported, not enforced, because the Session selection the human asked for is
|
|
49
|
-
* already installed by the time this runs.
|
|
50
|
-
*
|
|
51
|
-
* @param form - the official Main Settings namespace form.
|
|
52
|
-
* @param before - the snapshot captured before the switch.
|
|
53
|
-
* @param options - wait/timeout/attempt overrides for tests.
|
|
54
|
-
* @returns Whether the captured default stands again, and whether a newer edit won.
|
|
55
|
-
*/
|
|
56
|
-
export declare function restoreMainDefault(form: MainDefaultForm, before: ConfigFormSnapshot<MainSettingsView>, options?: MainDefaultRestoreOptions): Promise<MainDefaultRestore>;
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Apply a provider's saved capability group whenever the seat session's
|
|
3
|
-
* provider changes — on any switch surface.
|
|
4
|
-
*
|
|
5
|
-
* The official model-selection directory projects the Session's durable
|
|
6
|
-
* `model/selection` events into `store.current` (the sole emitter of those
|
|
7
|
-
* events is the `session.selectModel` RPC), so a switch performed through the
|
|
8
|
-
* TUI or any other client lands in the same store this plugin already reads.
|
|
9
|
-
* One watcher therefore covers every surface for sessions open in this Web
|
|
10
|
-
* UI, where the previous wiring only covered this plugin's own two call sites.
|
|
11
|
-
*
|
|
12
|
-
* Semantics stay exactly as before: a provider change applies the target
|
|
13
|
-
* provider's group when one exists; a provider without a group, a same-model
|
|
14
|
-
* change within one provider, and the subscription baseline itself write
|
|
15
|
-
* nothing. A failed apply is reported and never disturbs the switch.
|
|
16
|
-
*/
|
|
17
|
-
import type { ModelSelection } from '@deepseek-ai/dsh-api-session-controller/types';
|
|
18
|
-
/** The directory store slice the watcher observes. */
|
|
19
|
-
export interface DirectoryWatchSource {
|
|
20
|
-
subscribe: (listener: () => void) => () => void;
|
|
21
|
-
getSnapshot: () => {
|
|
22
|
-
current: ModelSelection | null;
|
|
23
|
-
};
|
|
24
|
-
}
|
|
25
|
-
export interface ProviderGroupWatchOptions {
|
|
26
|
-
source: DirectoryWatchSource;
|
|
27
|
-
/** Adopt the target provider's saved group; a group-less provider must write nothing. */
|
|
28
|
-
apply: (provider: string) => Promise<void>;
|
|
29
|
-
/** Reported apply failure; defaults to a console warning. */
|
|
30
|
-
onFailure?: (error: unknown) => void;
|
|
31
|
-
}
|
|
32
|
-
export interface ProviderGroupWatch {
|
|
33
|
-
/** Detach from the store; in-flight applies are left to finish. */
|
|
34
|
-
dispose: () => void;
|
|
35
|
-
}
|
|
36
|
-
/**
|
|
37
|
-
* Watch one directory store and apply groups on provider changes.
|
|
38
|
-
*
|
|
39
|
-
* - The first observed provider (or the one already loaded) is the baseline
|
|
40
|
-
* and never triggers a write, so mounting and initial load stay silent.
|
|
41
|
-
* - Applies are serialized: a change arriving mid-apply coalesces to the
|
|
42
|
-
* latest target and runs once the current apply finishes, so two writes
|
|
43
|
-
* never interleave pair writes.
|
|
44
|
-
* - `current` being null (catalog still loading) is ignored, not a change.
|
|
45
|
-
* @param options - the store to watch and the apply to run.
|
|
46
|
-
* @returns the watch handle.
|
|
47
|
-
*/
|
|
48
|
-
export declare function createProviderGroupWatch(options: ProviderGroupWatchOptions): ProviderGroupWatch;
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
import type { SettingsPathOpView } from '@deepseek-ai/dsh-api-remotes/client';
|
|
2
|
-
import type { SettingsScope, SettingsScopeSnapshot } from '@deepseek-ai/dsh-client-ui-settings/client';
|
|
3
|
-
interface RemoteError {
|
|
4
|
-
code: string;
|
|
5
|
-
message: string;
|
|
6
|
-
}
|
|
7
|
-
interface RemoteResult<T> {
|
|
8
|
-
ok: boolean;
|
|
9
|
-
value?: T;
|
|
10
|
-
error?: RemoteError;
|
|
11
|
-
}
|
|
12
|
-
interface NamespaceView {
|
|
13
|
-
ns: string;
|
|
14
|
-
value: unknown;
|
|
15
|
-
base?: unknown;
|
|
16
|
-
user?: unknown;
|
|
17
|
-
revision: number;
|
|
18
|
-
}
|
|
19
|
-
interface DescribeValue {
|
|
20
|
-
writable: boolean;
|
|
21
|
-
namespaces: readonly NamespaceView[];
|
|
22
|
-
}
|
|
23
|
-
export interface RemoteSettingsFace {
|
|
24
|
-
describe(): Promise<RemoteResult<DescribeValue>>;
|
|
25
|
-
mutate(ns: string, ops: readonly unknown[], expectedRevision: number | undefined): Promise<RemoteResult<NamespaceView>>;
|
|
26
|
-
}
|
|
27
|
-
/** Host-backed settings scope used by this plugin on authenticated remote browsers. */
|
|
28
|
-
export declare class RemoteSettingsScope<T> implements SettingsScope<T> {
|
|
29
|
-
private readonly api;
|
|
30
|
-
private readonly namespace;
|
|
31
|
-
private readonly decode;
|
|
32
|
-
private snapshot;
|
|
33
|
-
private readonly listeners;
|
|
34
|
-
constructor(api: RemoteSettingsFace, namespace: string, decode: (value: unknown) => T | undefined);
|
|
35
|
-
getSnapshot: () => SettingsScopeSnapshot<T>;
|
|
36
|
-
subscribe: (listener: () => void) => (() => void);
|
|
37
|
-
reload(): Promise<void>;
|
|
38
|
-
set(field: string, value: unknown): Promise<void>;
|
|
39
|
-
unset(field: string): Promise<void>;
|
|
40
|
-
mutate(ops: readonly SettingsPathOpView[], expectedRevision?: number): Promise<void>;
|
|
41
|
-
private write;
|
|
42
|
-
private accept;
|
|
43
|
-
private publish;
|
|
44
|
-
}
|
|
45
|
-
export {};
|
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
/** Send-time context check and optional old-model compaction before a switched request. */
|
|
2
|
-
import type { Context } from '@deepseek-ai/cordis';
|
|
3
|
-
import { type UserMessage } from '@deepseek-ai/dsh-llm';
|
|
4
|
-
declare module '@deepseek-ai/dsh-llm' {
|
|
5
|
-
interface MessageSourceMap {
|
|
6
|
-
'model-switch': {
|
|
7
|
-
kind: 'model-switch';
|
|
8
|
-
form: 'notice';
|
|
9
|
-
summary: string;
|
|
10
|
-
};
|
|
11
|
-
}
|
|
12
|
-
}
|
|
13
|
-
/** Provider and model selected for one model-routed request. */
|
|
14
|
-
export interface SwitchRoute {
|
|
15
|
-
readonly provider: string;
|
|
16
|
-
readonly model: string;
|
|
17
|
-
}
|
|
18
|
-
/**
|
|
19
|
-
* Compare two fully specified model routes.
|
|
20
|
-
* @param left - first route, if one was resolved.
|
|
21
|
-
* @param right - second route, if one was resolved.
|
|
22
|
-
* @returns Whether both routes identify the same provider and model.
|
|
23
|
-
*/
|
|
24
|
-
export declare function sameSwitchRoute(left: SwitchRoute | undefined, right: SwitchRoute | undefined): boolean;
|
|
25
|
-
/**
|
|
26
|
-
* Decide whether a changed, complete route needs send-time context protection.
|
|
27
|
-
* @param enabled - whether the user enabled send-time protection.
|
|
28
|
-
* @param previous - route used by the preceding request.
|
|
29
|
-
* @param selected - route assembled for the pending request.
|
|
30
|
-
* @returns Whether the pending request changes its provider or model.
|
|
31
|
-
*/
|
|
32
|
-
export declare function shouldProtectSwitch(enabled: boolean, previous: SwitchRoute | undefined, selected: SwitchRoute | undefined): boolean;
|
|
33
|
-
/**
|
|
34
|
-
* Input budget for the target window. Reserves output (maxTokens or 20%) plus a
|
|
35
|
-
* fixed estimator margin. `undefined` means the window cannot be used.
|
|
36
|
-
* @param contextWindow - adapter-owned combined request/response capacity.
|
|
37
|
-
* @param maxTokens - optional generation cap from the live agent options.
|
|
38
|
-
* @returns Tokens available to the request input, or undefined for an invalid window.
|
|
39
|
-
*/
|
|
40
|
-
export declare function switchInputBudget(contextWindow: number, maxTokens?: number): number | undefined;
|
|
41
|
-
/**
|
|
42
|
-
* Determine whether an estimated input exceeds its target route budget.
|
|
43
|
-
* @param tokens - estimated input tokens.
|
|
44
|
-
* @param budget - input budget for the target window.
|
|
45
|
-
* @returns Whether the budget is unusable or the estimate is too large.
|
|
46
|
-
*/
|
|
47
|
-
export declare function overSwitchBudget(tokens: number, budget: number): boolean;
|
|
48
|
-
/**
|
|
49
|
-
* Build one transcript-visible Model Switch progress notice.
|
|
50
|
-
* @param text - localized notice text shown in the transcript.
|
|
51
|
-
* @param summary - bounded event summary for durable session metadata.
|
|
52
|
-
* @returns A plugin-authored user message for the session log.
|
|
53
|
-
*/
|
|
54
|
-
export declare function switchNotice(text: string, summary: string): UserMessage;
|
|
55
|
-
/**
|
|
56
|
-
* Extract a complete route from partial request configuration.
|
|
57
|
-
* @param value - candidate provider and model values.
|
|
58
|
-
* @returns A complete route, or undefined when either identifier is absent.
|
|
59
|
-
*/
|
|
60
|
-
export declare function routeOf(value: {
|
|
61
|
-
provider?: string;
|
|
62
|
-
model?: string;
|
|
63
|
-
} | undefined): SwitchRoute | undefined;
|
|
64
|
-
/**
|
|
65
|
-
* Install send-time switch protection on the host context.
|
|
66
|
-
* @param ctx - host context that owns agent-loop, llm, and tokenMeter.
|
|
67
|
-
* @param settings - live Model Switch settings; `compactOnSwitch !== false` is on.
|
|
68
|
-
* @param roleOf - provider-role lookup used to exclude native Agent runtimes.
|
|
69
|
-
*/
|
|
70
|
-
export declare function installSwitchCompaction(ctx: Context, settings: () => {
|
|
71
|
-
compactOnSwitch?: boolean;
|
|
72
|
-
}, roleOf?: (provider: string) => 'llm' | 'agent' | undefined): void;
|