@qilin-agent/client-ui-settings-plugins 3.1.4 → 3.1.6

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 CHANGED
@@ -36,8 +36,8 @@
36
36
  en: 8e21487b8251d057
37
37
  zh: 9679617bac069cd3
38
38
  /qilin-agent-client-ui-settings-plugins/further-exploration:
39
- en: dd6103dffd4af94a
40
- zh: dd7e1dbffaf1aa5a
39
+ en: a9aea28be1bad3d8
40
+ zh: 5318cda666425a89
41
41
  /qilin-agent-client-ui-settings-plugins/model-experience:
42
42
  en: 6b7c6f82ab6c8435
43
43
  zh: 3328550d96a6368b
package/README.md CHANGED
@@ -72,7 +72,7 @@ Saving writes staged fields through the client configuration form, which fences
72
72
 
73
73
  These pages cover the Plugins page, the settings base, the inventory tab, and the durable seams behind the forms.
74
74
 
75
- - [ui-plugin-manager](../ui-plugin-manager/README.md) — the section's management tab, whose `plugins.item`, `plugins.bundle.config`, and `plugins.row.config` slots host configuration pages.
75
+ - [ui-plugin-manager](../ui-plugin-manager/README.md) — the Plugins page where official plugins are configured.
76
76
  - [ui-settings](../ui-settings/README.md) — the domain base declaring `settings.section` and the shared configuration forms.
77
77
  - [ui-settings-plugin-inventory](../ui-settings-plugin-inventory/README.md) — the read-only inventory the section shows.
78
78
  - [settings](../../settings/README.md) — the durable user-settings seam and its file provider.
package/README.zh.md CHANGED
@@ -72,7 +72,7 @@ kind: "package-reference"
72
72
 
73
73
  以下页面覆盖插件页、设置底座、清单标签页与表单背后的持久化 seam。
74
74
 
75
- - [ui-plugin-manager](../ui-plugin-manager/README.zh.md)——分区的「插件管理」标签页,其 `plugins.item`、`plugins.bundle.config` 与 `plugins.row.config` slot 承载配置页。
75
+ - [ui-plugin-manager](../ui-plugin-manager/README.zh.md)——配置官方插件的插件页。
76
76
  - [ui-settings](../ui-settings/README.zh.md)——声明 `settings.section` 与共享配置表单的领域底座。
77
77
  - [ui-settings-plugin-inventory](../ui-settings-plugin-inventory/README.zh.md)——分区显示的只读插件列表。
78
78
  - [settings](../../settings/README.zh.md)——持久化用户设置 seam 及其文件提供方。
package/lib/client.js CHANGED
@@ -10,13 +10,13 @@ window.__ModuleLoader__.load({
10
10
  let react = require("react");
11
11
  let _qilin_agent_client_store = require("@qilin-agent/client-store");
12
12
  //#region \0qilin-css:/home/runner/work/QiLin/QiLin/packages/client/ui-settings-plugins/src/client/PluginConfigForm.module.css.mjs
13
- const css$4 = ".PuF0xa_form{flex-direction:column;display:flex}.PuF0xa_readOnly,.PuF0xa_unavailable{color:var(--qilin-alias-label-tertiary);margin:0 0 12px;font-size:12px;line-height:1.5}.PuF0xa_footer{align-items:center;gap:8px;padding-top:16px;display:flex}.PuF0xa_failed{min-width:0;color:var(--qilin-alias-label-error);flex:1;margin:0;font-size:12px;line-height:1.5}.PuF0xa_save{appearance:none;font:inherit;cursor:pointer;background:var(--qilin-alias-label-primary);color:var(--qilin-alias-bg-layer-3);border:1px solid #0000;border-radius:8px;padding:5px 14px;font-size:13px;line-height:1.5}.PuF0xa_save:disabled{opacity:.4;cursor:default}.PuF0xa_save:focus-visible{outline:var(--qilin-focus-ring-width) solid var(--qilin-focus-ring-color,var(--qilin-alias-state-business-primary));outline-offset:1px}";
14
- const tagId$4 = "@qilin-agent/client-ui-settings-plugins/PluginConfigForm.module.css";
15
- if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$4) + "]") === null) {
13
+ const css$5 = ".PuF0xa_form{flex-direction:column;display:flex}.PuF0xa_readOnly,.PuF0xa_unavailable{color:var(--qilin-alias-label-tertiary);margin:0 0 12px;font-size:12px;line-height:1.5}.PuF0xa_footer{align-items:center;gap:8px;padding-top:16px;display:flex}.PuF0xa_failed{min-width:0;color:var(--qilin-alias-label-error);flex:1;margin:0;font-size:12px;line-height:1.5}.PuF0xa_save{appearance:none;font:inherit;cursor:pointer;background:var(--qilin-alias-label-primary);color:var(--qilin-alias-bg-layer-3);border:1px solid #0000;border-radius:8px;padding:5px 14px;font-size:13px;line-height:1.5}.PuF0xa_save:disabled{opacity:.4;cursor:default}.PuF0xa_save:focus-visible{outline:var(--qilin-focus-ring-width) solid var(--qilin-focus-ring-color,var(--qilin-alias-state-business-primary));outline-offset:1px}";
14
+ const tagId$5 = "@qilin-agent/client-ui-settings-plugins/PluginConfigForm.module.css";
15
+ if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$5) + "]") === null) {
16
16
  const tag = document.createElement("style");
17
17
  tag.dataset.plugin = "@qilin-agent/client-ui-settings-plugins";
18
- tag.dataset.pluginCss = tagId$4;
19
- tag.textContent = css$4;
18
+ tag.dataset.pluginCss = tagId$5;
19
+ tag.textContent = css$5;
20
20
  document.head.appendChild(tag);
21
21
  }
22
22
  var PluginConfigForm_module_css_default = {
@@ -173,13 +173,13 @@ window.__ModuleLoader__.load({
173
173
  }
174
174
  //#endregion
175
175
  //#region \0qilin-css:/home/runner/work/QiLin/QiLin/packages/client/ui-settings-plugins/src/client/PluginsSettingsSection.module.css.mjs
176
- const css$3 = "._2gTzQa_section{color:var(--qilin-alias-label-primary);flex-direction:column;gap:12px;display:flex}._2gTzQa_heading{margin:0;font-size:18px;font-weight:600}._2gTzQa_intro{color:var(--qilin-alias-label-tertiary);margin:0;font-size:13px}._2gTzQa_tabs{border-bottom:.5px solid var(--qilin-alias-border-l2);align-items:flex-end;gap:22px;margin-top:2px;display:flex}._2gTzQa_tab{color:var(--qilin-alias-label-tertiary);font:inherit;cursor:pointer;background:0 0;border:0;padding:7px 1px 9px;font-size:13px;line-height:20px;position:relative}._2gTzQa_tab:hover,._2gTzQa_tab[data-active=true]{color:var(--qilin-alias-label-primary)}._2gTzQa_tab[data-active=true]:after,._2gTzQa_tab:focus-visible:after{background:var(--qilin-alias-label-primary);content:\"\";border-radius:2px 2px 0 0;height:2px;position:absolute;bottom:-1px;left:0;right:0}._2gTzQa_tab:focus-visible{outline:var(--qilin-focus-ring-width) solid var(--qilin-focus-ring-color,var(--qilin-alias-state-business-primary));outline-offset:2px;color:var(--qilin-alias-label-primary);border-radius:2px}._2gTzQa_panel{min-width:0;padding-top:2px}._2gTzQa_cards{flex-direction:column;gap:10px;margin:0;padding:0;list-style:none;display:flex}._2gTzQa_empty{color:var(--qilin-alias-label-tertiary);margin:0;font-size:13px}._2gTzQa_configurable{flex-direction:column;gap:10px;display:flex}._2gTzQa_presetSettings{flex-direction:column;gap:8px;display:flex}._2gTzQa_presetSettingsTitle{margin:0;font-size:15px;font-weight:600;line-height:22px}";
177
- const tagId$3 = "@qilin-agent/client-ui-settings-plugins/PluginsSettingsSection.module.css";
178
- if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$3) + "]") === null) {
176
+ const css$4 = "._2gTzQa_section{color:var(--qilin-alias-label-primary);flex-direction:column;gap:12px;display:flex}._2gTzQa_heading{margin:0;font-size:18px;font-weight:600}._2gTzQa_intro{color:var(--qilin-alias-label-tertiary);margin:0;font-size:13px}._2gTzQa_tabs{border-bottom:.5px solid var(--qilin-alias-border-l2);align-items:flex-end;gap:22px;margin-top:2px;display:flex}._2gTzQa_tab{color:var(--qilin-alias-label-tertiary);font:inherit;cursor:pointer;background:0 0;border:0;padding:7px 1px 9px;font-size:13px;line-height:20px;position:relative}._2gTzQa_tab:hover,._2gTzQa_tab[data-active=true]{color:var(--qilin-alias-label-primary)}._2gTzQa_tab[data-active=true]:after,._2gTzQa_tab:focus-visible:after{background:var(--qilin-alias-label-primary);content:\"\";border-radius:2px 2px 0 0;height:2px;position:absolute;bottom:-1px;left:0;right:0}._2gTzQa_tab:focus-visible{outline:var(--qilin-focus-ring-width) solid var(--qilin-focus-ring-color,var(--qilin-alias-state-business-primary));outline-offset:2px;color:var(--qilin-alias-label-primary);border-radius:2px}._2gTzQa_panel{min-width:0;padding-top:2px}._2gTzQa_cards{flex-direction:column;gap:10px;margin:0;padding:0;list-style:none;display:flex}._2gTzQa_empty{color:var(--qilin-alias-label-tertiary);margin:0;font-size:13px}._2gTzQa_configurable{flex-direction:column;gap:10px;display:flex}._2gTzQa_presetSettings{flex-direction:column;gap:8px;display:flex}._2gTzQa_presetSettingsTitle{margin:0;font-size:15px;font-weight:600;line-height:22px}";
177
+ const tagId$4 = "@qilin-agent/client-ui-settings-plugins/PluginsSettingsSection.module.css";
178
+ if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$4) + "]") === null) {
179
179
  const tag = document.createElement("style");
180
180
  tag.dataset.plugin = "@qilin-agent/client-ui-settings-plugins";
181
- tag.dataset.pluginCss = tagId$3;
182
- tag.textContent = css$3;
181
+ tag.dataset.pluginCss = tagId$4;
182
+ tag.textContent = css$4;
183
183
  document.head.appendChild(tag);
184
184
  }
