@deepseek-ai/dsh-client-ui-model-selection 0.1.7-rc.2 → 0.2.0-rc.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.i18n.yaml +2 -2
- package/README.md +2 -0
- package/README.zh.md +2 -0
- package/lib/client.js +26 -16
- package/lib/types/client/directory.d.ts +6 -1
- package/lib/types/client/service.d.ts +0 -14
- package/package.json +17 -16
package/README.i18n.yaml
CHANGED
|
@@ -6,8 +6,8 @@
|
|
|
6
6
|
en: f39813648aeef5a0
|
|
7
7
|
zh: eea25094e8bfc031
|
|
8
8
|
/deepseek-ai-dsh-client-ui-model-selection:
|
|
9
|
-
en:
|
|
10
|
-
zh:
|
|
9
|
+
en: 4cb6feb12e46f3a0
|
|
10
|
+
zh: eea39dd76fe1fa8b
|
|
11
11
|
/deepseek-ai-dsh-client-ui-model-selection/summary:
|
|
12
12
|
en: 2fb361ef704528fb
|
|
13
13
|
zh: 2537d2afb4d2cb45
|
package/README.md
CHANGED
|
@@ -7,6 +7,8 @@ kind: "package-reference"
|
|
|
7
7
|
|
|
8
8
|
English | [中文](README.zh.md)
|
|
9
9
|
|
|
10
|
+
Desktop product events use the optional [product analytics service](../product-analytics/README.md); ordinary Web interactions are excluded.
|
|
11
|
+
|
|
10
12
|
## Summary
|
|
11
13
|
|
|
12
14
|
The Web GUI lets users switch the model and reasoning effort for an existing session through either the `/model` popup or the composer's model control. Both surfaces present the same provider-grouped choices, and the selected model determines the available effort names and default. A complete selection applies to the next request; a running step keeps the model and effort it started with. If the selected model is unavailable, the composer stays disabled until the user selects an available model or that exact model becomes available again.
|
package/README.zh.md
CHANGED
|
@@ -7,6 +7,8 @@ kind: "package-reference"
|
|
|
7
7
|
|
|
8
8
|
[English](README.md) | 中文
|
|
9
9
|
|
|
10
|
+
桌面端产品事件使用可选的[产品埋点服务](../product-analytics/README.zh.md),不包含普通 Web 交互。
|
|
11
|
+
|
|
10
12
|
## 概述
|
|
11
13
|
|
|
12
14
|
Web GUI 允许用户通过 `/model` 弹窗或 composer 模型控件切换既有会话使用的模型与推理(reasoning)强度。两个界面呈现同一组按提供方分组的选择;所选模型决定可用的推理强度名称与默认值。完整选择从下一次请求开始生效;运行中的步骤保留其启动时的模型与推理强度。所选模型不可用时,composer 保持停用,直到用户选择可用模型或同一模型恢复可用。
|
package/lib/client.js
CHANGED
|
@@ -173,6 +173,8 @@ window.__ModuleLoader__.load({
|
|
|
173
173
|
available;
|
|
174
174
|
catalog;
|
|
175
175
|
projected;
|
|
176
|
+
isBlank;
|
|
177
|
+
track;
|
|
176
178
|
/** The shared snapshot both entries render from (uSES-safe store). */
|
|
177
179
|
store = (0, _deepseek_ai_dsh_client_store.createSnapshotStore)({
|
|
178
180
|
current: null,
|
|
@@ -194,13 +196,17 @@ window.__ModuleLoader__.load({
|
|
|
194
196
|
* @param available - whether this session may use Agent-bound model RPCs.
|
|
195
197
|
* @param catalog - Host-generation catalog shared by every Session.
|
|
196
198
|
* @param projected - durable model selection projected from Session history.
|
|
199
|
+
* @param isBlank - whether this Session has no first message yet.
|
|
200
|
+
* @param track - desktop-only callback after a successful user selection.
|
|
197
201
|
*/
|
|
198
|
-
constructor(sessions, sessionId, available, catalog, projected) {
|
|
202
|
+
constructor(sessions, sessionId, available, catalog, projected, isBlank, track) {
|
|
199
203
|
this.sessions = sessions;
|
|
200
204
|
this.sessionId = sessionId;
|
|
201
205
|
this.available = available;
|
|
202
206
|
this.catalog = catalog;
|
|
203
207
|
this.projected = projected;
|
|
208
|
+
this.isBlank = isBlank;
|
|
209
|
+
this.track = track;
|
|
204
210
|
this.unsubscribeCatalog = catalog.store.subscribe(() => {
|
|
205
211
|
this.syncInputs();
|
|
206
212
|
});
|
|
@@ -228,6 +234,9 @@ window.__ModuleLoader__.load({
|
|
|
228
234
|
*/
|
|
229
235
|
async select(selection) {
|
|
230
236
|
this.assertAvailable();
|
|
237
|
+
const previous = this.store.getSnapshot().current;
|
|
238
|
+
const previousEffort = previous?.reasoningEffort ?? (previous === null ? void 0 : this.catalog.reasoningFor(previous)?.defaultEffort);
|
|
239
|
+
const nextEffort = selection.reasoningEffort ?? this.catalog.reasoningFor(selection)?.defaultEffort;
|
|
231
240
|
const generation = ++this.generation;
|
|
232
241
|
this.store.update((s) => {
|
|
233
242
|
s.status = "selecting";
|
|
@@ -252,6 +261,21 @@ window.__ModuleLoader__.load({
|
|
|
252
261
|
});
|
|
253
262
|
return result;
|
|
254
263
|
}
|
|
264
|
+
if (previous !== null) {
|
|
265
|
+
const from = `${previous.provider}/${previous.model}`;
|
|
266
|
+
const to = `${selection.provider}/${selection.model}`;
|
|
267
|
+
if (from !== to) this.track?.("model_switch", {
|
|
268
|
+
...this.isBlank() ? {} : { session_id: this.sessionId },
|
|
269
|
+
switch_from: from,
|
|
270
|
+
switch_to: to
|
|
271
|
+
});
|
|
272
|
+
if (from === to && previousEffort !== nextEffort) this.track?.("thinking_level_switch", {
|
|
273
|
+
...this.isBlank() ? {} : { session_id: this.sessionId },
|
|
274
|
+
model_name: to,
|
|
275
|
+
switch_from: previousEffort ?? "default",
|
|
276
|
+
switch_to: nextEffort ?? "default"
|
|
277
|
+
});
|
|
278
|
+
}
|
|
255
279
|
this.store.update((s) => {
|
|
256
280
|
s.status = "ready";
|
|
257
281
|
s.pending = null;
|
|
@@ -325,20 +349,6 @@ window.__ModuleLoader__.load({
|
|
|
325
349
|
}
|
|
326
350
|
//#endregion
|
|
327
351
|
//#region lib/types/client/service.js
|
|
328
|
-
/**
|
|
329
|
-
* ModelDirectoryResolver (`ctx.modelDirectories`): the root owner of per-session
|
|
330
|
-
* {@link ModelDirectory} instances. Both selection entries (the /model popup
|
|
331
|
-
* and the composer model seat) resolve their session's directory through
|
|
332
|
-
* this service, which is what makes the dual entry one shared state.
|
|
333
|
-
*
|
|
334
|
-
* Per-session storage follows the client service pattern (InputTriggerService /
|
|
335
|
-
* CommandUiRuntime): a lazy service-internal map whose entry is deleted by the
|
|
336
|
-
* owning scope's disposer. The host `dsh-scope` ScopedLayers registry does
|
|
337
|
-
* does not belong here: it derives scope from the host carrier mechanism
|
|
338
|
-
* (object-keyed), while client scopes tag contexts with branded SessionId
|
|
339
|
-
* strings, and it models global+shadow named registries — this is a
|
|
340
|
-
* per-session singleton with no global layer to merge.
|
|
341
|
-
*/
|
|
342
352
|
/** The `ctx.modelDirectories` session model-selection service. */
|
|
343
353
|
var ModelDirectoryResolver = class extends _deepseek_ai_cordis.Service {
|
|
344
354
|
static inject = [
|
|
@@ -387,7 +397,7 @@ window.__ModuleLoader__.load({
|
|
|
387
397
|
if (binding === void 0) throw new Error(`ui-model-selection: session "${String(sessionId)}" resolved no binding`);
|
|
388
398
|
const existing = live.directories.get(binding);
|
|
389
399
|
if (existing !== void 0) return existing;
|
|
390
|
-
const directory = new ModelDirectory(this.ctx.remote.session, sessionId, () => sessions.subagentAddress(sessionId) === void 0, this.catalog, binding.session.projections.faceOf("modelSelection"));
|
|
400
|
+
const directory = new ModelDirectory(this.ctx.remote.session, sessionId, () => sessions.subagentAddress(sessionId) === void 0, this.catalog, binding.session.projections.faceOf("modelSelection"), () => binding.session.getSnapshot().blank, (name, attributes) => this.ctx.get("productAnalytics")?.track(name, attributes));
|
|
391
401
|
live.directories.set(binding, directory);
|
|
392
402
|
actx.effect(() => () => {
|
|
393
403
|
directory.dispose();
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* Session's durable selection projection, then submit through the same
|
|
5
5
|
* selectModel call. A switch made in either entry updates this shared state.
|
|
6
6
|
*/
|
|
7
|
+
import type { TrackProductEvent } from '@deepseek-ai/dsh-client-product-analytics/client';
|
|
7
8
|
import type { ModelCatalogFailure, ModelProviderGroup, ModelSelection } from '@deepseek-ai/dsh-api-session-controller/types';
|
|
8
9
|
import type { SessionId } from '@deepseek-ai/dsh-api-remotes/client';
|
|
9
10
|
import type { RemoteResult, TypertClientRemote } from '@deepseek-ai/dsh-typert-protocol';
|
|
@@ -35,6 +36,8 @@ export declare class ModelDirectory {
|
|
|
35
36
|
private readonly available;
|
|
36
37
|
private readonly catalog;
|
|
37
38
|
private readonly projected;
|
|
39
|
+
private readonly isBlank;
|
|
40
|
+
private readonly track?;
|
|
38
41
|
/** The shared snapshot both entries render from (uSES-safe store). */
|
|
39
42
|
readonly store: SnapshotStore<ModelDirectoryState>;
|
|
40
43
|
/** Latest selection operation wins; an older response never overwrites a newer one. */
|
|
@@ -48,8 +51,10 @@ export declare class ModelDirectory {
|
|
|
48
51
|
* @param available - whether this session may use Agent-bound model RPCs.
|
|
49
52
|
* @param catalog - Host-generation catalog shared by every Session.
|
|
50
53
|
* @param projected - durable model selection projected from Session history.
|
|
54
|
+
* @param isBlank - whether this Session has no first message yet.
|
|
55
|
+
* @param track - desktop-only callback after a successful user selection.
|
|
51
56
|
*/
|
|
52
|
-
constructor(sessions: Pick<TypertClientRemote['session'], 'selectModel'>, sessionId: SessionId, available: () => boolean, catalog: ModelCatalogDirectory, projected: ObservableSnapshot<unknown
|
|
57
|
+
constructor(sessions: Pick<TypertClientRemote['session'], 'selectModel'>, sessionId: SessionId, available: () => boolean, catalog: ModelCatalogDirectory, projected: ObservableSnapshot<unknown>, isBlank: () => boolean, track?: TrackProductEvent | undefined);
|
|
53
58
|
/**
|
|
54
59
|
* Ensure the Host generation's shared available catalog is loaded.
|
|
55
60
|
* @returns the fresh directory value.
|
|
@@ -1,17 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* ModelDirectoryResolver (`ctx.modelDirectories`): the root owner of per-session
|
|
3
|
-
* {@link ModelDirectory} instances. Both selection entries (the /model popup
|
|
4
|
-
* and the composer model seat) resolve their session's directory through
|
|
5
|
-
* this service, which is what makes the dual entry one shared state.
|
|
6
|
-
*
|
|
7
|
-
* Per-session storage follows the client service pattern (InputTriggerService /
|
|
8
|
-
* CommandUiRuntime): a lazy service-internal map whose entry is deleted by the
|
|
9
|
-
* owning scope's disposer. The host `dsh-scope` ScopedLayers registry does
|
|
10
|
-
* does not belong here: it derives scope from the host carrier mechanism
|
|
11
|
-
* (object-keyed), while client scopes tag contexts with branded SessionId
|
|
12
|
-
* strings, and it models global+shadow named registries — this is a
|
|
13
|
-
* per-session singleton with no global layer to merge.
|
|
14
|
-
*/
|
|
15
1
|
import { Service } from '@deepseek-ai/cordis';
|
|
16
2
|
import type { Context } from '@deepseek-ai/cordis';
|
|
17
3
|
import type { SessionId } from '@deepseek-ai/dsh-session/types';
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@deepseek-ai/dsh-client-ui-model-selection",
|
|
3
3
|
"description": "Model selection over the shared model catalog, Session projection, and session.selectModel",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.2.0-rc.1",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
7
7
|
},
|
|
@@ -46,22 +46,23 @@
|
|
|
46
46
|
"react-dom": "^18.2.0",
|
|
47
47
|
"@types/react-dom": "~18.3.0",
|
|
48
48
|
"clsx": "^2.1.1",
|
|
49
|
-
"@deepseek-ai/dsh-api-remotes": "0.
|
|
50
|
-
"@deepseek-ai/dsh-api-session-controller": "0.
|
|
51
|
-
"@deepseek-ai/dsh-client-locale": "0.
|
|
52
|
-
"@deepseek-ai/dsh-client-test-runtime": "0.
|
|
53
|
-
"@deepseek-ai/dsh-client-ui-
|
|
54
|
-
"@deepseek-ai/dsh-client-ui-
|
|
55
|
-
"@deepseek-ai/dsh-client-ui-
|
|
56
|
-
"@deepseek-ai/dsh-client-ui-
|
|
57
|
-
"@deepseek-ai/dsh-
|
|
58
|
-
"@deepseek-ai/dsh-typert-protocol": "0.1.7-rc.2",
|
|
49
|
+
"@deepseek-ai/dsh-api-remotes": "0.2.0-rc.1",
|
|
50
|
+
"@deepseek-ai/dsh-api-session-controller": "0.2.0-rc.1",
|
|
51
|
+
"@deepseek-ai/dsh-client-locale": "0.2.0-rc.1",
|
|
52
|
+
"@deepseek-ai/dsh-client-test-runtime": "0.2.0-rc.1",
|
|
53
|
+
"@deepseek-ai/dsh-client-ui-conversation": "0.2.0-rc.1",
|
|
54
|
+
"@deepseek-ai/dsh-client-ui-commands": "0.2.0-rc.1",
|
|
55
|
+
"@deepseek-ai/dsh-client-ui-primitives": "0.2.0-rc.1",
|
|
56
|
+
"@deepseek-ai/dsh-client-ui-slots": "0.2.0-rc.1",
|
|
57
|
+
"@deepseek-ai/dsh-typert-protocol": "0.2.0-rc.1",
|
|
59
58
|
"@deepseek-ai/cordis": "~4.0.4",
|
|
60
|
-
"@deepseek-ai/dsh-client-store": "0.
|
|
61
|
-
"@deepseek-ai/dsh-session": "0.
|
|
62
|
-
"@deepseek-ai/dsh-util-values": "0.
|
|
63
|
-
"@deepseek-ai/dsh-client-ui-
|
|
64
|
-
"@deepseek-ai/dsh-client-ui-
|
|
59
|
+
"@deepseek-ai/dsh-client-store": "0.2.0-rc.1",
|
|
60
|
+
"@deepseek-ai/dsh-session": "0.2.0-rc.1",
|
|
61
|
+
"@deepseek-ai/dsh-util-values": "0.2.0-rc.1",
|
|
62
|
+
"@deepseek-ai/dsh-client-ui-input-trigger": "0.2.0-rc.1",
|
|
63
|
+
"@deepseek-ai/dsh-client-ui-renderer": "0.2.0-rc.1",
|
|
64
|
+
"@deepseek-ai/dsh-client-ui-session": "0.2.0-rc.1",
|
|
65
|
+
"@deepseek-ai/dsh-client-product-analytics": "0.2.0-rc.1"
|
|
65
66
|
},
|
|
66
67
|
"files": [
|
|
67
68
|
"lib/index.js",
|