dsh-advisor 0.4.0 → 0.5.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.
- package/README.i18n.yaml +2 -2
- package/README.md +31 -22
- package/README.zh.md +31 -22
- package/lib/advisor-runtime.js +1 -1
- package/lib/client/advisor-card.d.ts +18 -14
- package/lib/client/advisor-session.d.ts +75 -0
- package/lib/client/advisor-store.d.ts +131 -0
- package/lib/client/index.d.ts +18 -13
- package/lib/client/locales.d.ts +15 -0
- package/lib/client.js +375 -14
- package/lib/commands.d.ts +220 -27
- package/lib/commands.js +260 -34
- package/lib/commands.js.map +1 -1
- package/lib/config.d.ts +74 -20
- package/lib/config.js +74 -20
- package/lib/config.js.map +1 -1
- package/lib/delivery.d.ts +9 -9
- package/lib/delivery.js +10 -12
- package/lib/delivery.js.map +1 -1
- package/lib/gateway.d.ts +139 -24
- package/lib/gateway.js +138 -27
- package/lib/gateway.js.map +1 -1
- package/lib/index.d.ts +5 -5
- package/lib/index.js +483 -82
- package/lib/index.js.map +1 -1
- package/lib/kinds.d.ts +79 -51
- package/lib/kinds.js +60 -43
- package/lib/kinds.js.map +1 -1
- package/lib/settings.d.ts +56 -86
- package/lib/settings.js +48 -91
- package/lib/settings.js.map +1 -1
- package/lib/transcript.d.ts +11 -9
- package/lib/transcript.js +25 -16
- package/lib/transcript.js.map +1 -1
- package/lib/tui-settings.d.ts +10 -10
- package/lib/tui-settings.js +10 -10
- package/lib/tui-settings.js.map +1 -1
- package/lib/tui.js +39 -5
- package/lib/tui.js.map +1 -1
- package/package.json +24 -23
package/lib/client/index.d.ts
CHANGED
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Advisor settings plugin, browser half. Registers the
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
2
|
+
* Advisor settings plugin, browser half. Registers the Advisor card into the
|
|
3
|
+
* shell-declared `plugins.bundle.config` keyed slot (the Plugins page's
|
|
4
|
+
* per-bundle configuration seat — key `dsh-advisor`, the bundle's package name
|
|
5
|
+
* the page dispatches, rendered on the bundle's own page between its
|
|
6
|
+
* description and its rows) and, since B2, an Advisor action into the
|
|
7
|
+
* shell-declared `conversation.session.header.actions` list slot (the
|
|
8
|
+
* per-session reviewer-model control, bound to the slot parent's SessionId —
|
|
9
|
+
* the global card stays global-only). The card's store joins the settings
|
|
10
|
+
* namespaces and the provider directory through the connection wire, and
|
|
11
|
+
* keeps fresh on pushed invalidations. Export discipline: the client half
|
|
12
|
+
* value-imports ONLY the frozen platform module table (CLIENT_EXTERNALS:
|
|
13
|
+
* react / `@deepseek-ai/cordis` / ui-slots / ui-primitives / the documented
|
|
11
14
|
* `@deepseek-ai/dsh-client-store` exemption); every other
|
|
12
15
|
* `@deepseek-ai/*` import is type-only (erased at build) — values arrive via
|
|
13
16
|
* cordis injection (`ctx.get('connection')`, slot inject faces, the
|
|
@@ -16,8 +19,9 @@
|
|
|
16
19
|
import type { Context as ClientContext } from '@deepseek-ai/cordis';
|
|
17
20
|
import { type AdvisorKey } from './locales.ts';
|
|
18
21
|
export type { AdvisorCardInjected, AdvisorCardProps } from './advisor-card.tsx';
|
|
22
|
+
export type { AdvisorSessionActionInjected, AdvisorSessionActionProps } from './advisor-session.tsx';
|
|
19
23
|
export type { AdvisorKey } from './locales.ts';
|
|
20
|
-
export type { AdvisorDraft, AdvisorSettingsState, AdvisorSettingsStore, ApplyFailure, ApplyState, ModelOption, ModelsEmptyReason, ProviderOption, } from './advisor-store.ts';
|
|
24
|
+
export type { AdvisorDraft, AdvisorSessionMenuState, AdvisorSessionModelController, AdvisorSessionRpcPayload, AdvisorSessionSelection, AdvisorSessionSnapshotView, AdvisorSettingsState, AdvisorSettingsStore, ApplyFailure, ApplyState, ModelOption, ModelsEmptyReason, ProviderOption, } from './advisor-store.ts';
|
|
21
25
|
declare module '@deepseek-ai/dsh-client-ui-slots' {
|
|
22
26
|
interface LocaleNamespaceMap {
|
|
23
27
|
/** The Advisor settings card copy. */
|
|
@@ -27,8 +31,9 @@ declare module '@deepseek-ai/dsh-client-ui-slots' {
|
|
|
27
31
|
export { refreshIfLoaded } from './advisor-store.ts';
|
|
28
32
|
/**
|
|
29
33
|
* Required services (cordis fiber inject). The target slot is declared by
|
|
30
|
-
* ui-plugin-
|
|
31
|
-
* NOT constrained; registration depends on the
|
|
34
|
+
* ui-plugin-manager's apply (its `plugins` main-panel entry), whose activation
|
|
35
|
+
* order relative to this one is NOT constrained; registration depends on the
|
|
36
|
+
* slot through `slots.inject()`.
|
|
32
37
|
*
|
|
33
38
|
* rc.1 dotted-namespace contract: each client Remote namespace is a
|
|
34
39
|
* child-fiber service named `remote.<ns>` (upstream `remoteServiceKey`), and
|
|
@@ -41,7 +46,7 @@ export { refreshIfLoaded } from './advisor-store.ts';
|
|
|
41
46
|
*/
|
|
42
47
|
export declare const inject: string[];
|
|
43
48
|
/**
|
|
44
|
-
* Register the Advisor card once the `
|
|
49
|
+
* Register the Advisor card once the `plugins.bundle.config` declaration is on
|
|
45
50
|
* the ledger, wire its store to the connection, and keep it fresh on every
|
|
46
51
|
* pushed invalidation (settings or provider topology).
|
|
47
52
|
* @param ctx - client root context.
|
package/lib/client/locales.d.ts
CHANGED
|
@@ -33,6 +33,21 @@ export declare const en: {
|
|
|
33
33
|
saved: string;
|
|
34
34
|
readOnly: string;
|
|
35
35
|
namespaceUnavailable: string;
|
|
36
|
+
sessionTrigger: string;
|
|
37
|
+
sessionExpand: string;
|
|
38
|
+
sessionCollapse: string;
|
|
39
|
+
sessionLoading: string;
|
|
40
|
+
sessionModelHeading: string;
|
|
41
|
+
sessionSourceSession: string;
|
|
42
|
+
sessionSourceGlobal: string;
|
|
43
|
+
sessionNoPair: string;
|
|
44
|
+
sessionLifetime: string;
|
|
45
|
+
sessionAdvisorOff: string;
|
|
46
|
+
sessionGateBlocked: string;
|
|
47
|
+
sessionPinAction: string;
|
|
48
|
+
sessionPending: string;
|
|
49
|
+
sessionReset: string;
|
|
50
|
+
sessionUnavailable: string;
|
|
36
51
|
};
|
|
37
52
|
/** The settings.advisor namespace key union. */
|
|
38
53
|
export type AdvisorKey = keyof typeof en;
|
package/lib/client.js
CHANGED
|
@@ -34,7 +34,7 @@ module.exports = __toCommonJS(index_exports);
|
|
|
34
34
|
var import_react = require("react");
|
|
35
35
|
var import_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
|
|
36
36
|
|
|
37
|
-
var css = `.kPHV8a_card{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);border-radius:12px;
|
|
37
|
+
var css = `.kPHV8a_card{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);border-radius:12px;transition:border-color .16s,background .16s}.kPHV8a_card:hover{border-color:var(--dsw-alias-label-dimmed)}.kPHV8a_cardOpen{background:var(--dsw-alias-bg-layer-2);border-color:var(--dsw-alias-label-dimmed)}.kPHV8a_header{appearance:none;width:100%;font:inherit;color:inherit;text-align:left;cursor:pointer;background:0 0;border:0;border-radius:12px;align-items:center;gap:12px;padding:14px 16px;display:flex}.kPHV8a_header:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:-2px}.kPHV8a_headText{flex-direction:column;flex:1;gap:4px;min-width:0;display:flex}.kPHV8a_name{color:var(--dsw-alias-label-primary);font-size:15px;font-weight:600;line-height:1.4}.kPHV8a_description{color:var(--dsw-alias-label-tertiary);font-size:13px;line-height:1.5}.kPHV8a_chevron{color:var(--dsw-alias-label-tertiary);flex:none;transition:transform .16s}.kPHV8a_chevronOpen{transform:rotate(180deg)}.kPHV8a_body{border-top:1px solid var(--dsw-alias-border-l2);margin:0 16px;padding-bottom:8px}.kPHV8a_readOnly{color:var(--dsw-alias-label-tertiary);margin:12px 0 0;font-size:12px;line-height:1.5}.kPHV8a_pending{white-space:nowrap;background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-label-secondary);border-radius:999px;flex:none;padding:1px 8px;font-size:11px;font-weight:500;line-height:17px}.kPHV8a_footer{border-top:1px solid var(--dsw-alias-border-l2);justify-content:flex-end;align-items:center;gap:8px;padding:12px 0 4px;display:flex}.kPHV8a_failed{min-width:0;color:var(--dsw-alias-label-error);flex:1;margin:0;font-size:12px;line-height:1.5}.kPHV8a_discard,.kPHV8a_save{appearance:none;font:inherit;cursor:pointer;border:1px solid #0000;border-radius:8px;padding:5px 14px;font-size:13px;line-height:1.5}.kPHV8a_discard{border-color:var(--dsw-alias-border-l2);color:var(--dsw-alias-label-secondary);background:0 0}.kPHV8a_discard:hover:not(:disabled){color:var(--dsw-alias-label-primary);border-color:var(--dsw-alias-label-dimmed)}.kPHV8a_save{background:var(--dsw-alias-label-primary);color:var(--dsw-alias-bg-layer-3)}.kPHV8a_discard:disabled,.kPHV8a_save:disabled{opacity:.4;cursor:default}.kPHV8a_discard:focus-visible,.kPHV8a_save:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:1px}.kPHV8a_notice{color:var(--dsw-alias-state-warn-label);margin:12px 0 0;font-size:12px;line-height:18px}.kPHV8a_savedNotice{color:var(--dsw-alias-state-success-primary);margin:12px 0 0;font-size:12px;line-height:18px}.kPHV8a_error{color:var(--dsw-alias-state-error-primary);margin:12px 0 0;font-size:12px;line-height:18px}.kPHV8a_form{flex-direction:column;gap:12px;padding:12px 0 0;display:flex}.kPHV8a_checkboxRow{align-items:center;gap:8px;display:flex}.kPHV8a_checkLabel{color:var(--dsw-alias-label-primary);font-size:14px;font-weight:500;line-height:22px}.kPHV8a_checkbox{width:16px;height:16px;accent-color:var(--dsw-alias-brand-primary);cursor:pointer;margin:0}.kPHV8a_checkbox:disabled{opacity:.4;cursor:default}.kPHV8a_checkbox:focus-visible{outline:2px solid var(--dsw-alias-border-l3);outline-offset:2px}.kPHV8a_fieldset{border:none;flex-direction:column;gap:12px;margin:0;padding:0;display:flex}.kPHV8a_field{flex-direction:column;gap:6px;display:flex}.kPHV8a_fieldLabel{color:var(--dsw-alias-label-secondary);align-items:center;gap:10px;font-size:12px;font-weight:500;line-height:18px;display:inline-flex}.kPHV8a_input{box-sizing:border-box;border:1px solid var(--dsw-alias-border-l2);width:100%;height:32px;font:inherit;background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-primary);border-radius:8px;padding:0 10px;font-size:14px;line-height:22px}select.kPHV8a_input{cursor:pointer;max-width:240px}.kPHV8a_input:focus{border-color:var(--dsw-alias-brand-primary);outline:none}.kPHV8a_input::placeholder{color:var(--dsw-alias-label-dimmed)}.kPHV8a_input:disabled{opacity:.6;cursor:default}.kPHV8a_selectInput{appearance:none;background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12' fill='none'%3E%3Cpath d='M3 4.5L6 7.5L9 4.5' stroke='%2381858C' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");background-position:right 12px center;background-repeat:no-repeat;background-size:12px 12px;padding-right:32px}.kPHV8a_textarea{box-sizing:border-box;border:1px solid var(--dsw-alias-border-l2);width:100%;min-height:96px;font:inherit;background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-primary);resize:vertical;border-radius:8px;padding:8px 10px;font-size:14px;line-height:22px}.kPHV8a_textarea:focus{border-color:var(--dsw-alias-brand-primary);outline:none}.kPHV8a_textarea:disabled{opacity:.6;cursor:default}.kPHV8a_numberFields{grid-template-columns:repeat(auto-fit,minmax(160px,1fr));gap:12px;display:grid}.kPHV8a_hint{color:var(--dsw-alias-label-tertiary);margin:0;font-size:12px;line-height:18px}.kPHV8a_warnHint{color:var(--dsw-alias-state-warn-label);margin:0;font-size:12px;line-height:18px}`;
|
|
38
38
|
var tagId = "dsh-advisor/advisor-card.module.css";
|
|
39
39
|
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
|
|
40
40
|
const tag = document.createElement("style");
|
|
@@ -80,7 +80,7 @@ function AdvisorCard(props) {
|
|
|
80
80
|
] }),
|
|
81
81
|
state.dirty ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: advisor_card_module_css_default["pending"], children: t("unsaved") }) : null,
|
|
82
82
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
83
|
-
import_dsh_client_ui_primitives.
|
|
83
|
+
import_dsh_client_ui_primitives.IconChevronDownOutlineRegular,
|
|
84
84
|
{
|
|
85
85
|
className: open ? `${advisor_card_module_css_default["chevron"]} ${advisor_card_module_css_default["chevronOpen"]}` : advisor_card_module_css_default["chevron"]
|
|
86
86
|
}
|
|
@@ -276,12 +276,154 @@ function AdvisorCard(props) {
|
|
|
276
276
|
} else {
|
|
277
277
|
body = /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: advisor_card_module_css_default["body"] });
|
|
278
278
|
}
|
|
279
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("
|
|
279
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: open ? `${advisor_card_module_css_default["card"]} ${advisor_card_module_css_default["cardOpen"]}` : advisor_card_module_css_default["card"], children: [
|
|
280
280
|
header,
|
|
281
281
|
open ? body : null
|
|
282
282
|
] });
|
|
283
283
|
}
|
|
284
284
|
|
|
285
|
+
// src/client/advisor-session.tsx
|
|
286
|
+
var import_react2 = require("react");
|
|
287
|
+
|
|
288
|
+
var css2 = ".C5gNya_trigger{appearance:none;border:1px solid var(--dsw-alias-border-l2);font:inherit;color:var(--dsw-alias-label-secondary);cursor:pointer;white-space:nowrap;background:0 0;border-radius:999px;padding:3px 12px;font-size:13px;line-height:20px}.C5gNya_trigger:hover{color:var(--dsw-alias-label-primary);border-color:var(--dsw-alias-label-dimmed)}.C5gNya_trigger[aria-expanded=true]{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-3);border-color:var(--dsw-alias-label-dimmed)}.C5gNya_trigger:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:1px}.C5gNya_anchor{display:inline-flex;position:relative}.C5gNya_panel{z-index:30;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);border-radius:12px;flex-direction:column;gap:10px;width:300px;padding:12px 14px;display:flex;position:absolute;top:calc(100% + 6px);right:0;box-shadow:0 8px 24px #0000002e}.C5gNya_panelHeading{color:var(--dsw-alias-label-primary);margin:0;font-size:13px;font-weight:600;line-height:20px}.C5gNya_routeLine{color:var(--dsw-alias-label-primary);overflow-wrap:anywhere;margin:0;font-size:13px;line-height:20px}.C5gNya_sourceBadge{white-space:nowrap;background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-label-secondary);border-radius:999px;margin-left:6px;padding:1px 8px;font-size:11px;font-weight:500;line-height:17px}.C5gNya_mutedLine{color:var(--dsw-alias-label-tertiary);margin:0;font-size:12px;line-height:18px}.C5gNya_notice{color:var(--dsw-alias-state-warn-label);margin:0;font-size:12px;line-height:18px}.C5gNya_error{color:var(--dsw-alias-state-error-primary);margin:0;font-size:12px;line-height:18px}.C5gNya_controls{border-top:1px solid var(--dsw-alias-border-l2);flex-direction:column;gap:8px;padding-top:8px;display:flex}.C5gNya_selectRow{gap:8px;display:flex}.C5gNya_select{appearance:auto;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-2);min-width:0;color:var(--dsw-alias-label-primary);font:inherit;border-radius:8px;flex:1;padding:4px 6px;font-size:12px;line-height:18px}.C5gNya_select:disabled{opacity:.4;cursor:default}.C5gNya_select:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:-1px}.C5gNya_actions{justify-content:flex-end;align-items:center;gap:8px;display:flex}.C5gNya_reset,.C5gNya_pin{appearance:none;font:inherit;cursor:pointer;border:1px solid #0000;border-radius:8px;padding:4px 12px;font-size:12px;line-height:18px}.C5gNya_reset{border-color:var(--dsw-alias-border-l2);color:var(--dsw-alias-label-secondary);background:0 0}.C5gNya_reset:hover:not(:disabled){color:var(--dsw-alias-label-primary);border-color:var(--dsw-alias-label-dimmed)}.C5gNya_pin{background:var(--dsw-alias-label-primary);color:var(--dsw-alias-bg-layer-3)}.C5gNya_reset:disabled,.C5gNya_pin:disabled{opacity:.4;cursor:default}.C5gNya_reset:focus-visible,.C5gNya_pin:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:1px}";
|
|
289
|
+
var tagId2 = "dsh-advisor/advisor-session.module.css";
|
|
290
|
+
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId2) + "]") === null) {
|
|
291
|
+
const tag = document.createElement("style");
|
|
292
|
+
tag.dataset.plugin = "dsh-advisor";
|
|
293
|
+
tag.dataset.pluginCss = tagId2;
|
|
294
|
+
tag.textContent = css2;
|
|
295
|
+
document.head.appendChild(tag);
|
|
296
|
+
}
|
|
297
|
+
var advisor_session_module_css_default = { "actions": "C5gNya_actions", "anchor": "C5gNya_anchor", "controls": "C5gNya_controls", "error": "C5gNya_error", "mutedLine": "C5gNya_mutedLine", "notice": "C5gNya_notice", "panel": "C5gNya_panel", "panelHeading": "C5gNya_panelHeading", "pin": "C5gNya_pin", "reset": "C5gNya_reset", "routeLine": "C5gNya_routeLine", "select": "C5gNya_select", "selectRow": "C5gNya_selectRow", "sourceBadge": "C5gNya_sourceBadge", "trigger": "C5gNya_trigger" };
|
|
298
|
+
|
|
299
|
+
// src/client/advisor-session.tsx
|
|
300
|
+
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
301
|
+
function AdvisorSessionAction(props) {
|
|
302
|
+
const { controller, directory, useSnapshot, useRefreshSignal, useDirectory, t } = props;
|
|
303
|
+
const state = useSnapshot((s) => s);
|
|
304
|
+
const epoch = useRefreshSignal((s) => s.epoch);
|
|
305
|
+
const directoryState = useDirectory((s) => s);
|
|
306
|
+
const [open, setOpen] = (0, import_react2.useState)(false);
|
|
307
|
+
const [provider, setProvider] = (0, import_react2.useState)("");
|
|
308
|
+
const [model, setModel] = (0, import_react2.useState)("");
|
|
309
|
+
const openAdvisor = () => {
|
|
310
|
+
setOpen(true);
|
|
311
|
+
controller.takeSignal(epoch);
|
|
312
|
+
void controller.refresh();
|
|
313
|
+
if (directoryState.status === "idle") void directory.load();
|
|
314
|
+
};
|
|
315
|
+
if (open && controller.takeSignal(epoch)) void controller.refresh();
|
|
316
|
+
const snapshot = state.snapshot;
|
|
317
|
+
const busy = state.pending;
|
|
318
|
+
const pinned = snapshot?.modelSource === "session";
|
|
319
|
+
let body;
|
|
320
|
+
if (state.unavailable) {
|
|
321
|
+
body = /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: advisor_session_module_css_default.notice, role: "status", children: t("sessionUnavailable") });
|
|
322
|
+
} else if (snapshot === null) {
|
|
323
|
+
body = /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: advisor_session_module_css_default.mutedLine, role: "status", children: t("sessionLoading") });
|
|
324
|
+
} else {
|
|
325
|
+
const pair = snapshot.effectiveModel !== void 0 ? `${snapshot.effectiveModel.provider}/${snapshot.effectiveModel.model}` : void 0;
|
|
326
|
+
body = /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
|
|
327
|
+
snapshot.enabled ? null : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: advisor_session_module_css_default.notice, children: t("sessionAdvisorOff") }),
|
|
328
|
+
snapshot.disabledReason !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: advisor_session_module_css_default.notice, children: t("sessionGateBlocked", { reason: snapshot.disabledReason }) }) : null,
|
|
329
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("p", { className: advisor_session_module_css_default.routeLine, children: [
|
|
330
|
+
pair === void 0 ? t("sessionNoPair") : pair,
|
|
331
|
+
pair !== void 0 && snapshot.modelSource !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: advisor_session_module_css_default.sourceBadge, children: t(snapshot.modelSource === "session" ? "sessionSourceSession" : "sessionSourceGlobal") }) : null
|
|
332
|
+
] }),
|
|
333
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: advisor_session_module_css_default.mutedLine, children: t("sessionLifetime") }),
|
|
334
|
+
state.error !== null ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: advisor_session_module_css_default.error, role: "status", children: state.error }) : null,
|
|
335
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: advisor_session_module_css_default.controls, children: [
|
|
336
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: advisor_session_module_css_default.selectRow, children: [
|
|
337
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
338
|
+
"select",
|
|
339
|
+
{
|
|
340
|
+
"aria-label": t("provider"),
|
|
341
|
+
className: advisor_session_module_css_default.select,
|
|
342
|
+
value: provider,
|
|
343
|
+
disabled: busy,
|
|
344
|
+
onChange: (event) => {
|
|
345
|
+
const next = event.target.value;
|
|
346
|
+
setProvider(next);
|
|
347
|
+
setModel("");
|
|
348
|
+
if (next !== "") void directory.ensureModels(next);
|
|
349
|
+
},
|
|
350
|
+
children: [
|
|
351
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: "", children: t("providerPlaceholder") }),
|
|
352
|
+
directoryState.providers.map((option) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: option.provider, children: option.displayName }, option.provider))
|
|
353
|
+
]
|
|
354
|
+
}
|
|
355
|
+
),
|
|
356
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
357
|
+
"select",
|
|
358
|
+
{
|
|
359
|
+
"aria-label": t("model"),
|
|
360
|
+
className: advisor_session_module_css_default.select,
|
|
361
|
+
value: model,
|
|
362
|
+
disabled: busy || provider === "" || (directoryState.modelsByProvider[provider]?.length ?? 0) === 0,
|
|
363
|
+
onChange: (event) => {
|
|
364
|
+
setModel(event.target.value);
|
|
365
|
+
},
|
|
366
|
+
children: [
|
|
367
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: "", children: t("modelPlaceholder") }),
|
|
368
|
+
(directoryState.modelsByProvider[provider] ?? []).map((option) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: option.id, children: option.name }, option.id))
|
|
369
|
+
]
|
|
370
|
+
}
|
|
371
|
+
)
|
|
372
|
+
] }),
|
|
373
|
+
provider !== "" && (directoryState.modelsByProvider[provider]?.length ?? 0) === 0 ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: advisor_session_module_css_default.mutedLine, children: t("noModels") }) : null,
|
|
374
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: advisor_session_module_css_default.actions, children: [
|
|
375
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
376
|
+
"button",
|
|
377
|
+
{
|
|
378
|
+
type: "button",
|
|
379
|
+
className: advisor_session_module_css_default.reset,
|
|
380
|
+
disabled: busy || !pinned,
|
|
381
|
+
onClick: () => {
|
|
382
|
+
void controller.resetSessionModel();
|
|
383
|
+
},
|
|
384
|
+
children: t("sessionReset")
|
|
385
|
+
}
|
|
386
|
+
),
|
|
387
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
388
|
+
"button",
|
|
389
|
+
{
|
|
390
|
+
type: "button",
|
|
391
|
+
className: advisor_session_module_css_default.pin,
|
|
392
|
+
disabled: busy || provider === "" || model === "",
|
|
393
|
+
onClick: () => {
|
|
394
|
+
void controller.setSessionModel(provider, model);
|
|
395
|
+
},
|
|
396
|
+
children: busy ? t("sessionPending") : t("sessionPinAction")
|
|
397
|
+
}
|
|
398
|
+
)
|
|
399
|
+
] })
|
|
400
|
+
] })
|
|
401
|
+
] });
|
|
402
|
+
}
|
|
403
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: advisor_session_module_css_default.anchor, children: [
|
|
404
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
405
|
+
"button",
|
|
406
|
+
{
|
|
407
|
+
type: "button",
|
|
408
|
+
className: advisor_session_module_css_default.trigger,
|
|
409
|
+
"aria-expanded": open,
|
|
410
|
+
"aria-haspopup": "dialog",
|
|
411
|
+
"aria-label": t(open ? "sessionCollapse" : "sessionExpand"),
|
|
412
|
+
onClick: () => {
|
|
413
|
+
if (open) setOpen(false);
|
|
414
|
+
else openAdvisor();
|
|
415
|
+
},
|
|
416
|
+
children: t("sessionTrigger")
|
|
417
|
+
}
|
|
418
|
+
),
|
|
419
|
+
open ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: advisor_session_module_css_default.panel, role: "dialog", "aria-label": t("sessionModelHeading"), children: [
|
|
420
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: advisor_session_module_css_default.panelHeading, children: t("sessionModelHeading") }),
|
|
421
|
+
directoryState.providers.length === 0 && directoryState.status === "ready" && !state.unavailable ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: advisor_session_module_css_default.mutedLine, children: t("noProviders") }) : null,
|
|
422
|
+
body
|
|
423
|
+
] }) : null
|
|
424
|
+
] });
|
|
425
|
+
}
|
|
426
|
+
|
|
285
427
|
// src/client/advisor-store.ts
|
|
286
428
|
var import_dsh_client_store = require("@deepseek-ai/dsh-client-store");
|
|
287
429
|
function defaultDraft() {
|
|
@@ -741,6 +883,162 @@ function refreshIfLoaded(controller) {
|
|
|
741
883
|
if (controller.store.getSnapshot().status === "idle") return;
|
|
742
884
|
void controller.load();
|
|
743
885
|
}
|
|
886
|
+
var AdvisorSessionModelController = class {
|
|
887
|
+
constructor(sessionId, rpc) {
|
|
888
|
+
__publicField(this, "rpc", rpc);
|
|
889
|
+
__publicField(this, "sessionId");
|
|
890
|
+
/** The snapshot the menu renders from (uSES-safe store). */
|
|
891
|
+
__publicField(this, "store", (0, import_dsh_client_store.createSnapshotStore)({
|
|
892
|
+
phase: "idle",
|
|
893
|
+
snapshot: null,
|
|
894
|
+
error: null,
|
|
895
|
+
unavailable: false,
|
|
896
|
+
pending: false
|
|
897
|
+
}));
|
|
898
|
+
/** Fence token: a newer op makes every older settle stale. */
|
|
899
|
+
__publicField(this, "requestSeq", 0);
|
|
900
|
+
/** Last consumed refresh-signal epoch (reconnect / focus bumps). */
|
|
901
|
+
__publicField(this, "lastSignal");
|
|
902
|
+
this.sessionId = sessionId;
|
|
903
|
+
}
|
|
904
|
+
/**
|
|
905
|
+
* Record the refresh-signal epoch and report whether it is NEW. The open
|
|
906
|
+
* handler always refetches and merely marks the signal current; the render
|
|
907
|
+
* watcher calls this while open and refetches only on a true return (a
|
|
908
|
+
* reconnect/focus bump). Idempotent per epoch, so a re-render never
|
|
909
|
+
* double-fetches.
|
|
910
|
+
*/
|
|
911
|
+
takeSignal(epoch) {
|
|
912
|
+
if (this.lastSignal === epoch) return false;
|
|
913
|
+
this.lastSignal = epoch;
|
|
914
|
+
return true;
|
|
915
|
+
}
|
|
916
|
+
/**
|
|
917
|
+
* Fetch the authoritative snapshot (`/api/advisor/getSession`). Called on
|
|
918
|
+
* menu open and on every refresh signal while open. A stale settle (a newer
|
|
919
|
+
* op superseded this fetch) touches nothing. An `advisor/unavailable` /
|
|
920
|
+
* `advisor/session-unknown` tag or a transport failure latches
|
|
921
|
+
* `unavailable` (writes stay off until a later successful refresh); other
|
|
922
|
+
* tagged outcomes leave the surface usable with the error shown.
|
|
923
|
+
*/
|
|
924
|
+
async refresh() {
|
|
925
|
+
const seq = ++this.requestSeq;
|
|
926
|
+
this.store.update((s) => {
|
|
927
|
+
s.phase = "loading";
|
|
928
|
+
s.pending = false;
|
|
929
|
+
s.error = null;
|
|
930
|
+
});
|
|
931
|
+
let payload;
|
|
932
|
+
let transport;
|
|
933
|
+
try {
|
|
934
|
+
const result = await this.rpc.call("/api", "advisor/getSession", { args: { sessionId: this.sessionId } });
|
|
935
|
+
if (seq !== this.requestSeq) return;
|
|
936
|
+
if (result.ok) payload = result.value;
|
|
937
|
+
else transport = result.error.message;
|
|
938
|
+
} catch (error) {
|
|
939
|
+
if (seq !== this.requestSeq) return;
|
|
940
|
+
transport = error instanceof Error ? error.message : String(error);
|
|
941
|
+
}
|
|
942
|
+
this.applyOutcome(payload, transport, seq);
|
|
943
|
+
}
|
|
944
|
+
/**
|
|
945
|
+
* Pin the atomic `{provider, model}` pair for THIS session
|
|
946
|
+
* (`/api/advisor/setSessionModel`, selection = the pair). Refuses outright
|
|
947
|
+
* while `unavailable` (store-side defense-in-depth — an unavailable menu
|
|
948
|
+
* must never issue a write, and must never fall back to the global
|
|
949
|
+
* `advisor/set` channel). The host validates the pair through the same
|
|
950
|
+
* rules as the `/advisor model set` command face.
|
|
951
|
+
*/
|
|
952
|
+
async setSessionModel(provider, model) {
|
|
953
|
+
await this.write({ provider, model });
|
|
954
|
+
}
|
|
955
|
+
/**
|
|
956
|
+
* Drop the session pin and re-inherit the CURRENT global defaults
|
|
957
|
+
* (`selection: null`). Never touches the enable override; reset to a
|
|
958
|
+
* missing global pair still succeeds — the returned snapshot reports the
|
|
959
|
+
* gate-blocked/no-call state, which the menu renders truthfully.
|
|
960
|
+
*/
|
|
961
|
+
async resetSessionModel() {
|
|
962
|
+
await this.write(null);
|
|
963
|
+
}
|
|
964
|
+
/** Shared write path (both arms ride the same endpoint + fence + outcome mapping). */
|
|
965
|
+
async write(selection) {
|
|
966
|
+
if (this.store.getSnapshot().unavailable) {
|
|
967
|
+
this.store.update((s) => {
|
|
968
|
+
s.error = "advisor: the session control surface is unavailable \u2014 writes are not offered";
|
|
969
|
+
});
|
|
970
|
+
return;
|
|
971
|
+
}
|
|
972
|
+
const seq = ++this.requestSeq;
|
|
973
|
+
this.store.update((s) => {
|
|
974
|
+
s.pending = true;
|
|
975
|
+
s.error = null;
|
|
976
|
+
});
|
|
977
|
+
let payload;
|
|
978
|
+
let transport;
|
|
979
|
+
try {
|
|
980
|
+
const result = await this.rpc.call("/api", "advisor/setSessionModel", {
|
|
981
|
+
args: { sessionId: this.sessionId, selection }
|
|
982
|
+
});
|
|
983
|
+
if (seq !== this.requestSeq) return;
|
|
984
|
+
if (result.ok) payload = result.value;
|
|
985
|
+
else transport = result.error.message;
|
|
986
|
+
} catch (error) {
|
|
987
|
+
if (seq !== this.requestSeq) return;
|
|
988
|
+
transport = error instanceof Error ? error.message : String(error);
|
|
989
|
+
}
|
|
990
|
+
this.applyOutcome(payload, transport, seq);
|
|
991
|
+
}
|
|
992
|
+
/**
|
|
993
|
+
* Commit one settled outcome. Guards (seq checked by the callers before
|
|
994
|
+
* reaching here): tagged `advisor/unavailable` / `advisor/session-unknown`
|
|
995
|
+
* and transport failures latch `unavailable` (no writes offered, last good
|
|
996
|
+
* snapshot kept for context); other tagged outcomes keep the surface usable
|
|
997
|
+
* and surface the message (the host left the previous selection untouched);
|
|
998
|
+
* a snapshot commits as the new authoritative state.
|
|
999
|
+
*/
|
|
1000
|
+
applyOutcome(payload, transport, seq) {
|
|
1001
|
+
if (seq !== this.requestSeq) return;
|
|
1002
|
+
const tagged = payload?.error;
|
|
1003
|
+
if (transport !== void 0 || tagged?.tag === "advisor/unavailable" || tagged?.tag === "advisor/session-unknown") {
|
|
1004
|
+
this.store.update((s) => {
|
|
1005
|
+
s.phase = "ready";
|
|
1006
|
+
s.unavailable = true;
|
|
1007
|
+
s.pending = false;
|
|
1008
|
+
s.error = transport ?? tagged?.message ?? "advisor: the session control surface is unavailable";
|
|
1009
|
+
});
|
|
1010
|
+
return;
|
|
1011
|
+
}
|
|
1012
|
+
if (tagged !== void 0) {
|
|
1013
|
+
this.store.update((s) => {
|
|
1014
|
+
s.phase = "ready";
|
|
1015
|
+
s.pending = false;
|
|
1016
|
+
s.error = tagged.message;
|
|
1017
|
+
});
|
|
1018
|
+
return;
|
|
1019
|
+
}
|
|
1020
|
+
const snapshot = payload?.snapshot;
|
|
1021
|
+
if (snapshot === void 0) {
|
|
1022
|
+
this.store.update((s) => {
|
|
1023
|
+
s.phase = "ready";
|
|
1024
|
+
s.unavailable = true;
|
|
1025
|
+
s.pending = false;
|
|
1026
|
+
s.error = "advisor: the session endpoint returned no snapshot";
|
|
1027
|
+
});
|
|
1028
|
+
return;
|
|
1029
|
+
}
|
|
1030
|
+
this.store.update((s) => {
|
|
1031
|
+
s.phase = "ready";
|
|
1032
|
+
s.snapshot = snapshot;
|
|
1033
|
+
s.unavailable = false;
|
|
1034
|
+
s.pending = false;
|
|
1035
|
+
s.error = null;
|
|
1036
|
+
});
|
|
1037
|
+
}
|
|
1038
|
+
};
|
|
1039
|
+
|
|
1040
|
+
// src/client/index.ts
|
|
1041
|
+
var import_dsh_client_store2 = require("@deepseek-ai/dsh-client-store");
|
|
744
1042
|
|
|
745
1043
|
// src/client/locales.ts
|
|
746
1044
|
var en = {
|
|
@@ -771,7 +1069,24 @@ var en = {
|
|
|
771
1069
|
discard: "Discard",
|
|
772
1070
|
saved: "Advisor settings saved. New sessions pick them up immediately.",
|
|
773
1071
|
readOnly: "Settings are read-only in this environment.",
|
|
774
|
-
namespaceUnavailable: "The advisor configuration channel is not available yet \u2014 the settings gateway is not ready on this host. Configure the advisor via the plugin config row \u2014 `- id: advisor` whose `config:` map sets `enabled`/`provider`/`model` (e.g. `config: { enabled: true, provider: \u2026, model: \u2026 }`) in `$DSH_HOME/profiles/<name>/cordis.patch.yml`. The advisor plugin runs fully from its plugin config row; the web settings form becomes available again on the next load once the gateway is reachable. Note: `/advisor` only toggles the advisor per session; it cannot supply provider/model."
|
|
1072
|
+
namespaceUnavailable: "The advisor configuration channel is not available yet \u2014 the settings gateway is not ready on this host. Configure the advisor via the plugin config row \u2014 `- id: advisor` whose `config:` map sets `enabled`/`provider`/`model` (e.g. `config: { enabled: true, provider: \u2026, model: \u2026 }`) in `$DSH_HOME/profiles/<name>/cordis.patch.yml`. The advisor plugin runs fully from its plugin config row; the web settings form becomes available again on the next load once the gateway is reachable. Note: `/advisor` only toggles the advisor per session; it cannot supply provider/model.",
|
|
1073
|
+
// Session header action (B2): the control lives on the session header and
|
|
1074
|
+
// drives the live-session reviewer route only.
|
|
1075
|
+
sessionTrigger: "Advisor",
|
|
1076
|
+
sessionExpand: "Open the advisor controls for this session",
|
|
1077
|
+
sessionCollapse: "Close the advisor controls for this session",
|
|
1078
|
+
sessionLoading: "Loading\u2026",
|
|
1079
|
+
sessionModelHeading: "Reviewer model for this session",
|
|
1080
|
+
sessionSourceSession: "session override",
|
|
1081
|
+
sessionSourceGlobal: "global default",
|
|
1082
|
+
sessionNoPair: "No reviewer model \u2014 the global default has no provider/model.",
|
|
1083
|
+
sessionLifetime: "Lives for this session only \u2014 never persisted; cleared on dispose or restart. A new or forked session inherits the global defaults.",
|
|
1084
|
+
sessionAdvisorOff: "The advisor is off for this session.",
|
|
1085
|
+
sessionGateBlocked: "No model call can start: {reason}",
|
|
1086
|
+
sessionPinAction: "Pin this model",
|
|
1087
|
+
sessionPending: "Applying\u2026",
|
|
1088
|
+
sessionReset: "Use global default",
|
|
1089
|
+
sessionUnavailable: "The advisor session control surface is not available on this host. Use /advisor model in the session, or configure the global defaults on the Plugins page."
|
|
775
1090
|
};
|
|
776
1091
|
var zh = {
|
|
777
1092
|
title: "\u987E\u95EE",
|
|
@@ -801,16 +1116,33 @@ var zh = {
|
|
|
801
1116
|
discard: "\u653E\u5F03\u4FEE\u6539",
|
|
802
1117
|
saved: "\u987E\u95EE\u8BBE\u7F6E\u5DF2\u4FDD\u5B58\u3002\u65B0\u4F1A\u8BDD\u7ACB\u5373\u751F\u6548\u3002",
|
|
803
1118
|
readOnly: "\u5F53\u524D\u73AF\u5883\u4E2D\u7684\u8BBE\u7F6E\u4E3A\u53EA\u8BFB\u3002",
|
|
804
|
-
namespaceUnavailable: "\u987E\u95EE\u914D\u7F6E\u901A\u9053\u6682\u4E0D\u53EF\u7528\u2014\u2014\u672C\u5BBF\u4E3B\u4E0A\u7684\u8BBE\u7F6E\u7F51\u5173\u5C1A\u672A\u5C31\u7EEA\u3002\u8BF7\u901A\u8FC7\u63D2\u4EF6\u914D\u7F6E\u884C\u914D\u7F6E\u987E\u95EE\u2014\u2014\u5728 `$DSH_HOME/profiles/<name>/cordis.patch.yml` \u4E2D\u5199 `- id: advisor`\uFF0C\u5176 `config:` \u6620\u5C04\u4E2D\u8BBE\u7F6E `enabled`/`provider`/`model`\uFF08\u4F8B\u5982 `config: { enabled: true, provider: \u2026, model: \u2026 }`\uFF09\u3002\u987E\u95EE\u63D2\u4EF6\u5B8C\u5168\u901A\u8FC7\u63D2\u4EF6\u914D\u7F6E\u884C\u8FD0\u884C\uFF1B\u7F51\u5173\u53EF\u7528\u540E\uFF0Cweb \u8BBE\u7F6E\u8868\u5355\u5C06\u5728\u4E0B\u6B21\u52A0\u8F7D\u65F6\u91CD\u65B0\u663E\u793A\u3002\u6CE8\u610F\uFF1A`/advisor` \u4EC5\u5207\u6362\u5F53\u524D\u4F1A\u8BDD\u7684\u987E\u95EE\u5F00\u5173\uFF0C\u65E0\u6CD5\u63D0\u4F9B provider/model\u3002"
|
|
1119
|
+
namespaceUnavailable: "\u987E\u95EE\u914D\u7F6E\u901A\u9053\u6682\u4E0D\u53EF\u7528\u2014\u2014\u672C\u5BBF\u4E3B\u4E0A\u7684\u8BBE\u7F6E\u7F51\u5173\u5C1A\u672A\u5C31\u7EEA\u3002\u8BF7\u901A\u8FC7\u63D2\u4EF6\u914D\u7F6E\u884C\u914D\u7F6E\u987E\u95EE\u2014\u2014\u5728 `$DSH_HOME/profiles/<name>/cordis.patch.yml` \u4E2D\u5199 `- id: advisor`\uFF0C\u5176 `config:` \u6620\u5C04\u4E2D\u8BBE\u7F6E `enabled`/`provider`/`model`\uFF08\u4F8B\u5982 `config: { enabled: true, provider: \u2026, model: \u2026 }`\uFF09\u3002\u987E\u95EE\u63D2\u4EF6\u5B8C\u5168\u901A\u8FC7\u63D2\u4EF6\u914D\u7F6E\u884C\u8FD0\u884C\uFF1B\u7F51\u5173\u53EF\u7528\u540E\uFF0Cweb \u8BBE\u7F6E\u8868\u5355\u5C06\u5728\u4E0B\u6B21\u52A0\u8F7D\u65F6\u91CD\u65B0\u663E\u793A\u3002\u6CE8\u610F\uFF1A`/advisor` \u4EC5\u5207\u6362\u5F53\u524D\u4F1A\u8BDD\u7684\u987E\u95EE\u5F00\u5173\uFF0C\u65E0\u6CD5\u63D0\u4F9B provider/model\u3002",
|
|
1120
|
+
sessionTrigger: "\u987E\u95EE",
|
|
1121
|
+
sessionExpand: "\u6253\u5F00\u672C\u4F1A\u8BDD\u7684\u987E\u95EE\u63A7\u5236",
|
|
1122
|
+
sessionCollapse: "\u5173\u95ED\u672C\u4F1A\u8BDD\u7684\u987E\u95EE\u63A7\u5236",
|
|
1123
|
+
sessionLoading: "\u52A0\u8F7D\u4E2D\u2026",
|
|
1124
|
+
sessionModelHeading: "\u672C\u4F1A\u8BDD\u7684\u5BA1\u9605\u6A21\u578B",
|
|
1125
|
+
sessionSourceSession: "\u4F1A\u8BDD\u8986\u76D6",
|
|
1126
|
+
sessionSourceGlobal: "\u5168\u5C40\u9ED8\u8BA4",
|
|
1127
|
+
sessionNoPair: "\u6682\u65E0\u5BA1\u9605\u6A21\u578B\u2014\u2014\u5168\u5C40\u9ED8\u8BA4\u672A\u914D\u7F6E provider/model\u3002",
|
|
1128
|
+
sessionLifetime: "\u4EC5\u5728\u672C\u4F1A\u8BDD\u5185\u6709\u6548\u2014\u2014\u4ECE\u4E0D\u6301\u4E45\u5316\uFF1B\u4F1A\u8BDD\u9500\u6BC1\u6216\u91CD\u542F\u540E\u6E05\u9664\u3002\u65B0\u5EFA\u6216\u5206\u53C9\u7684\u4F1A\u8BDD\u7EE7\u627F\u5168\u5C40\u9ED8\u8BA4\u503C\u3002",
|
|
1129
|
+
sessionAdvisorOff: "\u672C\u4F1A\u8BDD\u7684\u987E\u95EE\u5DF2\u5173\u95ED\u3002",
|
|
1130
|
+
sessionGateBlocked: "\u65E0\u6CD5\u53D1\u8D77\u6A21\u578B\u8C03\u7528\uFF1A{reason}",
|
|
1131
|
+
sessionPinAction: "\u56FA\u5B9A\u6B64\u6A21\u578B",
|
|
1132
|
+
sessionPending: "\u5E94\u7528\u4E2D\u2026",
|
|
1133
|
+
sessionReset: "\u4F7F\u7528\u5168\u5C40\u9ED8\u8BA4",
|
|
1134
|
+
sessionUnavailable: "\u672C\u5BBF\u4E3B\u4E0A\u7684\u987E\u95EE\u4F1A\u8BDD\u63A7\u5236\u9762\u4E0D\u53EF\u7528\u3002\u8BF7\u5728\u4F1A\u8BDD\u4E2D\u4F7F\u7528 /advisor model\uFF0C\u6216\u5728 Plugins \u9875\u914D\u7F6E\u5168\u5C40\u9ED8\u8BA4\u503C\u3002"
|
|
805
1135
|
};
|
|
806
1136
|
|
|
807
1137
|
// src/client/index.ts
|
|
808
1138
|
var NS = "settings.advisor";
|
|
1139
|
+
var BUNDLE_NAME = "dsh-advisor";
|
|
809
1140
|
var inject = ["slots", "locale", "connection", "settingsSchema", "remote", "remote.llm", "remote.settings", "remote.session"];
|
|
810
1141
|
function apply(ctx) {
|
|
811
1142
|
ctx.effect(() => ctx.locale.register(NS, { zh, en }), "advisor: copy dictionaries");
|
|
812
1143
|
const connection = ctx.get("connection");
|
|
813
1144
|
const controller = new AdvisorSettingsStore(ctx.remote, connection.rpc, ctx.settingsSchema);
|
|
1145
|
+
const refreshSignal = (0, import_dsh_client_store2.createSnapshotStore)({ epoch: 0 });
|
|
814
1146
|
ctx.effect(() => {
|
|
815
1147
|
let pending = false;
|
|
816
1148
|
const refresh = () => {
|
|
@@ -819,25 +1151,30 @@ function apply(ctx) {
|
|
|
819
1151
|
queueMicrotask(() => {
|
|
820
1152
|
pending = false;
|
|
821
1153
|
refreshIfLoaded(controller);
|
|
1154
|
+
refreshSignal.update((signal) => {
|
|
1155
|
+
signal.epoch += 1;
|
|
1156
|
+
});
|
|
822
1157
|
});
|
|
823
1158
|
};
|
|
824
1159
|
const disposers = [ctx.on("connection/reset", refresh)];
|
|
825
1160
|
disposers.push(ctx.remote.$on("settings/document-updated", refresh));
|
|
826
1161
|
disposers.push(ctx.remote.$on("llm/adapters-updated", refresh));
|
|
1162
|
+
const onFocus = () => {
|
|
1163
|
+
refresh();
|
|
1164
|
+
};
|
|
1165
|
+
window.addEventListener("focus", onFocus);
|
|
827
1166
|
return () => {
|
|
1167
|
+
window.removeEventListener("focus", onFocus);
|
|
828
1168
|
for (const dispose of disposers) dispose();
|
|
829
1169
|
};
|
|
830
1170
|
}, "advisor: pushed invalidations");
|
|
831
|
-
ctx.slots.inject("
|
|
1171
|
+
ctx.slots.inject("plugins.bundle.config", function* () {
|
|
832
1172
|
yield ctx.slots.register({
|
|
833
|
-
name: "
|
|
834
|
-
// Keyed slot: the key is the
|
|
835
|
-
//
|
|
836
|
-
//
|
|
837
|
-
|
|
838
|
-
// entries declare no `id`/`order` — appearance order is registration
|
|
839
|
-
// order, which still places this card after the upstream three.
|
|
840
|
-
key: "advisor",
|
|
1173
|
+
name: "plugins.bundle.config",
|
|
1174
|
+
// Keyed slot: the key is the bundle package name the page dispatches
|
|
1175
|
+
// (`entryKey = pkg.name` in ui-plugin-manager's PackageDetail). Keyed
|
|
1176
|
+
// entries declare no `id`/`order` — there is one entry per bundle page.
|
|
1177
|
+
key: BUNDLE_NAME,
|
|
841
1178
|
locale: NS,
|
|
842
1179
|
// Hooks compartment: the renderer binds `hooks.snapshot` to the
|
|
843
1180
|
// component's `useSnapshot` selector hook (the old web-react
|
|
@@ -845,5 +1182,29 @@ function apply(ctx) {
|
|
|
845
1182
|
inject: () => ({ controller, hooks: { snapshot: controller.store } })
|
|
846
1183
|
}, AdvisorCard);
|
|
847
1184
|
});
|
|
1185
|
+
ctx.slots.inject("conversation.session.header.actions", function* () {
|
|
1186
|
+
yield ctx.slots.register({
|
|
1187
|
+
name: "conversation.session.header.actions",
|
|
1188
|
+
// List slot: one cell per `id` — this bundle contributes exactly one
|
|
1189
|
+
// action; default order keeps registration sequencing.
|
|
1190
|
+
id: BUNDLE_NAME,
|
|
1191
|
+
locale: NS,
|
|
1192
|
+
inject: (sessionId) => {
|
|
1193
|
+
const sessionController = new AdvisorSessionModelController(sessionId, connection.rpc);
|
|
1194
|
+
return {
|
|
1195
|
+
sessionId,
|
|
1196
|
+
controller: sessionController,
|
|
1197
|
+
// READ-only directory reuse: provider/model options come from the
|
|
1198
|
+
// global card's store; the session surface never writes through it.
|
|
1199
|
+
directory: controller,
|
|
1200
|
+
hooks: {
|
|
1201
|
+
snapshot: sessionController.store,
|
|
1202
|
+
refreshSignal,
|
|
1203
|
+
directory: controller.store
|
|
1204
|
+
}
|
|
1205
|
+
};
|
|
1206
|
+
}
|
|
1207
|
+
}, AdvisorSessionAction);
|
|
1208
|
+
});
|
|
848
1209
|
}
|
|
849
1210
|
return module.exports; } });
|