dsh-model-switch 0.4.22 → 0.4.24

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.
@@ -5,7 +5,16 @@ import type { BasicCompactionConfig } from '@deepseek-ai/dsh-compaction-basic';
5
5
  export declare const name = "model-switch-compaction";
6
6
  /** 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. */
7
7
  export declare const inject: string[];
8
- /** Both identifiers trimmed and non-empty; undefined means "official default". */
8
+ /**
9
+ * Both identifiers trimmed and non-empty; undefined means "official default".
10
+ *
11
+ * The summarization route stays deployment-wide on purpose. The official
12
+ * compaction transaction durably records the provider/model that wrote the
13
+ * summary, so a per-session rewrite of the summarization call would make that
14
+ * record false; a deployment that needs provider-scoped summarization uses the
15
+ * official exact-target `modelPolicies` table, which this row forwards
16
+ * verbatim from the profile's `compaction-basic` row config.
17
+ */
9
18
  export interface CompactionRoute {
10
19
  readonly provider: string;
11
20
  readonly model: string;
@@ -39,6 +48,17 @@ export declare function officialCompactionEntry(loader: Loader | undefined): Ent
39
48
  * @returns A plain object spread; missing or invalid configs become `{}`.
40
49
  */
41
50
  export declare function forwardedConfig(entry: Entry): BasicCompactionConfig;
51
+ /**
52
+ * Whether the compaction capability is actually served from this context.
53
+ *
54
+ * Awaiting a plugin fiber settles even when the plugin's injections were never
55
+ * satisfied, so the mount is confirmed through the public service instead of by
56
+ * the absence of an error: an unactivated engine must never be recorded as the
57
+ * live engine, or the row would stop retrying while `/compact` had no service.
58
+ * @param ctx - this row's context.
59
+ * @returns true when `ctx.compaction` exposes the engine's public entry points.
60
+ */
61
+ export declare function engineActive(ctx: Context): boolean;
42
62
  /**
43
63
  * Mount the Model Switch compaction engine for this profile.
44
64
  *
@@ -46,9 +66,10 @@ export declare function forwardedConfig(entry: Entry): BasicCompactionConfig;
46
66
  * with the same package under the configurable summarization route. Host
47
67
  * settings and the loader are read structurally so a disabled `model-switch`
48
68
  * row leaves official compaction untouched. Reconciles run on
49
- * `model-switch/settings-update` (emitted by the host on volatile commits and
50
- * ordinary saves); the listener is global so instances of this row inside
51
- * agent-preset realms still hear the host row's emission. The initial
69
+ * `model-switch/settings-update` (emitted by the host at construction, on
70
+ * volatile commits, and on ordinary saves) and read the settled settings, so one
71
+ * save costs at most one remount; the listener is global so instances of this
72
+ * row inside agent-preset realms still hear the host row's emission. The initial
52
73
  * reconcile is awaited so `/compact` resolves the service as soon as this row
53
74
  * completes.
54
75
  * @param ctx - this row's context.
@@ -1,6 +1,4 @@
1
1
  import { Context, Service } from '@deepseek-ai/cordis';
2
- import type { ModelSelection } from '@deepseek-ai/dsh-agent';
3
- import type { AgentDefaultModelConfig } from '@deepseek-ai/dsh-agent-default-model';
4
2
  import { Config, type Config as ModelSwitchSettingsConfig, type ModelSwitchSettings } from './host-settings.js';
5
3
  import { ModelSwitchAdapterRegistry } from './adapter-registry.js';
6
4
  declare module '@deepseek-ai/cordis' {
@@ -12,9 +10,8 @@ declare module '@deepseek-ai/cordis' {
12
10
  'model-switch/settings-update'(): void;
13
11
  }
14
12
  }
15
- /** Host owner for Model Switch settings and the released Main-default adapter. */
13
+ /** Host owner for Model Switch settings. */
16
14
  export declare class ModelSwitchRuntime extends Service {
17
- static inject: string[];
18
15
  static Config: import("@deepseek-ai/schemastery").default<any, Config, "plain">;
19
16
  get capabilities(): {
20
17
  searchProviderAdapters: {
@@ -52,11 +49,4 @@ export declare class ModelSwitchRuntime extends Service {
52
49
  private source;
53
50
  constructor(ctx: Context, entry: ModelSwitchSettingsConfig);
54
51
  currentSettings(): ModelSwitchSettings;
55
- currentMainSelection(): ModelSelection;
56
- saveMainSelection(selection: ModelSelection): Promise<void>;
57
52
  }
58
- export interface MainDefaultPort {
59
- currentSelection(): ModelSelection;
60
- saveSelection(selection: ModelSelection): Promise<void>;
61
- }
62
- export declare function mainDefaultPort(service: AgentDefaultModelConfig): MainDefaultPort;
@@ -21,6 +21,10 @@ export interface ModelSwitchSettings {
21
21
  compactProvider?: string;
22
22
  /** Summarization model for `/compact` and automatic compaction; set together with `compactProvider`. */
23
23
  compactModel?: string;
24
+ /** Naming provider for automatic session titles; both fields unset = official default (the session's own logged route). */
25
+ titleProvider?: string;
26
+ /** Naming model for automatic session titles; set together with `titleProvider`. */
27
+ titleModel?: string;
24
28
  /** Per-provider compaction/subagent/review presets, keyed by provider id; absent when no group is saved. */
25
29
  providerGroups?: ProviderGroups;
26
30
  }
@@ -39,6 +43,8 @@ export interface Config {
39
43
  autoReviewModel: Volatile<string | undefined>;
40
44
  compactProvider: Volatile<string | undefined>;
41
45
  compactModel: Volatile<string | undefined>;
46
+ titleProvider: Volatile<string | undefined>;
47
+ titleModel: Volatile<string | undefined>;
42
48
  /** Saved per-provider capability groups as one entry per provider; entry route fields are '' when the capability stays at its default. */
43
49
  providerGroups: Volatile<readonly ProviderGroupEntry[]>;
44
50
  }
@@ -1,5 +1,5 @@
1
1
  export { Config, readConfig, type ModelSwitchSettings } from './host-settings.js';
2
- export { mainDefaultPort, ModelSwitchRuntime, type MainDefaultPort } from './host-runtime.js';
2
+ export { ModelSwitchRuntime } from './host-runtime.js';
3
3
  export { ModelSwitchAdapterRegistry, type ModelSwitchProviderAdapters, type ModelSwitchSearchAdapter, type ModelSwitchImageAdapter, type ModelSwitchImageRequest, type ModelSwitchGeneratedImage } from './adapter-registry.js';
4
4
  export { RUNTIME_CAPABILITIES, type RuntimeCapabilities, type RuntimeCapability } from './runtime-capabilities.js';
5
5
  export { parsePickerId, groupFamilies, planReviewOf, selectPlanReview, approvePlanReview, } from './picker/public.ts';
@@ -14,18 +14,12 @@ export declare class PlanApprovalResponseError extends Error {
14
14
  /**
15
15
  * Result of committing the draft execution model before answering a review.
16
16
  *
17
- * A commit and the compensation of the Host's own deployment-default write are
18
- * separate facts: only a failed commit may hold the answer back, because the
19
- * Host persists a Session selection as the deployment default on several
20
- * releases and this plugin restores the captured Main default afterwards. A
21
- * failed restore is announced, never fatal — the Session selection the human
22
- * asked for is already installed.
17
+ * Only a failed commit may hold the answer back: once `committed` is true the
18
+ * Session runs the requested selection, and the answer proceeds under it.
23
19
  */
24
20
  export interface PlanCommitOutcome {
25
21
  /** The Session now runs the requested provider/model/effort. */
26
22
  committed: boolean;
27
- /** The captured Main default is the effective one again. */
28
- mainDefaultRestored: boolean;
29
23
  }
30
24
  /**
31
25
  * Diagnostic text for one failed action, keeping the wire code visible.
@@ -41,8 +35,6 @@ export declare function approvePlanReview(args: {
41
35
  selection: ModelSelection;
42
36
  current?: ModelSelection | null;
43
37
  answer: () => Promise<void>;
44
- /** Announced after a successful answer when the Main default could not be restored. */
45
- onNotRestored?: (notice: string) => void;
46
38
  }): Promise<boolean>;
47
39
  export interface PlanActionState {
48
40
  busy: boolean;
@@ -1,15 +1,24 @@
1
1
  /**
2
- * Provider configuration groups: per-provider presets for the compaction,
3
- * subagent, and auto-review routes.
2
+ * Provider configuration groups: per-provider presets for the session-naming
3
+ * and subagent routes.
4
4
  *
5
- * A group stores the exact flat settings fields it will write, so applying a
6
- * group is a plain settings-layer write: every capability consumer keeps
7
- * reading the live values unchanged. All functions here are pure and never
8
- * throw on malformed storage.
5
+ * A group is a DERIVED policy, not a write: `src/session-route.ts` resolves the
6
+ * routes one session should use from its own provider plus this stored table, so
7
+ * switching a session's provider never rewrites deployment-wide settings and two
8
+ * sessions on different providers cannot overwrite each other. The field names
9
+ * below are the flat settings field names a group pins, which keeps the stored
10
+ * shape identical to the earlier write-through design.
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).
17
+ *
18
+ * All functions here are pure and never throw on malformed storage.
9
19
  */
10
- import type { SubagentMode } from './host-settings.js';
11
- /** Flat settings fields a provider group can pin — exactly what an application writes. */
12
- export type ProviderGroupRouteField = 'compactProvider' | 'compactModel' | 'autoReviewProvider' | 'autoReviewModel' | 'subagentProvider' | 'subagentModel' | 'subagentReasoningEffort';
20
+ /** Flat settings fields a provider group carries; the first four are legacy-only. */
21
+ export type ProviderGroupRouteField = 'compactProvider' | 'compactModel' | 'autoReviewProvider' | 'autoReviewModel' | 'subagentProvider' | 'subagentModel' | 'subagentReasoningEffort' | 'titleProvider' | 'titleModel';
13
22
  /** Stored entry: the owning provider plus every route field; '' means the capability stays at its default. */
14
23
  export interface ProviderGroupEntry {
15
24
  provider: string;
@@ -20,6 +29,8 @@ export interface ProviderGroupEntry {
20
29
  subagentProvider: string;
21
30
  subagentModel: string;
22
31
  subagentReasoningEffort: string;
32
+ titleProvider: string;
33
+ titleModel: string;
23
34
  }
24
35
  /** Normalized view of one provider's group; absent fields follow their default state. */
25
36
  export type ProviderGroupConfig = Partial<Record<ProviderGroupRouteField, string>>;
@@ -40,22 +51,6 @@ export declare function normalizeProviderGroups(raw: unknown): ProviderGroups;
40
51
  * which is what leaves the live routes untouched during a switch.
41
52
  */
42
53
  export declare function groupOf(groups: ProviderGroups | undefined, provider: string): ProviderGroupConfig | undefined;
43
- /** One application write; `value` undefined means "unset this field". */
44
- export type ProviderGroupWrite = {
45
- readonly field: 'subagentMode';
46
- readonly mode: SubagentMode;
47
- } | {
48
- readonly field: ProviderGroupRouteField;
49
- readonly value: string | undefined;
50
- };
51
- /**
52
- * Ordered writes applying one group with full-replacement semantics: pinned
53
- * capabilities land as pairs, everything else reverts to its default state
54
- * (compaction/review follow the session model; Subagent follows official
55
- * inherit). The mode write comes last so a fixed route never publishes with
56
- * the previous provider's fields still half-written.
57
- */
58
- export declare function providerGroupWrites(group: ProviderGroupConfig): ProviderGroupWrite[];
59
54
  /** Storage entry for one provider's group; absent or blank route fields become ''. */
60
55
  export declare function entryOf(provider: string, group: ProviderGroupConfig): ProviderGroupEntry;
61
56
  /**
@@ -65,14 +60,3 @@ export declare function entryOf(provider: string, group: ProviderGroupConfig): P
65
60
  * provider only normalizes.
66
61
  */
67
62
  export declare function withProviderGroup(storage: unknown, provider: string, group: ProviderGroupConfig | undefined): ProviderGroupsStorage;
68
- /** Minimal writable settings surface an application needs; satisfied by the owned ConfigForm. */
69
- export interface ProviderGroupSink {
70
- set(field: 'subagentMode' | ProviderGroupRouteField, value: string): Promise<unknown>;
71
- unset(field: ProviderGroupRouteField): Promise<unknown>;
72
- }
73
- /**
74
- * Apply a saved group's routes to the live flat settings.
75
- * @returns true when a group existed and every write settled; false when the
76
- * provider has no group (nothing was written). A rejected write propagates.
77
- */
78
- export declare function applyProviderGroupTo(sink: ProviderGroupSink, groups: ProviderGroups | undefined, provider: string): Promise<boolean>;
@@ -0,0 +1,111 @@
1
+ /**
2
+ * Per-session capability route derivation.
3
+ *
4
+ * Model Switch stores one deployment-wide route per capability (the flat
5
+ * settings fields) plus, per provider, a saved provider group. Nothing is
6
+ * written when a session changes provider: this module DERIVES the route a
7
+ * capability should use for one session from (a) the session's own provider and
8
+ * (b) the stored group table. Two sessions on different providers therefore
9
+ * resolve independently, and no session's actions rewrite another session's
10
+ * route.
11
+ *
12
+ * The session's provider is read from durable, official state in this order:
13
+ * the `modelSelection` session projection (`pending` before `lastUsed`, so a
14
+ * selection the user just made counts), then the latest logged request-context
15
+ * route, then the latest `request/header` route. Every read is optional: a
16
+ * session with no observable provider, an unregistered projection, or a
17
+ * profile without the projection package all resolve to the deployment default,
18
+ * which is exactly the pre-derivation behavior.
19
+ *
20
+ * All functions are pure except the readers, which never throw and never write.
21
+ */
22
+ import type { Context } from '@deepseek-ai/cordis';
23
+ import type { Session } from '@deepseek-ai/dsh-session';
24
+ import { type ProviderGroups } from './provider-group.js';
25
+ /** Capabilities whose route can be derived per session. */
26
+ export type CapabilityId = 'compaction' | 'autoReview' | 'title' | 'subagent';
27
+ /** A complete pinned route; either half missing means "follow the default". */
28
+ export interface CapabilityRoute {
29
+ readonly provider: string;
30
+ readonly model: string;
31
+ }
32
+ /**
33
+ * Settings fields a route can be derived from. Structurally satisfied by
34
+ * {@link ModelSwitchSettings}; declared separately so the resolver stays pure
35
+ * and testable without a host runtime.
36
+ */
37
+ export interface RouteBearingSettings {
38
+ readonly subagentMode?: string;
39
+ readonly subagentProvider?: string;
40
+ readonly subagentModel?: string;
41
+ readonly subagentReasoningEffort?: string;
42
+ readonly autoReviewProvider?: string;
43
+ readonly autoReviewModel?: string;
44
+ readonly compactProvider?: string;
45
+ readonly compactModel?: string;
46
+ readonly titleProvider?: string;
47
+ readonly titleModel?: string;
48
+ readonly providerGroups?: ProviderGroups;
49
+ }
50
+ /**
51
+ * The deployment-wide route for one capability: the flat settings pair.
52
+ * @param settings - live Model Switch settings; undefined means none are reachable.
53
+ * @param capability - capability whose flat pair is read.
54
+ * @returns The complete pair, or undefined when the capability stays at its official/derived default.
55
+ */
56
+ export declare function deploymentRoute(settings: RouteBearingSettings | undefined, capability: CapabilityId): CapabilityRoute | undefined;
57
+ /** One capability's route plus the reasoning effort a subagent spawn also carries. */
58
+ export interface SubagentRoute extends CapabilityRoute {
59
+ readonly reasoningEffort?: string;
60
+ }
61
+ /**
62
+ * The route a subagent spawn should use for one parent-session provider.
63
+ *
64
+ * A saved group for that provider pins the spawn; otherwise the flat Subagent
65
+ * card pins it, but only in `fixed` mode — `follow-main` IS the official inherit
66
+ * path, expressed by leaving the request untouched rather than by naming it.
67
+ * @param settings - live Model Switch settings.
68
+ * @param provider - the delegating session's provider, when one is observable.
69
+ * @returns The complete route, or undefined for official inherit.
70
+ */
71
+ export declare function subagentRouteOf(settings: RouteBearingSettings | undefined, provider: string | undefined): SubagentRoute | undefined;
72
+ /**
73
+ * One provider's saved route for one capability.
74
+ * @param settings - live Model Switch settings carrying the group table.
75
+ * @param provider - the session's provider; blank or unknown resolves to undefined.
76
+ * @param capability - capability whose group pin is read.
77
+ * @returns The complete group pair, or undefined when the group pins nothing here.
78
+ */
79
+ export declare function groupRoute(settings: RouteBearingSettings | undefined, provider: string | undefined, capability: CapabilityId): CapabilityRoute | undefined;
80
+ /**
81
+ * The route one capability should use for one session.
82
+ *
83
+ * A saved provider group for the session's provider wins; otherwise the flat
84
+ * deployment default applies. An unknown session provider skips every group, so
85
+ * a session Model Switch cannot attribute keeps the deployment default.
86
+ * @param settings - live Model Switch settings.
87
+ * @param provider - the session's provider, when one is observable.
88
+ * @param capability - capability being resolved.
89
+ * @returns The complete pair, or undefined for the capability's official default.
90
+ */
91
+ export declare function resolveCapabilityRoute(settings: RouteBearingSettings | undefined, provider: string | undefined, capability: CapabilityId): CapabilityRoute | undefined;
92
+ /**
93
+ * The provider one session is using, from official durable state.
94
+ *
95
+ * Preferred source is the session's own model selection (it covers a switch the
96
+ * client has sent but no request has consumed yet); the logged request-context
97
+ * and request-header routes cover profiles without the projection package and
98
+ * replayed sessions that never emitted a selection.
99
+ * @param ctx - context used for the optional projection read.
100
+ * @param session - the session to resolve; undefined resolves to undefined.
101
+ * @returns The provider, or undefined when nothing durable names one.
102
+ */
103
+ export declare function sessionProviderOf(ctx: Context, session: Session | undefined): string | undefined;
104
+ /**
105
+ * The subagent route one exact session's spawns should use.
106
+ * @param ctx - context used for the optional session reads.
107
+ * @param session - the delegating session; undefined keeps official inherit.
108
+ * @param settings - live Model Switch settings.
109
+ * @returns The complete route, or undefined for official inherit.
110
+ */
111
+ export declare function sessionSubagentRouteOf(ctx: Context, session: Session | undefined, settings: RouteBearingSettings | undefined): SubagentRoute | undefined;
@@ -0,0 +1,104 @@
1
+ /**
2
+ * Model Switch-owned session-naming row.
3
+ *
4
+ * The official naming rows hardwire the naming route at registration time: the
5
+ * configured provider/model pair wins over the session's own logged route for
6
+ * every session in the profile. This row registers ONE provider of its own and
7
+ * resolves the route PER REQUEST instead, so a session whose provider has a
8
+ * saved group is named through that group's pair while every other session keeps
9
+ * following its own model.
10
+ *
11
+ * The call itself stays inside the official implementation: the exported
12
+ * `generateSessionTitleWithLlm` receives the session-resolved config and records
13
+ * exactly that route in `session/title-llm-request`, so the durable record and
14
+ * the actual request can never disagree. Nothing is remounted when settings
15
+ * change — the route is read through on every naming request — so a settings
16
+ * save can neither interrupt an in-flight naming request nor leave the profile
17
+ * without a registered provider.
18
+ *
19
+ * `cordis.patch.yml` disables the official row (the seam allows one registered
20
+ * provider per context), and this row mirrors the cadence the disabled row
21
+ * declared, so a profile that restated the row as all-prompts keeps its cadence.
22
+ *
23
+ * @module dsh-model-switch/session-title
24
+ */
25
+ import type { Context } from '@deepseek-ai/cordis';
26
+ 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 { ResolvedSessionTitleLlmConfig, SessionTitleLlmConfig } from '@deepseek-ai/dsh-session-title-llm';
29
+ import { type CapabilityRoute } from './session-route.js';
30
+ /** Cordis plugin identity; matches the cordis.patch.yml insert row id. */
31
+ export declare const name = "model-switch-session-title";
32
+ /** The loader names the disabled row, and the seam services the call needs are awaited before the first naming request. */
33
+ export declare const inject: string[];
34
+ /** One official cadence package; the row's own package selects which one this profile runs. */
35
+ export interface TitleCadence {
36
+ /** Official npm package that declares this cadence. */
37
+ readonly pkg: string;
38
+ /** Provider id recorded with every generated title; mirrors the official registration. */
39
+ readonly id: SessionTitleProviderId;
40
+ /** When the service starts automatic generation. */
41
+ readonly automatic: SessionTitleAutomaticMode;
42
+ /** Whether only the first human message is framed into the request. */
43
+ readonly firstPromptOnly: boolean;
44
+ }
45
+ /** Both official cadence packages, in the order a profile may declare them. */
46
+ export declare const TITLE_CADENCES: readonly TitleCadence[];
47
+ /**
48
+ * The cadence one official package name declares.
49
+ * @param pkg - the disabled row's package name.
50
+ * @returns The matching cadence, or undefined for a row this row cannot mirror.
51
+ */
52
+ export declare function titleCadence(pkg: string | undefined): TitleCadence | undefined;
53
+ /**
54
+ * Overlay the session-resolved route over the row's own validated policy.
55
+ *
56
+ * A resolved route always names both halves. When nothing resolves, the row's
57
+ * own policy is returned unchanged: an explicit pair the profile configured on
58
+ * the official row stays the deployment default, and a row without one keeps
59
+ * following each session's logged route.
60
+ * @param config - policy validated from the disabled official row.
61
+ * @param route - session-resolved naming route, or undefined for the row's own policy.
62
+ * @returns A detached config for one naming request.
63
+ */
64
+ export declare function composeTitleRoute(config: ResolvedSessionTitleLlmConfig, route: CapabilityRoute | undefined): ResolvedSessionTitleLlmConfig;
65
+ /**
66
+ * Frame the exact human messages one naming revision represents.
67
+ * @param messages - every eligible human message of the revision.
68
+ * @param firstPromptOnly - cadence flag: true mirrors the first-prompt provider.
69
+ * @returns The selected messages, in order.
70
+ * @throws when a first-prompt cadence receives an empty revision — the official provider's own contract.
71
+ */
72
+ export declare function selectTitleMessages(messages: readonly SessionTitleUserMessage[], firstPromptOnly: boolean): readonly SessionTitleUserMessage[];
73
+ /**
74
+ * Locate the official session-title provider row in the loader tree.
75
+ * Disabled entries stay in the tree, so a name-matched disable still matches.
76
+ * @param loader - the host loader, when one is reachable.
77
+ * @returns The official entry, or undefined when this profile has no such row.
78
+ */
79
+ export declare function officialTitleEntry(loader: Loader | undefined): Entry | undefined;
80
+ /**
81
+ * Copy the official row's stored config, ignoring non-object payloads.
82
+ * @param entry - the official session-title provider entry.
83
+ * @returns A plain object spread; missing or invalid configs become `{}`. The
84
+ * result is untrusted: the profile may be hand-edited, so the official policy
85
+ * validator runs over it before any naming request is served.
86
+ */
87
+ export declare function forwardedConfig(entry: Entry): Partial<SessionTitleLlmConfig>;
88
+ /**
89
+ * The official package name this row mounts (either cadence).
90
+ * @param entry - the official session-title provider entry.
91
+ * @returns The package name, or undefined when the row declares none.
92
+ */
93
+ export declare function officialTitlePackage(entry: Entry): string | undefined;
94
+ /**
95
+ * Mount the Model Switch session-naming row for this profile.
96
+ *
97
+ * A profile with no official naming row, an unrecognized row package, a missing
98
+ * auxiliary-LLM package, or an invalid stored policy keeps the session-title
99
+ * service's deterministic fallback titles and reports the lost capability
100
+ * explicitly instead of guessing a route. The registration is an effect of this
101
+ * row's fiber, so unloading the profile unregisters the provider.
102
+ * @param ctx - this row's context.
103
+ */
104
+ export declare function apply(ctx: Context): Promise<void>;
@@ -1,6 +1,6 @@
1
1
  import { Context } from '@deepseek-ai/cordis';
2
2
  import OfficialSubagentRuntime, { type ContinuableStart, type ContinuableStartSpec, type SubagentRun, type SubagentStartRequest } from '@deepseek-ai/dsh-subagent';
3
- import type { ModelSwitchSettings } from './host-settings.js';
3
+ import { type SubagentRoute } from './session-route.js';
4
4
  /** Raised only when an explicit startup check finds an unsupported public surface. */
5
5
  export declare class StartupIncompatibilityError extends Error {
6
6
  readonly name = "StartupIncompatibilityError";
@@ -21,8 +21,19 @@ export interface MountedStartup<T> {
21
21
  readonly dispose: () => Promise<void>;
22
22
  }
23
23
  type RoutableSubagentRequest = Pick<SubagentStartRequest, 'parent' | 'agentOptions'>;
24
- /** Inject a fixed Default Subagent route, or leave the request for Official inherit. */
25
- export declare function routeSubagentRequest<T extends RoutableSubagentRequest>(request: T, settings: ModelSwitchSettings): T;
24
+ /**
25
+ * Inject one resolved route into a spawn that names none.
26
+ *
27
+ * A spawn that already names a provider, model, or effort keeps it: the caller's
28
+ * explicit selection outranks any profile policy. The route itself is derived
29
+ * from the DELEGATING session (its provider selects a saved group, else the flat
30
+ * Subagent card in `fixed` mode), so two sessions on different providers route
31
+ * their own spawns and neither can rewrite the other's policy.
32
+ * @param request - the caller's spawn request.
33
+ * @param route - the delegating session's resolved route, or undefined for official inherit.
34
+ * @returns The request to hand the official runtime.
35
+ */
36
+ export declare function routeSubagentRequest<T extends RoutableSubagentRequest>(request: T, route: SubagentRoute | undefined): T;
26
37
  /**
27
38
  * Mount a candidate and use the fallback only for typed startup incompatibility.
28
39
  *
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-model-switch",
3
- "version": "0.4.22",
3
+ "version": "0.4.24",
4
4
  "description": "Explicit model routing plus composer/Plan picker for DeepSeek Harness",
5
5
  "repository": {
6
6
  "type": "git",
@@ -46,6 +46,10 @@
46
46
  "types": "./lib/types/compaction.d.ts",
47
47
  "default": "./lib/compaction.js"
48
48
  },
49
+ "./session-title": {
50
+ "types": "./lib/types/session-title.d.ts",
51
+ "default": "./lib/session-title.js"
52
+ },
49
53
  "./subagent-runtime": {
50
54
  "types": "./lib/types/subagent-runtime.d.ts",
51
55
  "default": "./lib/subagent-runtime.js"
@@ -134,6 +138,10 @@
134
138
  "@deepseek-ai/dsh-permission-presets": ">=0.1.7-alpha.2",
135
139
  "@deepseek-ai/dsh-plan-mode": ">=0.1.7-alpha.2",
136
140
  "@deepseek-ai/dsh-session": ">=0.1.7-alpha.2",
141
+ "@deepseek-ai/dsh-session-title": ">=0.1.7-alpha.2",
142
+ "@deepseek-ai/dsh-session-title-all-prompts-llm": ">=0.1.7-alpha.2",
143
+ "@deepseek-ai/dsh-session-title-first-prompt-llm": ">=0.1.7-alpha.2",
144
+ "@deepseek-ai/dsh-session-title-llm": ">=0.1.7-alpha.2",
137
145
  "@deepseek-ai/dsh-settings": ">=0.1.7-alpha.2",
138
146
  "@deepseek-ai/dsh-subagent": ">=0.1.7-alpha.2",
139
147
  "@deepseek-ai/dsh-system-prompt": ">=0.1.7-alpha.2",
@@ -210,6 +218,9 @@
210
218
  "@deepseek-ai/dsh-session-query": ">=0.1.7-alpha.2",
211
219
  "@deepseek-ai/dsh-session-reference": ">=0.1.7-alpha.2",
212
220
  "@deepseek-ai/dsh-session-title": ">=0.1.7-alpha.2",
221
+ "@deepseek-ai/dsh-session-title-all-prompts-llm": ">=0.1.7-alpha.2",
222
+ "@deepseek-ai/dsh-session-title-first-prompt-llm": ">=0.1.7-alpha.2",
223
+ "@deepseek-ai/dsh-session-title-llm": ">=0.1.7-alpha.2",
213
224
  "@deepseek-ai/dsh-settings": ">=0.1.7-alpha.2",
214
225
  "@deepseek-ai/dsh-shell": ">=0.1.7-alpha.2",
215
226
  "@deepseek-ai/dsh-skill": ">=0.1.7-alpha.2",
@@ -323,6 +334,18 @@
323
334
  "@deepseek-ai/dsh-compaction-basic": {
324
335
  "optional": true
325
336
  },
337
+ "@deepseek-ai/dsh-session-title": {
338
+ "optional": true
339
+ },
340
+ "@deepseek-ai/dsh-session-title-all-prompts-llm": {
341
+ "optional": true
342
+ },
343
+ "@deepseek-ai/dsh-session-title-first-prompt-llm": {
344
+ "optional": true
345
+ },
346
+ "@deepseek-ai/dsh-session-title-llm": {
347
+ "optional": true
348
+ },
326
349
  "@deepseek-ai/dsh-settings": {
327
350
  "optional": true
328
351
  },