185
185
  var PluginsSettingsSection_module_css_default = {
@@ -294,13 +294,13 @@ window.__ModuleLoader__.load({
294
294
  }
295
295
  //#endregion
296
296
  //#region \0qilin-css:/home/runner/work/QiLin/QiLin/packages/client/ui-settings-plugins/src/client/SubagentLimitsFields.module.css.mjs
297
- const css$2 = ".ilBR6W_limits{grid-template-columns:repeat(auto-fit,minmax(min(220px,100%),1fr));gap:16px;display:grid}.ilBR6W_limit{min-width:0}.ilBR6W_limit input{font-variant-numeric:tabular-nums;min-width:0}.ilBR6W_depthTable{border-collapse:collapse;border-block:.5px solid var(--qilin-alias-border-l2);width:100%;font:inherit;text-align:left;margin:8px 0}.ilBR6W_depthTable th,.ilBR6W_depthTable td{vertical-align:top;padding:6px 0}.ilBR6W_depthTable th{font-variant-numeric:tabular-nums;width:24px;color:var(--qilin-alias-label-primary);padding-right:8px;font-weight:500}.ilBR6W_depthTable tr+tr{border-top:.5px solid var(--qilin-alias-border-l2)}";
298
- const tagId$2 = "@qilin-agent/client-ui-settings-plugins/SubagentLimitsFields.module.css";
299
- if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$2) + "]") === null) {
297
+ const css$3 = ".ilBR6W_limits{grid-template-columns:repeat(auto-fit,minmax(min(220px,100%),1fr));gap:16px;display:grid}.ilBR6W_limit{min-width:0}.ilBR6W_limit input{font-variant-numeric:tabular-nums;min-width:0}.ilBR6W_depthTable{border-collapse:collapse;border-block:.5px solid var(--qilin-alias-border-l2);width:100%;font:inherit;text-align:left;margin:8px 0}.ilBR6W_depthTable th,.ilBR6W_depthTable td{vertical-align:top;padding:6px 0}.ilBR6W_depthTable th{font-variant-numeric:tabular-nums;width:24px;color:var(--qilin-alias-label-primary);padding-right:8px;font-weight:500}.ilBR6W_depthTable tr+tr{border-top:.5px solid var(--qilin-alias-border-l2)}";
298
+ const tagId$3 = "@qilin-agent/client-ui-settings-plugins/SubagentLimitsFields.module.css";
299
+ if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$3) + "]") === null) {
300
300
  const tag = document.createElement("style");
301
301
  tag.dataset.plugin = "@qilin-agent/client-ui-settings-plugins";
302
- tag.dataset.pluginCss = tagId$2;
303
- tag.textContent = css$2;
302
+ tag.dataset.pluginCss = tagId$3;
303
+ tag.textContent = css$3;
304
304
  document.head.appendChild(tag);
305
305
  }
306
306
  var SubagentLimitsFields_module_css_default = {
@@ -382,13 +382,13 @@ window.__ModuleLoader__.load({
382
382
  }
383
383
  //#endregion
384
384
  //#region \0qilin-css:/home/runner/work/QiLin/QiLin/packages/client/ui-settings-plugins/src/client/SubagentModelSelectionFields.module.css.mjs
385
- const css$1 = ".USzyAq_permission{gap:6px;padding:12px 0;display:grid}.USzyAq_toggleRow{color:var(--qilin-alias-label-primary);justify-content:space-between;align-items:flex-start;gap:16px;font-size:13px;line-height:1.5;display:flex}.USzyAq_toggleLabel{flex:1;min-width:0}.USzyAq_selection{gap:10px;display:grid}.USzyAq_hint,.USzyAq_notice,.USzyAq_invalid,.USzyAq_conflict{margin:0;font-size:12px;line-height:1.5}.USzyAq_hint,.USzyAq_notice{color:var(--qilin-alias-label-tertiary)}.USzyAq_invalid,.USzyAq_conflict{color:var(--qilin-alias-state-error-primary)}.USzyAq_catalogError{color:var(--qilin-alias-state-error-primary);justify-content:space-between;align-items:center;gap:12px;font-size:12px;display:flex}.USzyAq_catalogError button{color:var(--qilin-alias-brand-primary);cursor:pointer;background:0 0;border:0;padding:0}.USzyAq_models{border:.5px solid var(--qilin-alias-border-l4);border-radius:8px;gap:6px;min-width:0;max-height:280px;margin:0;padding:10px;display:grid;overflow:auto}.USzyAq_models legend{color:var(--qilin-alias-label-secondary);padding:0 4px;font-size:12px}.USzyAq_modelGroup{gap:6px;display:grid}.USzyAq_modelGroup+.USzyAq_modelGroup{border-top:.5px solid var(--qilin-alias-border-l3);margin-top:4px;padding-top:10px}.USzyAq_providerName{color:var(--qilin-alias-label-tertiary);padding:0 6px;font-size:11px;font-weight:500}.USzyAq_model{cursor:pointer;border-radius:6px;grid-template-columns:auto minmax(0,1fr) auto;align-items:center;gap:8px;min-width:0;padding:6px;display:grid}.USzyAq_model:hover{background:var(--qilin-alias-bg-layer-4)}.USzyAq_modelName,.USzyAq_route{text-overflow:ellipsis;white-space:nowrap;display:block;overflow:hidden}.USzyAq_modelName{color:var(--qilin-alias-label-primary);font-size:13px}.USzyAq_route{color:var(--qilin-alias-label-tertiary);margin-top:2px;font-size:11px}.USzyAq_unavailable{color:var(--qilin-alias-label-tertiary);font-size:11px}";
386
- const tagId$1 = "@qilin-agent/client-ui-settings-plugins/SubagentModelSelectionFields.module.css";
387
- if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$1) + "]") === null) {
385
+ const css$2 = ".USzyAq_permission{gap:6px;padding:12px 0;display:grid}.USzyAq_toggleRow{color:var(--qilin-alias-label-primary);justify-content:space-between;align-items:flex-start;gap:16px;font-size:13px;line-height:1.5;display:flex}.USzyAq_toggleLabel{flex:1;min-width:0}.USzyAq_selection{gap:10px;display:grid}.USzyAq_hint,.USzyAq_notice,.USzyAq_invalid,.USzyAq_conflict{margin:0;font-size:12px;line-height:1.5}.USzyAq_hint,.USzyAq_notice{color:var(--qilin-alias-label-tertiary)}.USzyAq_invalid,.USzyAq_conflict{color:var(--qilin-alias-state-error-primary)}.USzyAq_catalogError{color:var(--qilin-alias-state-error-primary);justify-content:space-between;align-items:center;gap:12px;font-size:12px;display:flex}.USzyAq_catalogError button{color:var(--qilin-alias-brand-primary);cursor:pointer;background:0 0;border:0;padding:0}.USzyAq_models{border:.5px solid var(--qilin-alias-border-l4);border-radius:8px;gap:6px;min-width:0;max-height:280px;margin:0;padding:10px;display:grid;overflow:auto}.USzyAq_models legend{color:var(--qilin-alias-label-secondary);padding:0 4px;font-size:12px}.USzyAq_modelGroup{gap:6px;display:grid}.USzyAq_modelGroup+.USzyAq_modelGroup{border-top:.5px solid var(--qilin-alias-border-l3);margin-top:4px;padding-top:10px}.USzyAq_providerName{color:var(--qilin-alias-label-tertiary);padding:0 6px;font-size:11px;font-weight:500}.USzyAq_model{cursor:pointer;border-radius:6px;grid-template-columns:auto minmax(0,1fr) auto;align-items:center;gap:8px;min-width:0;padding:6px;display:grid}.USzyAq_model:hover{background:var(--qilin-alias-bg-layer-4)}.USzyAq_modelName,.USzyAq_route{text-overflow:ellipsis;white-space:nowrap;display:block;overflow:hidden}.USzyAq_modelName{color:var(--qilin-alias-label-primary);font-size:13px}.USzyAq_route{color:var(--qilin-alias-label-tertiary);margin-top:2px;font-size:11px}.USzyAq_unavailable{color:var(--qilin-alias-label-tertiary);font-size:11px}";
386
+ const tagId$2 = "@qilin-agent/client-ui-settings-plugins/SubagentModelSelectionFields.module.css";
387
+ if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$2) + "]") === null) {
388
388
  const tag = document.createElement("style");
389
389
  tag.dataset.plugin = "@qilin-agent/client-ui-settings-plugins";
390
- tag.dataset.pluginCss = tagId$1;
391
- tag.textContent = css$1;
390
+ tag.dataset.pluginCss = tagId$2;
391
+ tag.textContent = css$2;
392
392
  document.head.appendChild(tag);
393
393
  }
394
394
  var SubagentModelSelectionFields_module_css_default = {
@@ -588,13 +588,13 @@ window.__ModuleLoader__.load({
588
588
  }
589
589
  //#endregion
590
590
  //#region \0qilin-css:/home/runner/work/QiLin/QiLin/packages/client/ui-settings-plugins/src/client/SubagentCard.module.css.mjs
591
- const css = ".NLp0wG_section{min-width:0;padding:16px 0}.NLp0wG_heading{color:var(--qilin-alias-label-primary);margin:0;font-size:13px;font-weight:600;line-height:1.5}";
592
- const tagId = "@qilin-agent/client-ui-settings-plugins/SubagentCard.module.css";
593
- if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
591
+ const css$1 = ".NLp0wG_section{min-width:0;padding:16px 0}.NLp0wG_heading{color:var(--qilin-alias-label-primary);margin:0;font-size:13px;font-weight:600;line-height:1.5}";
592
+ const tagId$1 = "@qilin-agent/client-ui-settings-plugins/SubagentCard.module.css";
593
+ if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$1) + "]") === null) {
594
594
  const tag = document.createElement("style");
595
595
  tag.dataset.plugin = "@qilin-agent/client-ui-settings-plugins";
596
- tag.dataset.pluginCss = tagId;
597
- tag.textContent = css;
596
+ tag.dataset.pluginCss = tagId$1;
597
+ tag.textContent = css$1;
598
598
  document.head.appendChild(tag);
599
599
  }
600
600
  var SubagentCard_module_css_default = {
@@ -834,6 +834,23 @@ window.__ModuleLoader__.load({
834
834
  });
835
835
  }
836
836
  //#endregion
837
+ //#region \0qilin-css:/home/runner/work/QiLin/QiLin/packages/client/ui-settings-plugins/src/client/WebSearchCard.module.css.mjs
838
+ const css = ".zhjlca_feature{gap:6px;display:grid}.zhjlca_toggleRow{color:var(--qilin-alias-label-primary);justify-content:space-between;align-items:flex-start;gap:16px;font-size:13px;line-height:1.5;display:flex}.zhjlca_hint{color:var(--qilin-alias-label-tertiary);margin:0;font-size:12px;line-height:1.5}.zhjlca_link{color:var(--qilin-alias-link);text-decoration:none}.zhjlca_link:hover{text-decoration:underline}";
839
+ const tagId = "@qilin-agent/client-ui-settings-plugins/WebSearchCard.module.css";
840
+ if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
841
+ const tag = document.createElement("style");
842
+ tag.dataset.plugin = "@qilin-agent/client-ui-settings-plugins";
843
+ tag.dataset.pluginCss = tagId;
844
+ tag.textContent = css;
845
+ document.head.appendChild(tag);
846
+ }
847
+ var WebSearchCard_module_css_default = {
848
+ "feature": "zhjlca_feature",
849
+ "hint": "zhjlca_hint",
850
+ "link": "zhjlca_link",
851
+ "toggleRow": "zhjlca_toggleRow"
852
+ };
853
+ //#endregion
837
854
  //#region lib/types/client/WebSearchCard.js
838
855
  /**
839
856
  * Render the web-search provider's one-liner or its configuration form, as the Plugins page asks.
@@ -844,13 +861,38 @@ window.__ModuleLoader__.load({
844
861
  const { t } = props;
845
862
  const state = props.useWebSearchCard((snapshot) => snapshot);
846
863
  if (props.view === "summary") return t("webSearchDescription");
847
- const disabled = !state.writable;
864
+ const disabled = !state.writable || state.saving;
865
+ const searchApi = state.useSearchApi;
866
+ const limitField = searchApi ? "count" : "maxUses";
848
867
  return (0, react_jsx_runtime.jsxs)(PluginConfigForm, {
849
868
  t,
850
869
  state,
851
870
  onSave: props.save,
852
871
  onDiscard: props.discard,
853
872
  children: [
873
+ state.apiSwitchAvailable && (0, react_jsx_runtime.jsxs)("div", {
874
+ className: WebSearchCard_module_css_default.feature,
875
+ children: [(0, react_jsx_runtime.jsxs)("label", {
876
+ className: WebSearchCard_module_css_default.toggleRow,
877
+ children: [(0, react_jsx_runtime.jsx)("span", { children: t("webSearchUseApi") }), (0, react_jsx_runtime.jsx)(_qilin_agent_client_ui_primitives.Switch, {
878
+ checked: searchApi,
879
+ label: t("webSearchUseApi"),
880
+ disabled: disabled || state.apiSwitchBlocked,
881
+ onChange: (checked) => {
882
+ props.setSearchApi(checked);
883
+ }
884
+ })]
885
+ }), (0, react_jsx_runtime.jsxs)("p", {
886
+ className: WebSearchCard_module_css_default.hint,
887
+ children: [t("webSearchUseApiHint"), (0, react_jsx_runtime.jsx)("a", {
888
+ className: WebSearchCard_module_css_default.link,
889
+ href: t("webSearchGuideUrl"),
890
+ target: "_blank",
891
+ rel: "noopener noreferrer",
892
+ children: t("webSearchGuide")
893
+ })]
894
+ })]
895
+ }),
854
896
  (0, react_jsx_runtime.jsx)(_qilin_agent_client_ui_primitives.SettingsSecretField, {
855
897
  id: "plugin-config-web-search-key",
856
898
  label: t("webSearchApiKey"),
@@ -865,8 +907,8 @@ window.__ModuleLoader__.load({
865
907
  }),
866
908
  (0, react_jsx_runtime.jsx)(_qilin_agent_client_ui_primitives.SettingsValueField, {
867
909
  id: "plugin-config-web-search-endpoint",
868
- label: t("webSearchBaseUrl"),
869
- hint: t("webSearchBaseUrlHint"),
910
+ label: t(searchApi ? "webSearchSearchApiBaseUrl" : "webSearchBaseUrl"),
911
+ hint: t(searchApi ? "webSearchSearchApiBaseUrlHint" : "webSearchBaseUrlHint"),
870
912
  overriddenLabel: t("overridden"),
871
913
  resetLabel: t("reset"),
872
914
  invalidLabel: t("invalidNumber"),
@@ -880,20 +922,20 @@ window.__ModuleLoader__.load({
880
922
  }
881
923
  }),
882
924
  (0, react_jsx_runtime.jsx)(_qilin_agent_client_ui_primitives.SettingsValueField, {
883
- id: "plugin-config-web-search-max-uses",
884
- label: t("webSearchMaxUses"),
885
- hint: t("webSearchMaxUsesHint"),
925
+ id: searchApi ? "plugin-config-web-search-count" : "plugin-config-web-search-max-uses",
926
+ label: t(limitField === "count" ? "webSearchCount" : "webSearchMaxUses"),
927
+ hint: t(searchApi ? "webSearchCountHint" : "webSearchMaxUsesHint"),
886
928
  overriddenLabel: t("overridden"),
887
929
  resetLabel: t("reset"),
888
- invalidLabel: t("invalidNumber"),
930
+ invalidLabel: t(searchApi ? "webSearchInvalidCount" : "invalidNumber"),
889
931
  numeric: true,
890
932
  disabled,
891
- ...state.maxUses,
933
+ ...state[limitField],
892
934
  onEdit: (text) => {
893
- props.edit("maxUses", text);
935
+ props.edit(limitField, text);
894
936
  },
895
937
  onReset: () => {
896
- props.resetField("maxUses");
938
+ props.resetField(limitField);
897
939
  }
898
940
  })
899
941
  ]
@@ -941,7 +983,7 @@ window.__ModuleLoader__.load({
941
983
  * client package must not depend on a Host package, and the executor families
942
984
  * that own it spell the same value.
943
985
  */
944
- const SHELL_NS = "shell";
986
+ const SHELL_NS = "bash-sandbox";
945
987
  /** Bridges the `bash` scope onto the shell card's staged form. */
946
988
  var BashCardController = class {
947
989
  form;
@@ -1024,7 +1066,7 @@ window.__ModuleLoader__.load({
1024
1066
  //#region lib/types/client/subagent-model-selection-card-controller.js
1025
1067
  /** Staged editor for the Host-owned subagent model allowlist. */
1026
1068
  /** Namespace of the Host-owned subagent model-selection preference. */
1027
- const SUBAGENT_MODEL_SELECTION_NS = "subagent-model-selection";
1069
+ const SUBAGENT_MODEL_SELECTION_NS = "subagent-model-selection-settings";
1028
1070
  /**
1029
1071
  * Stable identity for one exact route; callers resolve it by lookup and never parse it.
1030
1072
  * @param route - Provider/model route to identify.
@@ -1298,73 +1340,149 @@ window.__ModuleLoader__.load({
1298
1340
  //#endregion
1299
1341
  //#region lib/types/client/web-search-card-controller.js
1300
1342
  /**
1301
- * The web-search card's staged form over the `web-search-deepseek` settings
1302
- * namespace.
1343
+ * The web-search page's staged form over three settings namespaces: `web`,
1344
+ * whose provider selection the Search API switch writes, `web-search-deepseek`
1345
+ * for Messages search, and `web-deepseek-api` for the Search and Fetch APIs.
1346
+ *
1347
+ * The switch selects `deepseek-search-api` and `deepseek-fetch-api` together, or
1348
+ * Messages search with local HTTP fetch. A selection equal to the deployment's
1349
+ * composed value clears the override instead of storing a copy of it.
1303
1350
  *
1304
- * The key is the one control that does not live in the section: its literal
1305
- * never rides a response, so the card learns only whether one is configured
1351
+ * The key is the one control that does not live in a section: its literal
1352
+ * never rides a response, so the page learns only whether one is configured
1306
1353
  * and writes it through the credentials domain, addressed by the reference the
1307
- * section names. It is still staged with the rest of the form, so one save
1308
- * covers everything the card shows.
1354
+ * selected API's section names. It is still staged with the rest of the form,
1355
+ * so one save covers everything the page shows.
1309
1356
  */
1310
1357
  /**
1311
- * Namespace of the DeepSeek search provider. Spelled here rather than
1358
+ * Namespace of the DeepSeek Messages search provider. Spelled here rather than
1312
1359
  * imported: a client package must not depend on a Host package.
1313
1360
  */
1314
1361
  const WEB_SEARCH_NS = "web-search-deepseek";
1315
- /** Credential reference the provider resolves when the section names none. */
1362
+ /** Namespace of the DeepSeek Search and Fetch API providers. */
1363
+ const WEB_API_NS = "web-deepseek-api";
1364
+ /** Provider ids the switch writes into the web service's selection. */
1365
+ const PROVIDERS = {
1366
+ searchProvider: {
1367
+ api: "deepseek-search-api",
1368
+ messages: "deepseek-official"
1369
+ },
1370
+ fetchProvider: {
1371
+ api: "deepseek-fetch-api",
1372
+ messages: "http"
1373
+ }
1374
+ };
1375
+ /** Credential reference the providers resolve when a section names none. */
1316
1376
  const DEFAULT_API_KEY_REF = "DEEPSEEK_API_KEY";
1317
1377
  /** Form field the credential control stages under. */
1318
1378
  const API_KEY_FIELD = "apiKey";
1319
- /** Bridges the `web-search-deepseek` scope and the credentials domain onto the card. */
1379
+ /** Bridges the three settings scopes and the credentials domain onto the page. */
1320
1380
  var WebSearchCardController = class {
1321
- scope;
1381
+ scopes;
1322
1382
  ctx;
1323
- form;
1383
+ selection;
1384
+ messages;
1385
+ api;
1324
1386
  store;
1387
+ unsubscribe;
1325
1388
  credential = {
1326
1389
  ref: "",
1327
1390
  configured: false,
1328
1391
  writable: true
1329
1392
  };
1330
1393
  /**
1331
- * @param scope - the bound settings scope for the `web-search-deepseek` namespace.
1332
- * @param ctx - the card plugin's context, whose `remote.credentials` namespace
1333
- * answers for the credential the section references.
1394
+ * @param scopes - the bound settings scopes for the page's namespaces.
1395
+ * @param ctx - the page plugin's context, whose `remote.credentials` namespace
1396
+ * answers for the credential the selected section references.
1334
1397
  */
1335
- constructor(scope, ctx) {
1336
- this.scope = scope;
1398
+ constructor(scopes, ctx) {
1399
+ this.scopes = scopes;
1337
1400
  this.ctx = ctx;
1338
- this.form = new _qilin_agent_client_ui_primitives.SettingsFormModel(scope, [(0, _qilin_agent_client_ui_primitives.settingsTextField)("baseURL"), (0, _qilin_agent_client_ui_primitives.settingsNumberField)("maxUses")], [{
1401
+ this.selection = new _qilin_agent_client_ui_primitives.SettingsFormModel(scopes.web, [(0, _qilin_agent_client_ui_primitives.settingsTextField)("searchProvider"), (0, _qilin_agent_client_ui_primitives.settingsTextField)("fetchProvider")], [{
1339
1402
  field: API_KEY_FIELD,
1340
1403
  write: (text) => this.writeKey(text)
1341
1404
  }]);
1342
- this.store = this.form.bind(() => this.projection());
1343
- scope.subscribe(() => {
1405
+ this.messages = new _qilin_agent_client_ui_primitives.SettingsFormModel(scopes.messages, [(0, _qilin_agent_client_ui_primitives.settingsTextField)("baseURL"), (0, _qilin_agent_client_ui_primitives.settingsNumberField)("maxUses")]);
1406
+ this.api = new _qilin_agent_client_ui_primitives.SettingsFormModel(scopes.api, [(0, _qilin_agent_client_ui_primitives.settingsTextField)("baseURL"), {
1407
+ ...(0, _qilin_agent_client_ui_primitives.settingsNumberField)("count"),
1408
+ parse: (text) => {
1409
+ if (text.trim() === "") return { kind: "clear" };
1410
+ const value = Number(text);
1411
+ return Number.isInteger(value) && value >= 1 && value <= 50 ? {
1412
+ kind: "set",
1413
+ value
1414
+ } : void 0;
1415
+ }
1416
+ }]);
1417
+ this.store = (0, _qilin_agent_client_store.createSnapshotStore)(this.projection());
1418
+ const publish = () => {
1419
+ this.store.set(this.projection());
1420
+ if (this.ref() !== this.credential.ref) this.readCredential();
1421
+ };
1422
+ this.unsubscribe = [...[
1423
+ this.selection,
1424
+ this.messages,
1425
+ this.api
1426
+ ].map((form) => form.bind(() => form.shell()).subscribe(publish)), ...[
1427
+ scopes.web,
1428
+ scopes.messages,
1429
+ scopes.api
1430
+ ].map((scope) => scope.subscribe(() => {
1344
1431
  this.readCredential();
1345
- });
1432
+ }))];
1346
1433
  this.readCredential();
1347
1434
  }
1435
+ /** Whether the Host serves both sections the switch needs. */
1436
+ switchAvailable() {
1437
+ return this.selection.shell().available && this.api.shell().available;
1438
+ }
1439
+ /** The staged switch position, read from the staged search selection. */
1440
+ searchApi() {
1441
+ return this.switchAvailable() && this.selection.field("searchProvider").text === PROVIDERS.searchProvider.api;
1442
+ }
1348
1443
  projection() {
1444
+ const primary = this.messages.shell();
1445
+ const served = [
1446
+ primary,
1447
+ this.selection.shell(),
1448
+ this.api.shell()
1449
+ ].filter((item) => item.available);
1450
+ const shell = {
1451
+ available: primary.available,
1452
+ writable: served.every((item) => item.writable),
1453
+ dirty: served.some((item) => item.dirty),
1454
+ invalid: served.some((item) => item.invalid),
1455
+ saving: served.some((item) => item.saving),
1456
+ failed: served.some((item) => item.failed)
1457
+ };
1458
+ const searchApi = this.searchApi();
1349
1459
  return {
1350
- ...this.form.shell(),
1351
- baseURL: this.form.field("baseURL"),
1352
- maxUses: this.form.field("maxUses"),
1353
- apiKey: this.form.field(API_KEY_FIELD),
1460
+ ...shell,
1461
+ apiSwitchAvailable: this.switchAvailable(),
1462
+ apiSwitchBlocked: shell.invalid || shell.failed,
1463
+ useSearchApi: searchApi,
1464
+ baseURL: (searchApi ? this.api : this.messages).field("baseURL"),
1465
+ maxUses: this.messages.field("maxUses"),
1466
+ count: this.api.field("count"),
1467
+ apiKey: this.selection.field(API_KEY_FIELD),
1354
1468
  apiKeyConfigured: this.credential.configured,
1355
1469
  apiKeyWritable: this.credential.writable
1356
1470
  };
1357
1471
  }
1472
+ /** The reference the selected API's section names, or the providers' default. */
1473
+ ref() {
1474
+ return refOf(this.searchApi() ? this.scopes.api.getSnapshot() : this.scopes.messages.getSnapshot());
1475
+ }
1358
1476
  /**
1359
- * Ask the credentials domain about the reference the section currently names.
1477
+ * Ask the credentials domain about the reference the selected section currently names.
1360
1478
  *
1361
- * The answer is stored with the reference it describes: `apiKeyEnv` can
1362
- * change between the request and its response, and two reads can settle out
1363
- * of order, so a response is published only while it still answers for the
1364
- * reference in force.
1479
+ * The answer is stored with the reference it describes: `apiKeyEnv` and the
1480
+ * switch can change between the request and its response, and two reads can
1481
+ * settle out of order, so a response is published only while it still
1482
+ * answers for the reference in force.
1365
1483
  */
1366
1484
  async readCredential() {
1367
- const ref = refOf(this.scope.getSnapshot());
1485
+ const ref = this.ref();
1368
1486
  if (ref !== this.credential.ref) {
1369
1487
  this.credential = {
1370
1488
  ref,
@@ -1374,7 +1492,7 @@ window.__ModuleLoader__.load({
1374
1492
  this.store.set(this.projection());
1375
1493
  }
1376
1494
  const response = await this.ctx.remote.credentials.describe([ref]);
1377
- if (!response.ok || ref !== refOf(this.scope.getSnapshot())) return;
1495
+ if (!response.ok || ref !== this.ref()) return;
1378
1496
  const view = response.value[ref];
1379
1497
  const next = {
1380
1498
  ref,
@@ -1386,11 +1504,11 @@ window.__ModuleLoader__.load({
1386
1504
  this.store.set(this.projection());
1387
1505
  }
1388
1506
  /**
1389
- * Re-read after the Host reports a change to the reference this card watches.
1507
+ * Re-read after the Host reports a change to the reference this page watches.
1390
1508
  *
1391
1509
  * A key can be written from somewhere else — the Models page addresses the
1392
- * same reference — and the settings section does not change when it is, so
1393
- * without this the badge keeps reporting a state the Host already replaced.
1510
+ * same reference — and no settings section changes when it is, so without
1511
+ * this the badge keeps reporting a state the Host already replaced.
1394
1512
  * @param ref - the reference the Host reports as changed.
1395
1513
  */
1396
1514
  refreshCredential(ref) {
@@ -1398,29 +1516,94 @@ window.__ModuleLoader__.load({
1398
1516
  this.readCredential();
1399
1517
  }
1400
1518
  /**
1401
- * Build the face the card's slot registration injects.
1402
- * @returns the card's snapshot and its form actions.
1519
+ * Build the face the page's slot registration injects. `baseURL` edits the
1520
+ * selected API's endpoint; `maxUses` and `count` edit their own sections.
1521
+ * @returns the page's snapshot and its form actions.
1403
1522
  */
1404
1523
  inject() {
1524
+ const formOf = (field) => {
1525
+ if (field === API_KEY_FIELD) return this.selection;
1526
+ if (field === "maxUses") return this.messages;
1527
+ if (field === "count") return this.api;
1528
+ return this.searchApi() ? this.api : this.messages;
1529
+ };
1405
1530
  return {
1406
1531
  hooks: { webSearchCard: this.store },
1407
- ...this.form.actions()
1532
+ edit: (field, text) => {
1533
+ formOf(field).actions().edit(field, text);
1534
+ },
1535
+ resetField: (field) => {
1536
+ formOf(field).actions().resetField(field);
1537
+ },
1538
+ setSearchApi: (enabled) => {
1539
+ this.select(enabled);
1540
+ },
1541
+ save: () => {
1542
+ this.save();
1543
+ },
1544
+ discard: () => {
1545
+ for (const form of [
1546
+ this.selection,
1547
+ this.messages,
1548
+ this.api
1549
+ ]) form.actions().discard();
1550
+ }
1408
1551
  };
1409
1552
  }
1410
1553
  /**
1554
+ * Stage both provider selections for one switch position. A target equal to
1555
+ * the composed value clears the override so the deployment default keeps
1556
+ * applying.
1557
+ * @param enabled - true for the Search and Fetch APIs.
1558
+ */
1559
+ select(enabled) {
1560
+ const base = this.scopes.web.getSnapshot().base;
1561
+ const actions = this.selection.actions();
1562
+ for (const field of ["searchProvider", "fetchProvider"]) {
1563
+ const target = PROVIDERS[field][enabled ? "api" : "messages"];
1564
+ if (base?.[field] === target) actions.resetField(field);
1565
+ else actions.edit(field, target);
1566
+ }
1567
+ }
1568
+ /**
1569
+ * Save the provider sections before the selection, so a switch takes effect
1570
+ * only after the endpoint it uses has landed. A refused section stops the
1571
+ * selection from saving and keeps every remaining draft for correction.
1572
+ * @returns settlement after every attempted write.
1573
+ */
1574
+ async save() {
1575
+ const state = this.projection();
1576
+ if (!state.available || state.invalid || state.saving) return;
1577
+ for (const form of [this.messages, this.api]) {
1578
+ if (!form.shell().available || !form.shell().dirty) continue;
1579
+ await form.save();
1580
+ if (form.shell().failed) return;
1581
+ }
1582
+ if (this.selection.shell().dirty) await this.selection.save();
1583
+ }
1584
+ /**
1411
1585
  * Write the staged key, then re-read whether the Host now holds one.
1412
1586
  * @param value - the staged credential literal.
1413
1587
  * @returns whether the Host reports a configured credential afterwards.
1414
1588
  */
1415
1589
  async writeKey(value) {
1416
- await this.ctx.remote.credentials.set(refOf(this.scope.getSnapshot()), value);
1590
+ await this.ctx.remote.credentials.set(this.ref(), value);
1417
1591
  await this.readCredential();
1418
1592
  return this.credential.configured;
1419
1593
  }
1594
+ /** Release configuration subscriptions. */
1595
+ dispose() {
1596
+ for (const off of this.unsubscribe) off();
1597
+ for (const form of [
1598
+ this.selection,
1599
+ this.messages,
1600
+ this.api
1601
+ ]) form.dispose();
1602
+ }
1420
1603
  };
1421
1604
  /**
1422
- * The credential reference the section names, or the provider's default.
1423
- * @param snapshot - the current scope snapshot.
1605
+ * The credential reference a section names, or the providers' default.
1606
+ * @param snapshot - the section's current scope snapshot.
1424
1607
  * @returns the reference to address.
1425
1608
  */
1426
1609
  function refOf(snapshot) {
@@ -1474,15 +1657,24 @@ window.__ModuleLoader__.load({
1474
1657
  gitMaxListEntries: "List cap (entries)",
1475
1658
  gitMaxListEntriesHint: "Upper bound on branches or pull requests one list answer returns.",
1476
1659
  webSearchTitle: "Web search",
1477
- webSearchDescription: "The DeepSeek search provider.",
1660
+ webSearchDescription: "Set up the DeepSeek search provider.",
1661
+ webSearchUseApi: "Use the new Web Search API",
1662
+ webSearchUseApiHint: "Off by default: search runs through DeepSeek Messages. For the new Web Search API's features and pricing, see the ",
1663
+ webSearchGuide: "Search & Fetch guide",
1664
+ webSearchGuideUrl: "https://api-docs.deepseek.com/guides/search",
1478
1665
  webSearchApiKey: "API key",
1479
1666
  webSearchApiKeyHint: "Stored outside the settings file. Leave blank to keep the current key.",
1480
1667
  webSearchApiKeySet: "A key is configured.",
1481
1668
  webSearchApiKeyUnset: "No key is configured; search is unavailable until one is.",
1482
- webSearchBaseUrl: "Endpoint",
1483
- webSearchBaseUrlHint: "Leave blank to use the provider default.",
1669
+ webSearchBaseUrl: "Messages API base URL",
1670
+ webSearchBaseUrlHint: "Include the API prefix, such as https://api.deepseek.com/anthropic/v1. The provider appends /messages. Leave blank to restore the default.",
1484
1671
  webSearchMaxUses: "Max searches per request",
1485
- webSearchMaxUsesHint: "How many times one request may search before it must answer.",
1672
+ webSearchMaxUsesHint: "How many searches the auxiliary model may run within one Messages request. Applies only to the Messages API.",
1673
+ webSearchSearchApiBaseUrl: "Search / Fetch API base URL",
1674
+ webSearchSearchApiBaseUrlHint: "Include the API prefix, such as https://api.deepseek.com/v1/tools. The provider appends /search or /fetch. Leave blank to restore the default.",
1675
+ webSearchCount: "Results per search",
1676
+ webSearchCountHint: "Results returned per query: an integer from 1 to 50, default 10. This controls result count, not search calls. web_search keeps no more sources than its own result limit.",
1677
+ webSearchInvalidCount: "Enter an integer from 1 to 50, or leave blank to use the default.",
1486
1678
  subagentTitle: "Subagent",
1487
1679
  subagentDescription: "Set Subagent recursion depth, count, and models.",
1488
1680
  subagentLimitsTitle: "Limits",
@@ -1556,15 +1748,24 @@ window.__ModuleLoader__.load({
1556
1748
  gitMaxListEntries: "列表上限(条)",
1557
1749
  gitMaxListEntriesHint: "一次列表应答最多返回多少分支或拉取请求。",
1558
1750
  webSearchTitle: "网页搜索",
1559
- webSearchDescription: "DeepSeek 搜索提供方。",
1751
+ webSearchDescription: "设置 DeepSeek 的搜索提供方。",
1752
+ webSearchUseApi: "启用新版 Web 搜索 API",
1753
+ webSearchUseApiHint: "默认关闭,搜索通过 DeepSeek Messages 完成。新版 Web 搜索 API 功能与计费详见",
1754
+ webSearchGuide: "网页搜索与抓取指南",
1755
+ webSearchGuideUrl: "https://api-docs.deepseek.com/zh-cn/guides/search",
1560
1756
  webSearchApiKey: "API Key",
1561
1757
  webSearchApiKeyHint: "不写入设置文件。留空表示保持当前密钥。",
1562
1758
  webSearchApiKeySet: "已配置密钥。",
1563
1759
  webSearchApiKeyUnset: "未配置密钥;配置之前搜索不可用。",
1564
- webSearchBaseUrl: "接口地址",
1565
- webSearchBaseUrlHint: "留空则使用提供方默认地址。",
1760
+ webSearchBaseUrl: "Messages API 基础地址",
1761
+ webSearchBaseUrlHint: "填写含 API 前缀的地址,例如 https://api.deepseek.com/anthropic/v1;程序追加 /messages,留空恢复默认。",
1566
1762
  webSearchMaxUses: "单次请求最多搜索次数",
1567
- webSearchMaxUsesHint: "一次请求在必须作答前最多可以搜索多少次。",
1763
+ webSearchMaxUsesHint: "辅助模型在一次 Messages 请求内最多可执行的搜索次数,仅适用于 Messages API。",
1764
+ webSearchSearchApiBaseUrl: "Search / Fetch API 基础地址",
1765
+ webSearchSearchApiBaseUrlHint: "填写含 API 前缀的地址,例如 https://api.deepseek.com/v1/tools;程序追加 /search 或 /fetch,留空恢复默认。",
1766
+ webSearchCount: "每次搜索结果数",
1767
+ webSearchCountHint: "每个查询返回的结果条数,须为 1–50 的整数,默认 10;不控制搜索调用次数。web_search 保留的来源数不超过其自身的结果上限。",
1768
+ webSearchInvalidCount: "请填 1–50 的整数;留空表示使用默认值。",
1568
1769
  subagentTitle: "Subagent",
1569
1770
  subagentDescription: "设置 Subagent 的递归层级、数量和模型。",
1570
1771
  subagentLimitsTitle: "运行限制",
@@ -1630,7 +1831,11 @@ window.__ModuleLoader__.load({
1630
1831
  const bash = new BashCardController(ctx.configForms.get(SHELL_NS));
1631
1832
  const git = new GitCardController(ctx.configForms.get(GIT_NS));
1632
1833
  const agentLoop = new AgentLoopCardController(ctx.configForms.get(AGENT_LOOP_NS));
1633
- const webSearch = new WebSearchCardController(ctx.configForms.get(WEB_SEARCH_NS), ctx);
1834
+ const webSearch = new WebSearchCardController({
1835
+ web: ctx.configForms.get("web"),
1836
+ messages: ctx.configForms.get(WEB_SEARCH_NS),
1837
+ api: ctx.configForms.get(WEB_API_NS)
1838
+ }, ctx);
1634
1839
  const subagentLimits = new SubagentLimitsCardController(ctx.configForms.get("subagent"));
1635
1840
  const subagentModelSelection = new SubagentModelSelectionCardController(ctx.configForms.get(SUBAGENT_MODEL_SELECTION_NS), ctx);
1636
1841
  const subagentLimitsFace = subagentLimits.inject();
@@ -1650,6 +1855,9 @@ window.__ModuleLoader__.load({
1650
1855
  ctx.effect(() => () => {
1651
1856
  subagentModelSelection.dispose();
1652
1857
  }, "ui-settings-plugins: subagent preference");
1858
+ ctx.effect(() => () => {
1859
+ webSearch.dispose();
1860
+ }, "ui-settings-plugins: web-search form subscription");
1653
1861
  const pages = [
1654
1862
  [[SHELL_NS], () => ctx.slots.inject("plugins.item", () => ctx.slots.register({
1655
1863
  name: "plugins.item",
@@ -1,7 +1,8 @@
1
1
  /**
2
- * The web-search provider's configuration page: its endpoint, its per-request
3
- * search budget, and the key — which is written through the credentials
4
- * domain, never into the settings section, so the literal never rides a response.
2
+ * The web-search settings page: the switch between Messages search and the
3
+ * Search and Fetch APIs, the selected API's endpoint and per-search limit, and
4
+ * the key — which is written through the credentials domain, never into the
5
+ * settings section, so the literal never rides a response.
5
6
  */
6
7
  import type { InjectFace, PropsLocale, PropsRuntime } from '@qilin-agent/client-ui-slots';
7
8
  import type { WebSearchCardFace } from './web-search-card-controller.ts';
@@ -7,7 +7,7 @@ import { type SettingsFormActions, type SettingsFieldState, type SettingsFormShe
7
7
  * client package must not depend on a Host package, and the executor families
8
8
  * that own it spell the same value.
9
9
  */
10
- export declare const SHELL_NS = "shell";
10
+ export declare const SHELL_NS = "bash-sandbox";
11
11
  /** The shell fields this card edits — a subset of the served schema by design. */
12
12
  export interface BashSettings {
13
13
  /** Foreground command timeout in milliseconds. */
@@ -1,6 +1,6 @@
1
1
  /** Locale bundles for the built-in plugins settings section and the plugin configuration pages. */
2
2
  /** Locale keys these surfaces render. */
3
- export type PluginsSettingsLocaleKey = 'nav' | 'title' | 'intro' | 'tabs' | 'empty' | 'overridden' | 'reset' | 'readOnly' | 'unavailable' | 'save' | 'saving' | 'saveFailed' | 'invalidNumber' | 'bashTitle' | 'bashDescription' | 'bashTimeoutMs' | 'bashTimeoutMsHint' | 'bashMaxOutputBytes' | 'bashMaxOutputBytesHint' | 'agentLoopTitle' | 'agentLoopDescription' | 'agentLoopMaxParallel' | 'agentLoopMaxParallelHint' | 'webSearchTitle' | 'webSearchDescription' | 'webSearchApiKey' | 'webSearchApiKeyHint' | 'webSearchApiKeySet' | 'webSearchApiKeyUnset' | 'webSearchBaseUrl' | 'webSearchBaseUrlHint' | 'webSearchMaxUses' | 'webSearchMaxUsesHint' | 'gitTitle' | 'gitDescription' | 'gitBin' | 'gitBinHint' | 'ghBin' | 'ghBinHint' | 'gitTimeoutMs' | 'gitTimeoutMsHint' | 'gitDiscoveryTimeoutMs' | 'gitDiscoveryTimeoutMsHint' | 'ghTimeoutMs' | 'ghTimeoutMsHint' | 'gitMaxDiffBytes' | 'gitMaxDiffBytesHint' | 'gitMaxStderrChars' | 'gitMaxStderrCharsHint' | 'gitMaxListEntries' | 'gitMaxListEntriesHint' | 'subagentTitle' | 'subagentDescription' | 'subagentLimitsTitle' | 'subagentMaxDepth' | 'subagentDepthHelpLabel' | 'subagentDepthHelp' | 'subagentDepthZero' | 'subagentDepthOne' | 'subagentDepthOverride' | 'subagentMaxActive' | 'subagentCapacityHelpLabel' | 'subagentCapacityHelp' | 'subagentDepthInvalid' | 'subagentCapacityInvalid' | 'subagentModelSelectionTitle' | 'subagentModelSelectionToggle' | 'subagentModelSelectionChoose' | 'subagentModelSelectionAllowed' | 'subagentModelSelectionLoading' | 'subagentModelSelectionLoadFailed' | 'subagentModelSelectionRetry' | 'subagentModelSelectionPartial' | 'subagentModelSelectionUnavailable' | 'subagentModelSelectionUnavailableGroup' | 'subagentModelSelectionEmpty' | 'subagentModelSelectionRequired' | 'subagentModelSelectionConflict' | 'subagentModelSelectionOff';
3
+ export type PluginsSettingsLocaleKey = 'nav' | 'title' | 'intro' | 'tabs' | 'empty' | 'overridden' | 'reset' | 'readOnly' | 'unavailable' | 'save' | 'saving' | 'saveFailed' | 'invalidNumber' | 'bashTitle' | 'bashDescription' | 'bashTimeoutMs' | 'bashTimeoutMsHint' | 'bashMaxOutputBytes' | 'bashMaxOutputBytesHint' | 'agentLoopTitle' | 'agentLoopDescription' | 'agentLoopMaxParallel' | 'agentLoopMaxParallelHint' | 'webSearchTitle' | 'webSearchDescription' | 'webSearchUseApi' | 'webSearchUseApiHint' | 'webSearchGuide' | 'webSearchGuideUrl' | 'webSearchApiKey' | 'webSearchApiKeyHint' | 'webSearchApiKeySet' | 'webSearchApiKeyUnset' | 'webSearchBaseUrl' | 'webSearchBaseUrlHint' | 'webSearchMaxUses' | 'webSearchMaxUsesHint' | 'webSearchSearchApiBaseUrl' | 'webSearchSearchApiBaseUrlHint' | 'webSearchCount' | 'webSearchCountHint' | 'webSearchInvalidCount' | 'gitTitle' | 'gitDescription' | 'gitBin' | 'gitBinHint' | 'ghBin' | 'ghBinHint' | 'gitTimeoutMs' | 'gitTimeoutMsHint' | 'gitDiscoveryTimeoutMs' | 'gitDiscoveryTimeoutMsHint' | 'ghTimeoutMs' | 'ghTimeoutMsHint' | 'gitMaxDiffBytes' | 'gitMaxDiffBytesHint' | 'gitMaxStderrChars' | 'gitMaxStderrCharsHint' | 'gitMaxListEntries' | 'gitMaxListEntriesHint' | 'subagentTitle' | 'subagentDescription' | 'subagentLimitsTitle' | 'subagentMaxDepth' | 'subagentDepthHelpLabel' | 'subagentDepthHelp' | 'subagentDepthZero' | 'subagentDepthOne' | 'subagentDepthOverride' | 'subagentMaxActive' | 'subagentCapacityHelpLabel' | 'subagentCapacityHelp' | 'subagentDepthInvalid' | 'subagentCapacityInvalid' | 'subagentModelSelectionTitle' | 'subagentModelSelectionToggle' | 'subagentModelSelectionChoose' | 'subagentModelSelectionAllowed' | 'subagentModelSelectionLoading' | 'subagentModelSelectionLoadFailed' | 'subagentModelSelectionRetry' | 'subagentModelSelectionPartial' | 'subagentModelSelectionUnavailable' | 'subagentModelSelectionUnavailableGroup' | 'subagentModelSelectionEmpty' | 'subagentModelSelectionRequired' | 'subagentModelSelectionConflict' | 'subagentModelSelectionOff';
4
4
  /** English copy. */
5
5
  export declare const en: Record<PluginsSettingsLocaleKey, string>;
6
6
  /** Simplified Chinese copy. */
@@ -5,7 +5,7 @@ import { type SnapshotStore } from '@qilin-agent/client-store';
5
5
  import type { ConfigForm } from '@qilin-agent/client-ui-settings/client';
6
6
  import type { SettingsFormShell } from '@qilin-agent/client-ui-primitives';
7
7
  /** Namespace of the Host-owned subagent model-selection preference. */
8
- export declare const SUBAGENT_MODEL_SELECTION_NS = "subagent-model-selection";
8
+ export declare const SUBAGENT_MODEL_SELECTION_NS = "subagent-model-selection-settings";
9
9
  /** One exact provider/model route stored as user authorization. */
10
10
  export interface AllowedSubagentModel {
11
11
  provider: string;
@@ -1,37 +1,70 @@
1
1
  /**
2
- * The web-search card's staged form over the `web-search-deepseek` settings
3
- * namespace.
2
+ * The web-search page's staged form over three settings namespaces: `web`,
3
+ * whose provider selection the Search API switch writes, `web-search-deepseek`
4
+ * for Messages search, and `web-deepseek-api` for the Search and Fetch APIs.
4
5
  *
5
- * The key is the one control that does not live in the section: its literal
6
- * never rides a response, so the card learns only whether one is configured
6
+ * The switch selects `deepseek-search-api` and `deepseek-fetch-api` together, or
7
+ * Messages search with local HTTP fetch. A selection equal to the deployment's
8
+ * composed value clears the override instead of storing a copy of it.
9
+ *
10
+ * The key is the one control that does not live in a section: its literal
11
+ * never rides a response, so the page learns only whether one is configured
7
12
  * and writes it through the credentials domain, addressed by the reference the
8
- * section names. It is still staged with the rest of the form, so one save
9
- * covers everything the card shows.
13
+ * selected API's section names. It is still staged with the rest of the form,
14
+ * so one save covers everything the page shows.
10
15
  */
11
16
  import type { Context as ClientContext } from '@qilin-agent/kylin';
12
- import type { SnapshotStore } from '@qilin-agent/client-store';
17
+ import { type SnapshotStore } from '@qilin-agent/client-store';
13
18
  import type { ConfigForm } from '@qilin-agent/client-ui-settings/client';
14
- import { type SettingsFormActions, type SettingsFieldState, type SettingsFormShell } from '@qilin-agent/client-ui-primitives';
19
+ import { type SettingsFieldState, type SettingsFormActions, type SettingsFormShell } from '@qilin-agent/client-ui-primitives';
15
20
  /**
16
- * Namespace of the DeepSeek search provider. Spelled here rather than
21
+ * Namespace of the DeepSeek Messages search provider. Spelled here rather than
17
22
  * imported: a client package must not depend on a Host package.
18
23
  */
19
24
  export declare const WEB_SEARCH_NS = "web-search-deepseek";
20
- /** The search-provider fields this card edits. */
25
+ /** Namespace of the DeepSeek Search and Fetch API providers. */
26
+ export declare const WEB_API_NS = "web-deepseek-api";
27
+ /** Namespace of the web service's provider selection. */
28
+ export declare const WEB_NS = "web";
29
+ /** The web service's provider selection. */
30
+ export interface WebProviderSelection {
31
+ /** Search provider id. */
32
+ searchProvider?: string;
33
+ /** Fetch provider id. */
34
+ fetchProvider?: string;
35
+ }
36
+ /** The Messages search fields this page edits. */
21
37
  export interface WebSearchSettings {
22
38
  /** Credential reference naming the environment key. */
23
39
  apiKeyEnv?: string;
24
- /** Provider endpoint; blank inherits the provider default. */
40
+ /** Messages endpoint; blank inherits the provider default. */
25
41
  baseURL?: string;
26
- /** Maximum searches served within one request. */
42
+ /** Maximum Messages server-tool uses. */
27
43
  maxUses?: number;
28
44
  }
29
- /** What the web-search card renders. */
45
+ /** The Search and Fetch API fields this page edits. */
46
+ export interface WebApiSettings {
47
+ /** Credential reference naming the environment key. */
48
+ apiKeyEnv?: string;
49
+ /** Search and Fetch API base with its path prefix; blank inherits the provider default. */
50
+ baseURL?: string;
51
+ /** Search API results per search. */
52
+ count?: number;
53
+ }
54
+ /** What the web-search page renders. */
30
55
  export interface WebSearchCardState extends SettingsFormShell {
31
- /** Provider endpoint. */
56
+ /** Whether the Host serves both the selection and the Search / Fetch API section. */
57
+ apiSwitchAvailable: boolean;
58
+ /** Invalid edits or failed saves that switching APIs must keep visible. */
59
+ apiSwitchBlocked: boolean;
60
+ /** Staged switch position: true selects the Search and Fetch APIs. */
61
+ useSearchApi: boolean;
62
+ /** Endpoint of the selected API. */
32
63
  baseURL: SettingsFieldState;
33
- /** Searches allowed per request. */
64
+ /** Maximum Messages server-tool uses. */
34
65
  maxUses: SettingsFieldState;
66
+ /** Search API results per search. */
67
+ count: SettingsFieldState;
35
68
  /** The staged credential, which starts blank on every load. */
36
69
  apiKey: SettingsFieldState;
37
70
  /** Whether the Host reports a credential configured for the referenced key. */
@@ -39,55 +72,92 @@ export interface WebSearchCardState extends SettingsFormShell {
39
72
  /** Whether the credentials domain accepts a write for it; false disables the control. */
40
73
  apiKeyWritable: boolean;
41
74
  }
42
- /** The registration-side face the web-search card's slot entry injects. */
75
+ /** The registration-side face the web-search page's slot entry injects. */
43
76
  export interface WebSearchCardFace extends SettingsFormActions {
44
77
  hooks: {
45
- /** Card snapshot bound by the renderer as useWebSearchCard. */
78
+ /** Page snapshot bound by the renderer as useWebSearchCard. */
46
79
  webSearchCard: SnapshotStore<WebSearchCardState>;
47
80
  };
81
+ /** Stage the API switch: true selects the Search and Fetch APIs, false Messages search with local fetch. */
82
+ setSearchApi: (enabled: boolean) => void;
48
83
  }
49
- /** Bridges the `web-search-deepseek` scope and the credentials domain onto the card. */
84
+ /** Settings scopes for the namespaces the page edits. */
85
+ export interface WebSearchCardScopes {
86
+ /** The web service's provider selection. */
87
+ web: ConfigForm<WebProviderSelection>;
88
+ /** Messages search settings. */
89
+ messages: ConfigForm<WebSearchSettings>;
90
+ /** Search and Fetch API settings. */
91
+ api: ConfigForm<WebApiSettings>;
92
+ }
93
+ /** Bridges the three settings scopes and the credentials domain onto the page. */
50
94
  export declare class WebSearchCardController {
51
- private readonly scope;
95
+ private readonly scopes;
52
96
  private readonly ctx;
53
- private readonly form;
97
+ private readonly selection;
98
+ private readonly messages;
99
+ private readonly api;
54
100
  private readonly store;
101
+ private readonly unsubscribe;
55
102
  private credential;
56
103
  /**
57
- * @param scope - the bound settings scope for the `web-search-deepseek` namespace.
58
- * @param ctx - the card plugin's context, whose `remote.credentials` namespace
59
- * answers for the credential the section references.
104
+ * @param scopes - the bound settings scopes for the page's namespaces.
105
+ * @param ctx - the page plugin's context, whose `remote.credentials` namespace
106
+ * answers for the credential the selected section references.
60
107
  */
61
- constructor(scope: ConfigForm<WebSearchSettings>, ctx: ClientContext);
108
+ constructor(scopes: WebSearchCardScopes, ctx: ClientContext);
109
+ /** Whether the Host serves both sections the switch needs. */
110
+ private switchAvailable;
111
+ /** The staged switch position, read from the staged search selection. */
112
+ private searchApi;
62
113
  private projection;
114
+ /** The reference the selected API's section names, or the providers' default. */
115
+ private ref;
63
116
  /**
64
- * Ask the credentials domain about the reference the section currently names.
117
+ * Ask the credentials domain about the reference the selected section currently names.
65
118
  *
66
- * The answer is stored with the reference it describes: `apiKeyEnv` can
67
- * change between the request and its response, and two reads can settle out
68
- * of order, so a response is published only while it still answers for the
69
- * reference in force.
119
+ * The answer is stored with the reference it describes: `apiKeyEnv` and the
120
+ * switch can change between the request and its response, and two reads can
121
+ * settle out of order, so a response is published only while it still
122
+ * answers for the reference in force.
70
123
  */
71
124
  private readCredential;
72
125
  /**
73
- * Re-read after the Host reports a change to the reference this card watches.
126
+ * Re-read after the Host reports a change to the reference this page watches.
74
127
  *
75
128
  * A key can be written from somewhere else — the Models page addresses the
76
- * same reference — and the settings section does not change when it is, so
77
- * without this the badge keeps reporting a state the Host already replaced.
129
+ * same reference — and no settings section changes when it is, so without
130
+ * this the badge keeps reporting a state the Host already replaced.
78
131
  * @param ref - the reference the Host reports as changed.
79
132
  */
80
133
  refreshCredential(ref: string): void;
81
134
  /**
82
- * Build the face the card's slot registration injects.
83
- * @returns the card's snapshot and its form actions.
135
+ * Build the face the page's slot registration injects. `baseURL` edits the
136
+ * selected API's endpoint; `maxUses` and `count` edit their own sections.
137
+ * @returns the page's snapshot and its form actions.
84
138
  */
85
139
  inject(): WebSearchCardFace;
140
+ /**
141
+ * Stage both provider selections for one switch position. A target equal to
142
+ * the composed value clears the override so the deployment default keeps
143
+ * applying.
144
+ * @param enabled - true for the Search and Fetch APIs.
145
+ */
146
+ private select;
147
+ /**
148
+ * Save the provider sections before the selection, so a switch takes effect
149
+ * only after the endpoint it uses has landed. A refused section stops the
150
+ * selection from saving and keeps every remaining draft for correction.
151
+ * @returns settlement after every attempted write.
152
+ */
153
+ private save;
86
154
  /**
87
155
  * Write the staged key, then re-read whether the Host now holds one.
88
156
  * @param value - the staged credential literal.
89
157
  * @returns whether the Host reports a configured credential afterwards.
90
158
  */
91
159
  private writeKey;
160
+ /** Release configuration subscriptions. */
161
+ dispose(): void;
92
162
  }
93
163
  //# sourceMappingURL=web-search-card-controller.d.ts.map
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@qilin-agent/client-ui-settings-plugins",
3
3
  "description": "Plugins settings section with feature-owned tabs and configurable host-plane plugin cards",
4
- "version": "3.1.4",
4
+ "version": "3.1.6",
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },
@@ -40,22 +40,22 @@
40
40
  },
41
41
  "license": "MIT",
42
42
  "peerDependencies": {
43
- "@qilin-agent/kylin": "~4.0.3"
43
+ "@qilin-agent/kylin": "~4.0.5"
44
44
  },
45
45
  "devDependencies": {
46
46
  "@types/react": "~18.3.1",
47
47
  "clsx": "^2.0.0",
48
48
  "react": "^18.2.0",
49
- "@qilin-agent/kylin": "~4.0.3",
50
- "@qilin-agent/api-remotes": "3.1.4",
51
- "@qilin-agent/client-test-runtime": "3.1.4",
52
- "@qilin-agent/client-store": "3.1.4",
53
- "@qilin-agent/client-locale": "3.1.4",
54
- "@qilin-agent/client-ui-plugin-manager": "3.1.4",
55
- "@qilin-agent/client-ui-primitives": "3.1.4",
56
- "@qilin-agent/client-ui-renderer": "3.1.4",
57
- "@qilin-agent/client-ui-settings": "3.1.4",
58
- "@qilin-agent/client-ui-slots": "3.1.4"
49
+ "@qilin-agent/kylin": "~4.0.5",
50
+ "@qilin-agent/api-remotes": "3.1.6",
51
+ "@qilin-agent/client-test-runtime": "3.1.6",
52
+ "@qilin-agent/client-locale": "3.1.6",
53
+ "@qilin-agent/client-ui-plugin-manager": "3.1.6",
54
+ "@qilin-agent/client-store": "3.1.6",
55
+ "@qilin-agent/client-ui-primitives": "3.1.6",
56
+ "@qilin-agent/client-ui-renderer": "3.1.6",
57
+ "@qilin-agent/client-ui-settings": "3.1.6",
58
+ "@qilin-agent/client-ui-slots": "3.1.6"
59
59
  },
60
60
  "files": [
61
61
  "lib/index.js",