@mofeng2223/dsh-claude-provider 0.3.1 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/client.js CHANGED
@@ -8,7 +8,7 @@ window.__ModuleLoader__.load({
8
8
  let react = require("react");
9
9
  let react_dom = require("react-dom");
10
10
  let _deepseek_ai_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
11
- let _deepseek_ai_dsh_client_runtime_client = require("@deepseek-ai/dsh-client-runtime/client");
11
+ let _deepseek_ai_dsh_client_store = require("@deepseek-ai/dsh-client-store");
12
12
  //#region lib/types/client/apiKey.js
13
13
  /**
14
14
  * Browser-side judgement of a typed API key.
@@ -56,7 +56,7 @@ window.__ModuleLoader__.load({
56
56
  }
57
57
  //#endregion
58
58
  //#region \0dsh-css:/home/runner/work/deepseek-harness/deepseek-harness/packages/client/ui-settings-models/src/client/ModelsSection.module.css.mjs
59
- const css$3 = ".zGbnIq_section{max-width:720px;color:var(--dsw-alias-label-primary);flex-direction:column;gap:12px;display:flex}.zGbnIq_title{color:var(--dsw-alias-label-primary);margin:0;font-size:16px;font-weight:500;line-height:24px}.zGbnIq_intro{color:var(--dsw-alias-label-tertiary);margin:0;font-size:14px;line-height:22px}.zGbnIq_notice{color:var(--dsw-alias-state-warn-label);margin:0;font-size:12px;line-height:18px}.zGbnIq_savedNotice{color:var(--dsw-alias-state-success-primary);margin:0;font-size:12px;line-height:18px}.zGbnIq_rows{flex-direction:column;gap:8px;margin:12px 0 0;padding:0;list-style:none;display:flex}.zGbnIq_rowCard{border:1px solid var(--dsw-alias-border-l2);border-radius:12px;flex-direction:column;gap:12px;padding:12px 14px;display:flex}.zGbnIq_rowHead{align-items:center;gap:10px;display:flex}.zGbnIq_rowIdentity{align-items:center;gap:6px;min-width:0;display:inline-flex}.zGbnIq_rowName{color:var(--dsw-alias-label-primary);font-size:14px;font-weight:500;line-height:22px}.zGbnIq_rowTag{border:1px solid var(--dsw-alias-border-l3);color:var(--dsw-alias-label-secondary);border-radius:4px;flex:none;padding:1px 6px;font-size:11px;line-height:16px}.zGbnIq_credentialDot{box-sizing:border-box;border-radius:50%;flex:none;width:8px;height:8px;display:inline-block}.zGbnIq_credentialDotConfigured{background:var(--dsw-alias-state-success-primary)}.zGbnIq_credentialDotMissing{background:var(--dsw-alias-state-error-primary)}.zGbnIq_rowActions{align-items:center;gap:4px;margin-left:auto;display:inline-flex}.zGbnIq_primaryButton,.zGbnIq_secondaryButton,.zGbnIq_addButton{box-sizing:border-box;height:36px;font:inherit;cursor:pointer;border:none;border-radius:18px;justify-content:center;align-items:center;gap:4px;padding:0 14px;font-size:14px;line-height:22px;display:inline-flex}.zGbnIq_primaryButton{background:var(--dsw-alias-button-primary-fill);color:var(--dsw-alias-label-primary-foreground)}.zGbnIq_primaryButton:hover:not(:disabled){background:var(--dsw-alias-button-primary-hover)}.zGbnIq_secondaryButton,.zGbnIq_addButton{border:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-primary);background:0 0}.zGbnIq_secondaryButton:hover:not(:disabled),.zGbnIq_addButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.zGbnIq_secondaryButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover-solid)}.zGbnIq_dangerButton{box-sizing:border-box;height:36px;color:var(--dsw-alias-state-error-primary);font:inherit;cursor:pointer;background:0 0;border:none;border-radius:18px;justify-content:center;align-items:center;padding:0 14px;font-size:14px;line-height:22px;display:inline-flex}.zGbnIq_dangerButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover-danger)}.zGbnIq_rowActions .zGbnIq_secondaryButton,.zGbnIq_rowActions .zGbnIq_dangerButton{border-radius:14px;height:28px;padding:0 10px;font-size:12px;line-height:18px}.zGbnIq_primaryButton:disabled,.zGbnIq_secondaryButton:disabled,.zGbnIq_dangerButton:disabled,.zGbnIq_addButton:disabled,.zGbnIq_linkButton:disabled,.zGbnIq_addModelButton:disabled{opacity:.4;cursor:default}.zGbnIq_primaryButton:focus-visible,.zGbnIq_secondaryButton:focus-visible,.zGbnIq_dangerButton:focus-visible,.zGbnIq_addButton:focus-visible,.zGbnIq_linkButton:focus-visible,.zGbnIq_addModelButton:focus-visible,.zGbnIq_iconButton:focus-visible,.zGbnIq_customizedSummary:focus-visible{box-shadow:0 0 0 2px var(--dsw-alias-border-l3);outline:none}.zGbnIq_editor{background:var(--dsw-alias-bg-module-platform);border-radius:12px;flex-direction:column;gap:14px;padding:14px 16px;display:flex}.zGbnIq_editorHeader{align-items:baseline;gap:8px;display:flex}.zGbnIq_editorTitle{color:var(--dsw-alias-label-primary);font-size:14px;font-weight:500;line-height:22px}.zGbnIq_editorRoute{color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:18px}.zGbnIq_field{flex-direction:column;gap:6px;display:flex}.zGbnIq_fieldLabel{color:var(--dsw-alias-label-secondary);align-items:center;gap:10px;font-size:12px;font-weight:500;line-height:18px;display:inline-flex}.zGbnIq_linkButton{box-sizing:border-box;height:28px;color:var(--dsw-alias-label-tertiary);font:inherit;cursor:pointer;background:0 0;border:none;border-radius:14px;align-items:center;padding:0 10px;font-size:12px;line-height:18px;display:inline-flex}.zGbnIq_linkButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-secondary)}.zGbnIq_advancedHint{color:var(--dsw-alias-label-tertiary);margin:0;font-size:12px;line-height:18px}.zGbnIq_editorActions{justify-content:flex-end;gap:8px;display:flex}.zGbnIq_addBlock{flex-direction:column;gap:12px;display:flex}.zGbnIq_addActions{flex-wrap:wrap;gap:10px;display:flex}.zGbnIq_addButton{border:1px dashed var(--dsw-alias-border-l3);border-radius:12px;flex:1 1 0;gap:6px;min-width:180px;height:44px}.zGbnIq_addCard,.zGbnIq_setupCard{background:var(--dsw-alias-bg-module-platform);border-radius:12px;flex-direction:column;gap:14px;padding:14px 16px;list-style:none;display:flex}.zGbnIq_addCard .zGbnIq_editor,.zGbnIq_setupCard .zGbnIq_editor{background:0 0;padding:0}.zGbnIq_customized{border-top:1px solid var(--dsw-alias-border-l2);padding-top:10px}.zGbnIq_customizedSummary{cursor:pointer;width:fit-content;color:var(--dsw-alias-label-secondary);border-radius:6px;align-items:center;gap:6px;margin-left:-4px;padding:2px 4px;font-size:12px;font-weight:500;line-height:18px;list-style:none;display:flex}.zGbnIq_customizedSummary::-webkit-details-marker{display:none}.zGbnIq_customizedSummary:before{content:\"\";border-bottom:1.5px solid;border-right:1.5px solid;width:5px;height:5px;transition:transform .12s;transform:rotate(-45deg)translate(-1px,-1px)}.zGbnIq_customized[open]>.zGbnIq_customizedSummary:before{transform:rotate(45deg)translate(-1px,-1px)}.zGbnIq_customizedSummary:hover{color:var(--dsw-alias-label-primary)}.zGbnIq_customizedBody{flex-direction:column;gap:12px;padding-top:12px;display:flex}.zGbnIq_modelCatalog{border-top:1px solid var(--dsw-alias-border-l2);flex-direction:column;gap:10px;padding-top:12px;display:flex}.zGbnIq_modelCatalogHeading{flex-direction:column;gap:2px;display:flex}.zGbnIq_modelCatalogTitle{color:var(--dsw-alias-label-secondary);font-size:12px;font-weight:500;line-height:18px}.zGbnIq_modelCatalogMeta,.zGbnIq_modelEmpty{color:var(--dsw-alias-label-tertiary);margin:0;font-size:12px;line-height:18px}.zGbnIq_modelList{flex-direction:column;gap:8px;display:flex}.zGbnIq_modelListHead{justify-content:space-between;align-items:flex-start;gap:12px;display:flex}.zGbnIq_modelEntry{border:1px solid var(--dsw-alias-border-l2);border-radius:8px;padding:6px}.zGbnIq_modelRow{grid-template-columns:minmax(0,1.4fr) minmax(0,1fr) auto auto;align-items:center;gap:6px;display:grid}.zGbnIq_iconButton{box-sizing:border-box;width:28px;height:28px;color:var(--dsw-alias-label-tertiary);cursor:pointer;background:0 0;border:none;border-radius:6px;justify-content:center;align-items:center;display:inline-flex}.zGbnIq_iconButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.zGbnIq_iconButton:disabled{cursor:default;opacity:.4}.zGbnIq_iconButtonDanger:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover-danger);color:var(--dsw-alias-state-error-primary)}.zGbnIq_modelAdvanced{grid-template-columns:repeat(auto-fit,minmax(160px,1fr));gap:8px;padding:8px 4px 2px;display:grid}.zGbnIq_modelField{flex-direction:column;gap:4px;display:flex}.zGbnIq_modelFieldLabel{color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:18px}.zGbnIq_modelEmpty{border:1px dashed var(--dsw-alias-border-l3);text-align:center;border-radius:8px;padding:12px}.zGbnIq_addModelButton{box-sizing:border-box;border:1px solid var(--dsw-alias-border-l2);height:28px;color:var(--dsw-alias-label-primary);font:inherit;cursor:pointer;background:0 0;border-radius:14px;align-self:flex-start;align-items:center;gap:4px;padding:0 10px;font-size:12px;line-height:18px;display:inline-flex}.zGbnIq_addModelButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.zGbnIq_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.zGbnIq_input{cursor:pointer;max-width:240px}.zGbnIq_input:focus{border-color:var(--dsw-alias-brand-primary);outline:none}.zGbnIq_input::placeholder{color:var(--dsw-alias-label-dimmed)}.zGbnIq_input:disabled{opacity:.6;cursor:default}.zGbnIq_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}.zGbnIq_error{color:var(--dsw-alias-state-error-primary);margin:0;font-size:12px;line-height:18px}.zGbnIq_deleteDialog{width:min(480px,100%)}.zGbnIq_deleteConfirm:not(:disabled){border-color:var(--dsw-alias-state-error-primary);color:var(--dsw-alias-state-error-primary)}.zGbnIq_deleteConfirm:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover-danger)}.zGbnIq_hiddenLabel{clip:rect(0 0 0 0);white-space:nowrap;width:1px;height:1px;position:absolute;overflow:hidden}@media (prefers-reduced-motion:reduce){.zGbnIq_customizedSummary:before{transition:none}}.zGbnIq_fetchDialog{--dsh-scrollbar-thumb:var(--dsw-alias-scrollbar-bg-l2);--dsh-scrollbar-thumb-hover:var(--dsw-alias-scrollbar-hover-l2);max-width:520px}.zGbnIq_candidateActions{justify-content:flex-end;margin-bottom:6px;display:flex}.zGbnIq_candidateList{flex-direction:column;gap:2px;max-height:320px;margin:0;padding:0;list-style:none;display:flex;overflow-y:auto}.zGbnIq_candidate{border-radius:6px}.zGbnIq_candidateLabel{cursor:pointer;align-items:center;gap:8px;padding:6px 8px;display:flex}.zGbnIq_candidateId{font-family:var(--ds-font-family-code);overflow-wrap:anywhere;flex:auto;font-size:13px}";
59
+ const css$3 = ".zGbnIq_section{max-width:720px;color:var(--dsw-alias-label-primary);flex-direction:column;gap:12px;display:flex}.zGbnIq_title{color:var(--dsw-alias-label-primary);margin:0;font-size:16px;font-weight:500;line-height:24px}.zGbnIq_intro{color:var(--dsw-alias-label-tertiary);margin:0;font-size:14px;line-height:22px}.zGbnIq_notice{color:var(--dsw-alias-state-warn-label);margin:0;font-size:12px;line-height:18px}.zGbnIq_savedNotice{color:var(--dsw-alias-state-success-primary);margin:0;font-size:12px;line-height:18px}.zGbnIq_rows{flex-direction:column;gap:8px;margin:12px 0 0;padding:0;list-style:none;display:flex}.zGbnIq_rowCard{border:.5px solid var(--dsw-alias-border-l4);border-radius:16px;flex-direction:column;gap:12px;padding:12px 14px;display:flex}.zGbnIq_rowHead{align-items:center;gap:10px;display:flex}.zGbnIq_rowIdentity{align-items:center;gap:6px;min-width:0;display:inline-flex}.zGbnIq_rowName{color:var(--dsw-alias-label-primary);font-size:14px;font-weight:500;line-height:22px}.zGbnIq_rowTag{border:.5px solid var(--dsw-alias-border-l3);color:var(--dsw-alias-label-secondary);border-radius:4px;flex:none;padding:1px 6px;font-size:11px;line-height:16px}.zGbnIq_credentialDot{box-sizing:border-box;corner-shape:round;border-radius:50%;flex:none;width:8px;height:8px;display:inline-block}.zGbnIq_credentialDotConfigured{background:var(--dsw-alias-state-success-primary)}.zGbnIq_credentialDotMissing{background:var(--dsw-alias-state-error-primary)}.zGbnIq_rowActions{align-items:center;gap:4px;margin-left:auto;display:inline-flex}.zGbnIq_primaryButton,.zGbnIq_secondaryButton,.zGbnIq_addButton{box-sizing:border-box;height:36px;font:inherit;cursor:pointer;border:none;border-radius:18px;justify-content:center;align-items:center;gap:4px;padding:0 14px;font-size:14px;line-height:22px;display:inline-flex}.zGbnIq_primaryButton{background:var(--dsw-alias-button-primary-fill);color:var(--dsw-alias-label-primary-foreground)}.zGbnIq_primaryButton:hover:not(:disabled){background:var(--dsw-alias-button-primary-hover)}.zGbnIq_secondaryButton,.zGbnIq_addButton{border:.5px solid var(--dsw-alias-border-l3);color:var(--dsw-alias-label-primary);background:0 0}.zGbnIq_secondaryButton:hover:not(:disabled),.zGbnIq_addButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.zGbnIq_secondaryButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover-solid)}.zGbnIq_dangerButton{box-sizing:border-box;height:36px;color:var(--dsw-alias-state-error-primary);font:inherit;cursor:pointer;background:0 0;border:none;border-radius:18px;justify-content:center;align-items:center;padding:0 14px;font-size:14px;line-height:22px;display:inline-flex}.zGbnIq_dangerButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover-danger)}.zGbnIq_rowActions .zGbnIq_secondaryButton,.zGbnIq_rowActions .zGbnIq_dangerButton{border-radius:14px;height:28px;padding:0 10px;font-size:12px;line-height:18px}.zGbnIq_primaryButton:disabled,.zGbnIq_secondaryButton:disabled,.zGbnIq_dangerButton:disabled,.zGbnIq_addButton:disabled,.zGbnIq_linkButton:disabled,.zGbnIq_addModelButton:disabled{opacity:.4;cursor:default}.zGbnIq_primaryButton:focus-visible,.zGbnIq_secondaryButton:focus-visible,.zGbnIq_dangerButton:focus-visible,.zGbnIq_addButton:focus-visible,.zGbnIq_linkButton:focus-visible,.zGbnIq_addModelButton:focus-visible,.zGbnIq_iconButton:focus-visible,.zGbnIq_customizedSummary:focus-visible{box-shadow:0 0 0 2px var(--dsw-alias-border-l3);outline:none}.zGbnIq_editor{background:var(--dsw-alias-bg-module-platform);border-radius:12px;flex-direction:column;gap:14px;padding:14px 16px;display:flex}.zGbnIq_editorHeader{align-items:baseline;gap:8px;display:flex}.zGbnIq_editorTitle{color:var(--dsw-alias-label-primary);font-size:14px;font-weight:500;line-height:22px}.zGbnIq_editorRoute{color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:18px}.zGbnIq_field{flex-direction:column;gap:6px;display:flex}.zGbnIq_fieldLabel{color:var(--dsw-alias-label-secondary);align-items:center;gap:10px;font-size:12px;font-weight:500;line-height:18px;display:inline-flex}.zGbnIq_linkButton{box-sizing:border-box;height:28px;color:var(--dsw-alias-label-tertiary);font:inherit;cursor:pointer;background:0 0;border:none;border-radius:14px;align-items:center;padding:0 10px;font-size:12px;line-height:18px;display:inline-flex}.zGbnIq_linkButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-secondary)}.zGbnIq_advancedHint{color:var(--dsw-alias-label-tertiary);margin:0;font-size:12px;line-height:18px}.zGbnIq_editorActions{justify-content:flex-end;gap:8px;display:flex}.zGbnIq_addBlock{flex-direction:column;gap:12px;display:flex}.zGbnIq_addActions{flex-wrap:wrap;gap:10px;display:flex}.zGbnIq_addButton{border:1px dashed var(--dsw-alias-border-l3);border-radius:16px;flex:1 1 0;gap:6px;min-width:180px;height:44px}.zGbnIq_addCard,.zGbnIq_setupCard{background:var(--dsw-alias-bg-module-platform);border-radius:12px;flex-direction:column;gap:14px;padding:14px 16px;list-style:none;display:flex}.zGbnIq_addCard .zGbnIq_editor,.zGbnIq_setupCard .zGbnIq_editor{background:0 0;padding:0}.zGbnIq_customized{border-top:.5px solid var(--dsw-alias-border-l2);padding-top:10px}.zGbnIq_customizedSummary{cursor:pointer;width:fit-content;color:var(--dsw-alias-label-secondary);border-radius:6px;align-items:center;gap:6px;margin-left:-4px;padding:2px 4px;font-size:12px;font-weight:500;line-height:18px;list-style:none;display:flex}.zGbnIq_customizedSummary::-webkit-details-marker{display:none}.zGbnIq_customizedSummary:before{content:\"\";border-bottom:1.5px solid;border-right:1.5px solid;width:5px;height:5px;transition:transform .12s;transform:rotate(-45deg)translate(-1px,-1px)}.zGbnIq_customized[open]>.zGbnIq_customizedSummary:before{transform:rotate(45deg)translate(-1px,-1px)}.zGbnIq_customizedSummary:hover{color:var(--dsw-alias-label-primary)}.zGbnIq_customizedBody{flex-direction:column;gap:12px;padding-top:12px;display:flex}.zGbnIq_modelCatalog{border-top:.5px solid var(--dsw-alias-border-l2);flex-direction:column;gap:10px;padding-top:12px;display:flex}.zGbnIq_modelCatalogHeading{flex-direction:column;gap:2px;display:flex}.zGbnIq_modelCatalogTitle{color:var(--dsw-alias-label-secondary);font-size:12px;font-weight:500;line-height:18px}.zGbnIq_modelCatalogMeta,.zGbnIq_modelEmpty{color:var(--dsw-alias-label-tertiary);margin:0;font-size:12px;line-height:18px}.zGbnIq_modelList{flex-direction:column;gap:8px;display:flex}.zGbnIq_modelListHead{justify-content:space-between;align-items:flex-start;gap:12px;display:flex}.zGbnIq_modelEntry{border:.5px solid var(--dsw-alias-border-l4);border-radius:10px;padding:6px}.zGbnIq_modelRow{grid-template-columns:minmax(0,1.4fr) minmax(0,1fr) auto auto;align-items:center;gap:6px;display:grid}.zGbnIq_iconButton{box-sizing:border-box;width:28px;height:28px;color:var(--dsw-alias-label-tertiary);cursor:pointer;background:0 0;border:none;border-radius:6px;justify-content:center;align-items:center;display:inline-flex}.zGbnIq_iconButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.zGbnIq_iconButton:disabled{cursor:default;opacity:.4}.zGbnIq_iconButtonDanger:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover-danger);color:var(--dsw-alias-state-error-primary)}.zGbnIq_modelAdvanced{grid-template-columns:repeat(auto-fit,minmax(160px,1fr));gap:8px;padding:8px 4px 2px;display:grid}.zGbnIq_modelField{flex-direction:column;gap:4px;display:flex}.zGbnIq_modelFieldLabel{color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:18px}.zGbnIq_modelEmpty{border:1px dashed var(--dsw-alias-border-l3);text-align:center;border-radius:8px;padding:12px}.zGbnIq_addModelButton{box-sizing:border-box;border:.5px solid var(--dsw-alias-border-l3);height:28px;color:var(--dsw-alias-label-primary);font:inherit;cursor:pointer;background:0 0;border-radius:14px;align-self:flex-start;align-items:center;gap:4px;padding:0 10px;font-size:12px;line-height:18px;display:inline-flex}.zGbnIq_addModelButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.zGbnIq_input{box-sizing:border-box;border:.5px solid var(--dsw-alias-border-l4);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.zGbnIq_input{cursor:pointer;max-width:240px}.zGbnIq_input:focus{border-color:var(--dsw-alias-brand-primary);outline:none}.zGbnIq_input::placeholder{color:var(--dsw-alias-label-dimmed)}.zGbnIq_input:disabled{opacity:.6;cursor:default}.zGbnIq_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}.zGbnIq_error{color:var(--dsw-alias-state-error-primary);margin:0;font-size:12px;line-height:18px}.zGbnIq_deleteDialog{width:min(480px,100%)}.zGbnIq_deleteConfirm:not(:disabled){border-color:var(--dsw-alias-state-error-primary);color:var(--dsw-alias-state-error-primary)}.zGbnIq_deleteConfirm:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover-danger)}.zGbnIq_hiddenLabel{clip:rect(0 0 0 0);white-space:nowrap;width:1px;height:1px;position:absolute;overflow:hidden}@media (prefers-reduced-motion:reduce){.zGbnIq_customizedSummary:before,.zGbnIq_switchThumb{transition:none}}.zGbnIq_fetchDialog{--dsh-scrollbar-thumb:var(--dsw-alias-scrollbar-bg-l2);--dsh-scrollbar-thumb-hover:var(--dsw-alias-scrollbar-hover-l2);max-width:520px}.zGbnIq_candidateToolbar{align-items:center;gap:8px;margin-bottom:6px;display:flex}.zGbnIq_candidateSearch{flex:240px;min-width:0}.zGbnIq_candidateList{flex-direction:column;gap:2px;max-height:320px;margin:0;padding:0;list-style:none;display:flex;overflow-y:auto}.zGbnIq_candidate{border-radius:6px}.zGbnIq_candidateLabel{cursor:pointer;align-items:center;gap:8px;padding:6px 8px;display:flex}.zGbnIq_candidateId{font-family:var(--ds-font-family-code);overflow-wrap:anywhere;flex:auto;font-size:13px}.zGbnIq_candidateEmpty{color:var(--dsw-alias-label-secondary);text-align:center;margin:24px 0;font-size:13px;line-height:20px}";
60
60
  const tagId$3 = "@mofeng2223/dsh-claude-provider/ModelsSection.module.css";
61
61
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$3) + "]") === null) {
62
62
  const tag = document.createElement("style");
@@ -73,10 +73,12 @@ window.__ModuleLoader__.load({
73
73
  "addModelButton": "zGbnIq_addModelButton",
74
74
  "advancedHint": "zGbnIq_advancedHint",
75
75
  "candidate": "zGbnIq_candidate",
76
- "candidateActions": "zGbnIq_candidateActions",
76
+ "candidateEmpty": "zGbnIq_candidateEmpty",
77
77
  "candidateId": "zGbnIq_candidateId",
78
78
  "candidateLabel": "zGbnIq_candidateLabel",
79
79
  "candidateList": "zGbnIq_candidateList",
80
+ "candidateSearch": "zGbnIq_candidateSearch",
81
+ "candidateToolbar": "zGbnIq_candidateToolbar",
80
82
  "credentialDot": "zGbnIq_credentialDot",
81
83
  "credentialDotConfigured": "zGbnIq_credentialDotConfigured",
82
84
  "credentialDotMissing": "zGbnIq_credentialDotMissing",
@@ -127,6 +129,7 @@ window.__ModuleLoader__.load({
127
129
  "section": "zGbnIq_section",
128
130
  "selectInput": "zGbnIq_selectInput",
129
131
  "setupCard": "zGbnIq_setupCard",
132
+ "switchThumb": "zGbnIq_switchThumb",
130
133
  "title": "zGbnIq_title"
131
134
  };
132
135
  //#endregion
@@ -145,13 +148,13 @@ window.__ModuleLoader__.load({
145
148
  className: ModelsSection_module_css_default["secondaryButton"],
146
149
  disabled: props.busy,
147
150
  onClick: props.onCancel,
148
- children: t(props.cancelLabel ?? "cancel")
151
+ children: t(props.cancelLabelKey ?? "cancel")
149
152
  }), (0, react_jsx_runtime.jsx)("button", {
150
153
  type: "button",
151
154
  className: ModelsSection_module_css_default["primaryButton"],
152
155
  disabled: props.submitDisabled,
153
156
  onClick: props.onSubmit,
154
- children: props.busy ? t(props.submitBusyLabel) : t(props.submitLabel)
157
+ children: props.busy ? t(props.submitBusyLabelKey) : t(props.submitLabelKey)
155
158
  })]
156
159
  });
157
160
  }
@@ -443,212 +446,6 @@ window.__ModuleLoader__.load({
443
446
  });
444
447
  }
445
448
  //#endregion
446
- //#region lib/types/client/store.js
447
- /**
448
- * Models settings page store: one snapshot joining the configurable-provider
449
- * directory (`llm.providers`), the settings namespaces (shared settings mirror),
450
- * and the referenced credentials (`credentials.describe`). The host stays the
451
- * single fact source — every mutation writes through the wire and the page
452
- * re-renders from the next describe, pushed or refetched.
453
- */
454
- /**
455
- * Any route key walks a dict schema to the same profile node, so the lookup
456
- * names one that cannot collide with a configured route.
457
- */
458
- const PROBE_ROUTE = "\0probe";
459
- /**
460
- * Human text for a rejected wire call. A transport failure rejects with an
461
- * Error; a host or a runtime can reject with anything, and the page still has
462
- * to say something.
463
- * @param error - the rejection value.
464
- * @returns the message to show.
465
- */
466
- function messageOf(error) {
467
- return error instanceof Error ? error.message : String(error);
468
- }
469
- /**
470
- * Derive the conventional credential reference for a provider route: the v1
471
- * page never asks for an environment-variable name, so a typed key stores
472
- * under this derived reference and the profile records it as `apiKeyEnv`.
473
- * @param provider - provider route id (e.g. `anthropic`, `minimax-cn`).
474
- * @returns the derived reference name (e.g. `MINIMAX_CN_API_KEY`).
475
- */
476
- function deriveKeyRef(provider) {
477
- return `${provider.toUpperCase().replace(/[^A-Z0-9]+/g, "_")}_API_KEY`;
478
- }
479
- /**
480
- * The wire protocols a hand-declared route may name, read out of the owning
481
- * namespace's own schema. This stays a schema read rather than a wire field so
482
- * the choices the page offers cannot drift from the ones the adapter accepts:
483
- * both come from the same `Config`.
484
- * @param namespace - the namespace view whose schema declares the profile shape.
485
- * @param schema - settings schema operations.
486
- * @returns the protocol identifiers, or an empty list when the schema has none.
487
- */
488
- function protocolChoices(namespace, schema) {
489
- if (namespace === void 0) return [];
490
- const list = schema.nodeAtPath(schema.rehydrate(namespace.schema), [
491
- "providers",
492
- PROBE_ROUTE,
493
- "api"
494
- ]);
495
- if (list?.type !== "union" || list.list === void 0) return [];
496
- return list.list.map((entry) => entry.value).filter((value) => typeof value === "string");
497
- }
498
- /** The credential reference a resolved profile names (its `apiKeyEnv` field). */
499
- function apiKeyEnvOf(namespace, path, schema) {
500
- if (namespace === void 0) return void 0;
501
- const profile = schema.getPath(namespace.value, path);
502
- if (typeof profile !== "object" || profile === null) return void 0;
503
- const ref = profile.apiKeyEnv;
504
- return typeof ref === "string" && ref.length > 0 ? ref : void 0;
505
- }
506
- /** The models settings page controller (one per settings surface). */
507
- var ModelsSettingsStore = class {
508
- api;
509
- schema;
510
- describeFace;
511
- /** The snapshot the section renders from (uSES-safe store). */
512
- store = (0, _deepseek_ai_dsh_client_runtime_client.createSnapshotStore)({
513
- status: "idle",
514
- error: null,
515
- credentialError: null,
516
- writable: false,
517
- rows: [],
518
- namespaces: /* @__PURE__ */ new Map()
519
- });
520
- /** Latest load wins; an older response never overwrites a newer one. */
521
- generation = 0;
522
- /**
523
- * @param api - the wire face (credentials/llm domains, and settings writes).
524
- * @param describeFace - the shared mirror's describe face (namespace views and writability).
525
- */
526
- constructor(api, schema, describeFace) {
527
- this.api = api;
528
- this.schema = schema;
529
- this.describeFace = describeFace;
530
- }
531
- /**
532
- * Refresh the whole page snapshot: the provider directory and the mirror's
533
- * settings answer in parallel, then one batched credential describe over
534
- * every referenced ref. Provider failure or absence of an initial settings
535
- * answer keeps the last good rows and surfaces an error; a failed settings
536
- * refresh reuses the mirror's held view.
537
- * @returns nothing; the snapshot carries the outcome.
538
- */
539
- async load() {
540
- const generation = ++this.generation;
541
- this.store.update((s) => {
542
- s.status = "loading";
543
- s.error = null;
544
- });
545
- let providers;
546
- let writable;
547
- let views;
548
- try {
549
- const [providersResponse] = await Promise.all([this.api.llm.providers({}), this.describeFace.ensure()]);
550
- if (!providersResponse.result.ok) throw new Error(providersResponse.result.error.message);
551
- const mirrored = this.describeFace.getSnapshot();
552
- if (mirrored.view === void 0) throw new Error(mirrored.error ?? "settings are unavailable in this browser");
553
- providers = providersResponse.result.value.providers.filter((entry) => entry.provider !== CLAUDE_PROVIDER_DIRECTORY_SENTINEL);
554
- writable = mirrored.view.writable;
555
- views = mirrored.view.namespaces;
556
- } catch (error) {
557
- if (generation !== this.generation) return;
558
- this.store.update((s) => {
559
- s.status = "error";
560
- s.error = error instanceof Error ? error.message : String(error);
561
- });
562
- return;
563
- }
564
- const namespaces = new Map(views.map((view) => [view.ns, view]));
565
- const rows = providers.map((entry) => {
566
- const namespace = namespaces.get(entry.settingsNs);
567
- return {
568
- entry,
569
- configured: namespace !== void 0 && (entry.settingsPath.length === 0 || this.schema.getPath(namespace.value, entry.settingsPath) !== void 0),
570
- removable: namespace !== void 0 && entry.settingsPath.length > 0 && this.schema.hasPath(namespace.user, entry.settingsPath) && !this.schema.hasPath(namespace.base, entry.settingsPath),
571
- apiKeyEnv: apiKeyEnvOf(namespace, entry.settingsPath, this.schema),
572
- credential: void 0
573
- };
574
- });
575
- const refs = [...new Set(rows.flatMap((row) => row.apiKeyEnv === void 0 ? [] : [row.apiKeyEnv]))];
576
- let credentials = {};
577
- let credentialError = null;
578
- if (refs.length > 0) try {
579
- const response = await this.api.credentials.describe({ refs });
580
- if (response.result.ok) credentials = response.result.value.credentials;
581
- else credentialError = response.result.error.message;
582
- } catch (error) {
583
- credentialError = messageOf(error);
584
- }
585
- if (generation !== this.generation) return;
586
- this.store.update((s) => {
587
- s.status = "ready";
588
- s.error = null;
589
- s.credentialError = credentialError;
590
- s.writable = writable;
591
- s.rows = rows.map((row) => ({
592
- ...row,
593
- ...row.apiKeyEnv !== void 0 && credentials[row.apiKeyEnv] !== void 0 ? { credential: credentials[row.apiKeyEnv] } : {}
594
- }));
595
- s.namespaces = namespaces;
596
- });
597
- }
598
- };
599
- /**
600
- * Whether a joined row can serve model requests as it stands: the route is
601
- * registered with the adapter registry, and whatever credential its resolved
602
- * profile names is stored. A profile naming no reference authenticates through
603
- * the provider's own path (the Bedrock chain, Vertex ADC, a gateway that needs
604
- * nothing), as does a live route with no settings address at all, so neither
605
- * owes this page a key.
606
- * @param row - one joined provider row.
607
- * @returns whether the user already has this provider to talk to.
608
- */
609
- function providerUsable(row) {
610
- if (!row.entry.active) return false;
611
- if (row.apiKeyEnv === void 0) return true;
612
- return row.credential?.configured === true;
613
- }
614
- /**
615
- * Project first-run readiness from the provider/settings/credential join used
616
- * by the Models page. The step exists to leave the user with a model to talk
617
- * to, so ANY usable provider ends it; only when none exists does the official
618
- * DeepSeek route — the one route the prompt can offer a key field for — decide
619
- * whether prompting can help. A missing official configurable-provider
620
- * declaration means the adapter is not repairable by navigating to Models.
621
- * @param state - current shared Models join snapshot.
622
- * @returns the onboarding state without reading a parallel fact source.
623
- */
624
- function onboardingReadiness(state) {
625
- if ((state.status === "idle" || state.status === "loading") && state.rows.length === 0) return { kind: "loading" };
626
- if (state.status === "error") return {
627
- kind: "unavailable",
628
- reason: "load-failed"
629
- };
630
- if (state.rows.some(providerUsable)) return { kind: "provider-ready" };
631
- const row = state.rows.find((candidate) => candidate.entry.provider === "deepseek-official" && candidate.entry.settingsNs === "llm-deepseek" && candidate.entry.settingsPath.length === 0);
632
- if (row === void 0) return { kind: "adapter-absent" };
633
- if (!row.entry.active) return {
634
- kind: "unavailable",
635
- reason: "provider-inactive"
636
- };
637
- if (state.credentialError !== null || row.credential === void 0) return {
638
- kind: "unavailable",
639
- reason: "credentials-unavailable"
640
- };
641
- if (!state.writable) return {
642
- kind: "unavailable",
643
- reason: "settings-read-only"
644
- };
645
- if (!row.credential.writable) return {
646
- kind: "unavailable",
647
- reason: "credential-read-only"
648
- };
649
- return { kind: "credential-missing" };
650
- }
651
- //#endregion
652
449
  //#region lib/types/client/ModelListEditor.js
653
450
  /**
654
451
  * The model list of one pi-ai provider profile, plus the action that asks the
@@ -753,11 +550,12 @@ window.__ModuleLoader__.load({
753
550
  * @returns the model-list editor.
754
551
  */
755
552
  function ModelListEditor(props) {
756
- const { models, onChange, probe, api, t, disabled } = props;
553
+ const { models, onChange, probe, operations, t, disabled } = props;
757
554
  const [busy, setBusy] = (0, react.useState)(false);
758
555
  const [failure, setFailure] = (0, react.useState)(void 0);
759
556
  const [candidates, setCandidates] = (0, react.useState)(void 0);
760
557
  const [picked, setPicked] = (0, react.useState)(/* @__PURE__ */ new Set());
558
+ const [candidateQuery, setCandidateQuery] = (0, react.useState)("");
761
559
  const [expanded, setExpanded] = (0, react.useState)(/* @__PURE__ */ new Set());
762
560
  const [editing, setEditing] = (0, react.useState)(/* @__PURE__ */ new Map());
763
561
  /** Buffer key for one capacity field; the row half moves when rows do. */
@@ -799,27 +597,25 @@ window.__ModuleLoader__.load({
799
597
  setBusy(true);
800
598
  setFailure(void 0);
801
599
  try {
802
- const response = await api.llm.discoverModels({
803
- settingsNs: probe.settingsNs,
600
+ const answer = await operations.discoverModels(probe.settingsNs, {
804
601
  ...probe.provider === void 0 ? {} : { provider: probe.provider },
805
602
  ...probe.baseURL === void 0 || probe.baseURL.length === 0 ? {} : { baseURL: probe.baseURL },
806
603
  ...probe.api === void 0 ? {} : { api: props.thinkingPresets ? CLAUDE_DISCOVERY_API : probe.api },
807
604
  ...probe.apiKey === void 0 ? {} : { apiKey: probe.apiKey }
808
605
  });
809
- if (!response.result.ok) {
810
- setFailure(response.result.error.message);
606
+ if (answer.kind === "refused") {
607
+ setFailure(answer.message);
811
608
  return;
812
609
  }
813
- const found = response.result.value.models;
610
+ const found = answer.models;
814
611
  if (found.length === 0) {
815
612
  setFailure(t("fetchEmpty"));
816
613
  return;
817
614
  }
818
615
  const known = new Set(models.map((model) => textOf(model, "id")));
616
+ setCandidateQuery("");
819
617
  setCandidates(found);
820
618
  setPicked(new Set(found.filter((model) => !known.has(model.id)).map((model) => model.id)));
821
- } catch (error) {
822
- setFailure(messageOf(error));
823
619
  } finally {
824
620
  setBusy(false);
825
621
  }
@@ -827,6 +623,7 @@ window.__ModuleLoader__.load({
827
623
  const closePicker = () => {
828
624
  setCandidates(void 0);
829
625
  setPicked(/* @__PURE__ */ new Set());
626
+ setCandidateQuery("");
830
627
  };
831
628
  const adoptPicked = () => {
832
629
  /* v8 ignore next -- the dialog only renders with candidates loaded */
@@ -847,10 +644,15 @@ window.__ModuleLoader__.load({
847
644
  });
848
645
  };
849
646
  const activeCandidates = candidates ?? [];
850
- const allCandidatesPicked = activeCandidates.length > 0 && activeCandidates.every((candidate) => picked.has(candidate.id));
851
- const toggleAllCandidates = () => {
647
+ const normalizedCandidateQuery = candidateQuery.trim().toLowerCase();
648
+ const visibleCandidates = normalizedCandidateQuery.length === 0 ? activeCandidates : activeCandidates.filter((candidate) => candidate.id.toLowerCase().includes(normalizedCandidateQuery) || candidate.name?.toLowerCase().includes(normalizedCandidateQuery) === true);
649
+ const allVisibleCandidatesPicked = visibleCandidates.length > 0 && visibleCandidates.every((candidate) => picked.has(candidate.id));
650
+ const toggleVisibleCandidates = () => {
852
651
  setPicked((current) => {
853
- return activeCandidates.every((candidate) => current.has(candidate.id)) ? /* @__PURE__ */ new Set() : new Set(activeCandidates.map((candidate) => candidate.id));
652
+ const next = new Set(current);
653
+ if (visibleCandidates.every((candidate) => current.has(candidate.id))) for (const candidate of visibleCandidates) next.delete(candidate.id);
654
+ else for (const candidate of visibleCandidates) next.add(candidate.id);
655
+ return next;
854
656
  });
855
657
  };
856
658
  const askable = probe.provider !== void 0 || probe.baseURL !== void 0 && probe.baseURL.length > 0;
@@ -1034,17 +836,31 @@ window.__ModuleLoader__.load({
1034
836
  onClick: adoptPicked,
1035
837
  children: t("fetchAdopt")
1036
838
  })] }),
1037
- children: [(0, react_jsx_runtime.jsx)("div", {
1038
- className: ModelsSection_module_css_default["candidateActions"],
1039
- children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
839
+ children: [(0, react_jsx_runtime.jsxs)("div", {
840
+ className: ModelsSection_module_css_default["candidateToolbar"],
841
+ children: [(0, react_jsx_runtime.jsx)("input", {
842
+ className: `${ModelsSection_module_css_default["input"]} ${ModelsSection_module_css_default["candidateSearch"]}`,
843
+ type: "search",
844
+ value: candidateQuery,
845
+ placeholder: t("fetchSearch"),
846
+ "aria-label": t("fetchSearch"),
847
+ onChange: (event) => {
848
+ setCandidateQuery(event.target.value);
849
+ }
850
+ }), (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
1040
851
  variant: "ghost",
1041
852
  size: "sm",
1042
- onClick: toggleAllCandidates,
1043
- children: t(allCandidatesPicked ? "fetchDeselectAll" : "fetchSelectAll")
1044
- })
1045
- }), (0, react_jsx_runtime.jsx)("ul", {
853
+ disabled: visibleCandidates.length === 0,
854
+ onClick: toggleVisibleCandidates,
855
+ children: t(allVisibleCandidatesPicked ? "fetchDeselectAll" : "fetchSelectAll")
856
+ })]
857
+ }), visibleCandidates.length === 0 ? (0, react_jsx_runtime.jsx)("p", {
858
+ className: ModelsSection_module_css_default["candidateEmpty"],
859
+ role: "status",
860
+ children: t("fetchNoMatches")
861
+ }) : (0, react_jsx_runtime.jsx)("ul", {
1046
862
  className: ModelsSection_module_css_default["candidateList"],
1047
- children: (candidates ?? []).map((candidate) => (0, react_jsx_runtime.jsx)("li", {
863
+ children: visibleCandidates.map((candidate) => (0, react_jsx_runtime.jsx)("li", {
1048
864
  className: ModelsSection_module_css_default["candidate"],
1049
865
  children: (0, react_jsx_runtime.jsxs)("label", {
1050
866
  className: ModelsSection_module_css_default["candidateLabel"],
@@ -1066,6 +882,247 @@ window.__ModuleLoader__.load({
1066
882
  });
1067
883
  }
1068
884
  //#endregion
885
+ //#region lib/types/client/store.js
886
+ /**
887
+ * Models settings page store: one snapshot joining the configurable-provider
888
+ * directory (`llm/listProviders` joined with `llm/listConfigurableProviders`),
889
+ * the settings namespaces (shared settings mirror),
890
+ * and the referenced credentials (`credentials/describe`). The host stays the
891
+ * single fact source — every mutation writes through the wire and the page
892
+ * re-renders from the next describe, pushed or refetched.
893
+ */
894
+ /**
895
+ * Any route key walks a dict schema to the same profile node, so the lookup
896
+ * names one that cannot collide with a configured route.
897
+ */
898
+ const PROBE_ROUTE = "\0probe";
899
+ /**
900
+ * Join declared configurable providers with the currently registered routes.
901
+ * @param registered - live provider routes in registration order.
902
+ * @param directory - declared configurable providers in declaration order.
903
+ * @returns declared rows followed by live routes with no declaration.
904
+ */
905
+ function joinProviderDirectory(registered, directory) {
906
+ const active = new Set(registered.map((provider) => provider.id));
907
+ const declared = new Set(directory.map((entry) => entry.provider));
908
+ const rows = directory.map((entry) => ({
909
+ provider: entry.provider,
910
+ displayName: entry.displayName,
911
+ settingsNs: entry.settingsNs,
912
+ settingsPath: [...entry.settingsPath],
913
+ active: active.has(entry.provider),
914
+ ...entry.declared === void 0 ? {} : { declared: entry.declared }
915
+ }));
916
+ for (const provider of registered) {
917
+ if (declared.has(provider.id)) continue;
918
+ rows.push({
919
+ provider: provider.id,
920
+ displayName: provider.name,
921
+ settingsNs: "",
922
+ settingsPath: [],
923
+ active: true
924
+ });
925
+ }
926
+ return rows;
927
+ }
928
+ /**
929
+ * Derive the conventional credential reference for a provider route: the v1
930
+ * page never asks for an environment-variable name, so a typed key stores
931
+ * under this derived reference and the profile records it as `apiKeyEnv`.
932
+ * @param provider - provider route id (e.g. `anthropic`, `minimax-cn`).
933
+ * @returns the derived reference name (e.g. `MINIMAX_CN_API_KEY`).
934
+ */
935
+ function deriveKeyRef(provider) {
936
+ return `${provider.toUpperCase().replace(/[^A-Z0-9]+/g, "_")}_API_KEY`;
937
+ }
938
+ /**
939
+ * The wire protocols a hand-declared route may name, read out of the owning
940
+ * namespace's own schema. This stays a schema read rather than a wire field so
941
+ * the choices the page offers cannot drift from the ones the adapter accepts:
942
+ * both come from the same `Config`.
943
+ * @param namespace - the namespace view whose schema declares the profile shape.
944
+ * @param schema - settings schema operations.
945
+ * @returns the protocol identifiers, or an empty list when the schema has none.
946
+ */
947
+ function protocolChoices(namespace, schema) {
948
+ if (namespace === void 0) return [];
949
+ const list = schema.nodeAtPath(schema.rehydrate(namespace.schema), [
950
+ "providers",
951
+ PROBE_ROUTE,
952
+ "api"
953
+ ]);
954
+ if (list?.type !== "union" || list.list === void 0) return [];
955
+ return list.list.map((entry) => entry.value).filter((value) => typeof value === "string");
956
+ }
957
+ /** The credential reference a resolved profile names (its `apiKeyEnv` field). */
958
+ function apiKeyEnvOf(namespace, path, schema) {
959
+ if (namespace === void 0) return void 0;
960
+ const profile = schema.getPath(namespace.value, path);
961
+ if (typeof profile !== "object" || profile === null) return void 0;
962
+ const ref = profile.apiKeyEnv;
963
+ return typeof ref === "string" && ref.length > 0 ? ref : void 0;
964
+ }
965
+ /** The models settings page controller (one per settings surface). */
966
+ var ModelsSettingsStore = class {
967
+ ctx;
968
+ schema;
969
+ describeFace;
970
+ /** The snapshot the section renders from (uSES-safe store). */
971
+ store = (0, _deepseek_ai_dsh_client_store.createSnapshotStore)({
972
+ status: "idle",
973
+ error: null,
974
+ credentialError: null,
975
+ writable: false,
976
+ rows: [],
977
+ namespaces: /* @__PURE__ */ new Map()
978
+ });
979
+ /** Latest load wins; an older response never overwrites a newer one. */
980
+ generation = 0;
981
+ /**
982
+ * @param ctx - the page plugin's context, whose `remote.llm` and
983
+ * `remote.credentials` namespaces carry the directory and credential reads.
984
+ * @param schema - settings-owned schema and immutable path operations.
985
+ * @param describeFace - the shared mirror's describe face (namespace views and writability).
986
+ */
987
+ constructor(ctx, schema, describeFace) {
988
+ this.ctx = ctx;
989
+ this.schema = schema;
990
+ this.describeFace = describeFace;
991
+ }
992
+ /**
993
+ * Refresh the whole page snapshot: the provider directory and the mirror's
994
+ * settings answer in parallel, then one batched credential describe over
995
+ * every referenced ref. Provider failure or absence of an initial settings
996
+ * answer keeps the last good rows and surfaces an error; a failed settings
997
+ * refresh reuses the mirror's held view.
998
+ * @returns nothing; the snapshot carries the outcome.
999
+ */
1000
+ async load() {
1001
+ const generation = ++this.generation;
1002
+ this.store.update((s) => {
1003
+ s.status = "loading";
1004
+ s.error = null;
1005
+ });
1006
+ const [registered, declared] = await Promise.all([
1007
+ this.ctx.remote.llm.listProviders(),
1008
+ this.ctx.remote.llm.listConfigurableProviders(),
1009
+ this.describeFace.ensure()
1010
+ ]);
1011
+ if (!registered.ok) {
1012
+ this.failLoad(generation, registered.error.message);
1013
+ return;
1014
+ }
1015
+ if (!declared.ok) {
1016
+ this.failLoad(generation, declared.error.message);
1017
+ return;
1018
+ }
1019
+ const mirrored = this.describeFace.getSnapshot();
1020
+ if (mirrored.view === void 0) {
1021
+ this.failLoad(generation, mirrored.error ?? "settings are unavailable in this browser");
1022
+ return;
1023
+ }
1024
+ const providers = joinProviderDirectory(registered.value, declared.value);
1025
+ const writable = mirrored.view.writable;
1026
+ const views = mirrored.view.namespaces;
1027
+ const namespaces = new Map(views.map((view) => [view.ns, view]));
1028
+ const rows = providers.map((entry) => {
1029
+ const namespace = namespaces.get(entry.settingsNs);
1030
+ return {
1031
+ entry,
1032
+ configured: namespace !== void 0 && (entry.settingsPath.length === 0 || this.schema.getPath(namespace.value, entry.settingsPath) !== void 0),
1033
+ removable: namespace !== void 0 && entry.settingsPath.length > 0 && this.schema.hasPath(namespace.user, entry.settingsPath) && !this.schema.hasPath(namespace.base, entry.settingsPath),
1034
+ apiKeyEnv: apiKeyEnvOf(namespace, entry.settingsPath, this.schema),
1035
+ credential: void 0
1036
+ };
1037
+ });
1038
+ const refs = [...new Set(rows.map((row) => row.apiKeyEnv ?? deriveKeyRef(row.entry.provider)))];
1039
+ let credentials = {};
1040
+ let credentialError = null;
1041
+ if (refs.length > 0) {
1042
+ const response = await this.ctx.remote.credentials.describe(refs);
1043
+ if (response.ok) credentials = response.value;
1044
+ else credentialError = response.error.message;
1045
+ }
1046
+ if (generation !== this.generation) return;
1047
+ this.store.update((s) => {
1048
+ s.status = "ready";
1049
+ s.error = null;
1050
+ s.credentialError = credentialError;
1051
+ s.writable = writable;
1052
+ s.rows = rows.map((row) => {
1053
+ const named = row.apiKeyEnv === void 0 ? void 0 : credentials[row.apiKeyEnv];
1054
+ const derived = row.apiKeyEnv !== void 0 ? void 0 : credentials[deriveKeyRef(row.entry.provider)];
1055
+ return {
1056
+ ...row,
1057
+ ...named === void 0 ? {} : { credential: named },
1058
+ ...derived === void 0 ? {} : { derivedCredential: derived }
1059
+ };
1060
+ });
1061
+ s.namespaces = namespaces;
1062
+ });
1063
+ }
1064
+ /** Publish one load's failure text, unless a newer load already took over. */
1065
+ failLoad(generation, message) {
1066
+ if (generation !== this.generation) return;
1067
+ this.store.update((s) => {
1068
+ s.status = "error";
1069
+ s.error = message;
1070
+ });
1071
+ }
1072
+ };
1073
+ /**
1074
+ * Whether a joined row can serve model requests as it stands: the route is
1075
+ * registered with the adapter registry, and whatever credential its resolved
1076
+ * profile names is stored. A profile naming no reference authenticates through
1077
+ * the provider's own path (the Bedrock chain, Vertex ADC, a gateway that needs
1078
+ * nothing), as does a live route with no settings address at all, so neither
1079
+ * owes this page a key.
1080
+ * @param row - one joined provider row.
1081
+ * @returns whether the user already has this provider to talk to.
1082
+ */
1083
+ function providerUsable(row) {
1084
+ if (!row.entry.active) return false;
1085
+ if (row.apiKeyEnv === void 0) return true;
1086
+ return row.credential?.configured === true;
1087
+ }
1088
+ /**
1089
+ * Project first-run readiness from the provider/settings/credential join used
1090
+ * by the Models page. The step exists to leave the user with a model to talk
1091
+ * to, so ANY usable provider ends it; only when none exists does the official
1092
+ * DeepSeek route — the one route the prompt can offer a key field for — decide
1093
+ * whether prompting can help. A missing official configurable-provider
1094
+ * declaration means the adapter is not repairable by navigating to Models.
1095
+ * @param state - current shared Models join snapshot.
1096
+ * @returns the onboarding state without reading a parallel fact source.
1097
+ */
1098
+ function onboardingReadiness(state) {
1099
+ if ((state.status === "idle" || state.status === "loading") && state.rows.length === 0) return { kind: "loading" };
1100
+ if (state.status === "error") return {
1101
+ kind: "unavailable",
1102
+ reason: "load-failed"
1103
+ };
1104
+ if (state.rows.some(providerUsable)) return { kind: "provider-ready" };
1105
+ const row = state.rows.find((candidate) => candidate.entry.provider === "deepseek-official" && candidate.entry.settingsNs === "llm-deepseek" && candidate.entry.settingsPath.length === 0);
1106
+ if (row === void 0) return { kind: "adapter-absent" };
1107
+ if (!row.entry.active) return {
1108
+ kind: "unavailable",
1109
+ reason: "provider-inactive"
1110
+ };
1111
+ if (state.credentialError !== null || row.credential === void 0) return {
1112
+ kind: "unavailable",
1113
+ reason: "credentials-unavailable"
1114
+ };
1115
+ if (!state.writable) return {
1116
+ kind: "unavailable",
1117
+ reason: "settings-read-only"
1118
+ };
1119
+ if (!row.credential.writable) return {
1120
+ kind: "unavailable",
1121
+ reason: "credential-read-only"
1122
+ };
1123
+ return { kind: "credential-missing" };
1124
+ }
1125
+ //#endregion
1069
1126
  //#region lib/types/client/CustomProviderCard.js
1070
1127
  /**
1071
1128
  * The card that declares a provider pi-ai does not ship — an OpenAI-compatible
@@ -1076,7 +1133,7 @@ window.__ModuleLoader__.load({
1076
1133
  * the provider editor with extra fields: the route id is being *chosen* here,
1077
1134
  * and the settings address does not exist until it is. One `settings.mutate`
1078
1135
  * sets the whole profile at `providers.<route>`; the key travels separately
1079
- * through `credentials.set` under the reference the profile records, exactly as
1136
+ * through `credentials/set` under the reference the profile records, exactly as
1080
1137
  * an existing provider's key does.
1081
1138
  *
1082
1139
  * The three fields a hand-declared route cannot default — endpoint, protocol,
@@ -1106,7 +1163,7 @@ window.__ModuleLoader__.load({
1106
1163
  * @returns the creation card.
1107
1164
  */
1108
1165
  function CustomProviderCard(props) {
1109
- const { taken, protocols, api, t } = props;
1166
+ const { taken, protocols, operations, t } = props;
1110
1167
  const [openedAt] = (0, react.useState)(() => props.revision);
1111
1168
  const [route, setRoute] = (0, react.useState)("");
1112
1169
  const [displayName, setDisplayName] = (0, react.useState)("");
@@ -1147,31 +1204,25 @@ window.__ModuleLoader__.load({
1147
1204
  models: models.map((model) => isAdaptiveClaude ? withNativeClaudeModel(model) : { ...model }),
1148
1205
  ...isAdaptiveClaude ? { reasoning: "high" } : {}
1149
1206
  };
1150
- const response = await api.settings.mutate({
1151
- ns: NS$1,
1152
- ops: [{
1153
- op: "set",
1154
- path: ["providers", route],
1155
- value: profile
1156
- }],
1157
- expectedRevision: openedAt
1158
- });
1159
- if (!response.result.ok) return response.result.error.message;
1207
+ const written = await operations.writeSettings(NS$1, [{
1208
+ op: "set",
1209
+ path: ["providers", route],
1210
+ value: profile
1211
+ }], openedAt);
1212
+ if (written.kind !== "written") return written.kind === "conflict" ? t("conflict") : written.message;
1160
1213
  setCommitted(true);
1161
1214
  }
1162
1215
  if (isAdaptiveClaude) {
1163
- const typed = await api.settings.mutate({
1164
- ns: CLAUDE_PROVIDER_SETTINGS_NS,
1165
- ops: [{ op: "set", path: ["providerTypes", route], value: CLAUDE_PROVIDER_TYPE }]
1166
- });
1167
- if (!typed.result.ok) return typed.result.error.message;
1216
+ const typed = await operations.writeSettings(CLAUDE_PROVIDER_SETTINGS_NS, [{
1217
+ op: "set",
1218
+ path: ["providerTypes", route],
1219
+ value: CLAUDE_PROVIDER_TYPE
1220
+ }], void 0);
1221
+ if (typed.kind !== "written") return typed.kind === "conflict" ? t("conflict") : typed.message;
1168
1222
  }
1169
1223
  if (storesKey) {
1170
- const stored = await api.credentials.set({
1171
- ref: keyRef,
1172
- value: keyValue
1173
- });
1174
- if (!stored.result.ok) return stored.result.error.message;
1224
+ const stored = await operations.storeCredential(keyRef, keyValue);
1225
+ if (stored !== void 0) return stored;
1175
1226
  }
1176
1227
  };
1177
1228
  const create = async () => {
@@ -1184,8 +1235,6 @@ window.__ModuleLoader__.load({
1184
1235
  return;
1185
1236
  }
1186
1237
  props.onClose(true);
1187
- } catch (error) {
1188
- setFailure(messageOf(error));
1189
1238
  } finally {
1190
1239
  setBusy(false);
1191
1240
  }
@@ -1255,7 +1304,7 @@ window.__ModuleLoader__.load({
1255
1304
  className: ModelsSection_module_css_default["input"],
1256
1305
  type: "text",
1257
1306
  value: baseURL,
1258
- placeholder: "https://gateway.example/v1",
1307
+ placeholder: t("customBaseUrlPlaceholder"),
1259
1308
  "aria-label": t("baseUrl"),
1260
1309
  disabled: profileDisabled,
1261
1310
  onChange: (event) => {
@@ -1318,7 +1367,7 @@ window.__ModuleLoader__.load({
1318
1367
  },
1319
1368
  probeBlocked: keyFailure === "keyBlank" ? "keyBlankNew" : keyFailure,
1320
1369
  thinkingPresets: isAdaptiveClaude,
1321
- api,
1370
+ operations,
1322
1371
  t,
1323
1372
  disabled: profileDisabled
1324
1373
  }),
@@ -1334,8 +1383,8 @@ window.__ModuleLoader__.load({
1334
1383
  t,
1335
1384
  busy,
1336
1385
  submitDisabled: disabled || !ready,
1337
- submitLabel: "create",
1338
- submitBusyLabel: "creating",
1386
+ submitLabelKey: "create",
1387
+ submitBusyLabelKey: "creating",
1339
1388
  onCancel: () => {
1340
1389
  props.onClose(committed);
1341
1390
  },
@@ -1351,7 +1400,7 @@ window.__ModuleLoader__.load({
1351
1400
  /**
1352
1401
  * One provider's editor card, hand-written per adapter family: the primary
1353
1402
  * field is a single write-only **API key** input (the page never asks for an
1354
- * environment-variable name — a typed key stores through `credentials.set`
1403
+ * environment-variable name — a typed key stores through `credentials/set`
1355
1404
  * under the profile's reference, deriving `<ROUTE>_API_KEY` when the profile
1356
1405
  * has none. The pi-ai profile records that derivation as `apiKeyEnv` only when
1357
1406
  * a key is entered; a blank key materializes a reference-free profile for
@@ -1423,7 +1472,7 @@ window.__ModuleLoader__.load({
1423
1472
  * @returns the editor card.
1424
1473
  */
1425
1474
  function ProviderEditor(props) {
1426
- const { namespace, schema, settingsPath, api, t } = props;
1475
+ const { namespace, schema, settingsPath, operations, t } = props;
1427
1476
  const [draft, setDraft] = (0, react.useState)(() => draftAt(schema, namespace, settingsPath));
1428
1477
  const [keyDraft, setKeyDraft] = (0, react.useState)("");
1429
1478
  const [keyState, setKeyState] = (0, react.useState)(void 0);
@@ -1449,14 +1498,14 @@ window.__ModuleLoader__.load({
1449
1498
  (0, react.useEffect)(() => {
1450
1499
  let stale = false;
1451
1500
  setKeyState(void 0);
1452
- api.credentials.describe({ refs: [keyRef] }).then((response) => {
1453
- if (stale || !response.result.ok) return;
1454
- setKeyState(response.result.value.credentials[keyRef]);
1455
- }, () => void 0);
1501
+ operations.describeCredential(keyRef).then((described) => {
1502
+ if (stale) return;
1503
+ setKeyState(described);
1504
+ });
1456
1505
  return () => {
1457
1506
  stale = true;
1458
1507
  };
1459
- }, [api.credentials, keyRef]);
1508
+ }, [operations, keyRef]);
1460
1509
  const stringAt = (source, key) => {
1461
1510
  const value = schema.getPath(source, [key]);
1462
1511
  return typeof value === "string" && value.trim().length > 0 ? value : void 0;
@@ -1505,22 +1554,15 @@ window.__ModuleLoader__.load({
1505
1554
  value: {}
1506
1555
  }] : pathOps(settingsPath, committedOriginal, next);
1507
1556
  if (ops.length > 0) {
1508
- const response = await api.settings.mutate({
1509
- ns,
1510
- ops,
1511
- expectedRevision
1512
- });
1513
- if (!response.result.ok) return response.result.error.code === "settings-conflict" ? t("conflict") : response.result.error.message;
1514
- setCommittedOriginal(schema.getPath(response.result.value.user, settingsPath));
1515
- setExpectedRevision(response.result.value.revision);
1557
+ const written = await operations.writeSettings(ns, ops, expectedRevision);
1558
+ if (written.kind !== "written") return written.kind === "conflict" ? t("conflict") : written.message;
1559
+ setCommittedOriginal(schema.getPath(written.view.user, settingsPath));
1560
+ setExpectedRevision(written.view.revision);
1516
1561
  setDraft(next);
1517
1562
  }
1518
1563
  if (keyValue.length > 0) {
1519
- const stored = await api.credentials.set({
1520
- ref: keyRef,
1521
- value: keyValue
1522
- });
1523
- if (!stored.result.ok) return stored.result.error.message;
1564
+ const stored = await operations.storeCredential(keyRef, keyValue);
1565
+ if (stored !== void 0) return stored;
1524
1566
  }
1525
1567
  setKeyDraft("");
1526
1568
  };
@@ -1534,15 +1576,17 @@ window.__ModuleLoader__.load({
1534
1576
  return;
1535
1577
  }
1536
1578
  props.onClose(true);
1537
- } catch (error) {
1538
- setFailure(messageOf(error));
1539
1579
  } finally {
1540
1580
  setBusy(false);
1541
1581
  }
1542
1582
  };
1543
- if (node === void 0) return (0, react_jsx_runtime.jsx)("p", {
1583
+ if (node === void 0) return (0, react_jsx_runtime.jsxs)("p", {
1544
1584
  className: ModelsSection_module_css_default["error"],
1545
- children: `${props.provider}: unresolvable settings path`
1585
+ children: [
1586
+ props.provider,
1587
+ ": ",
1588
+ props.t("settingsPathUnresolvable")
1589
+ ]
1546
1590
  });
1547
1591
  const keyLocked = keyState?.writable === false;
1548
1592
  /**
@@ -1681,7 +1725,7 @@ window.__ModuleLoader__.load({
1681
1725
  probe,
1682
1726
  probeBlocked: keyFailure,
1683
1727
  thinkingPresets: props.thinkingPresets === true,
1684
- api
1728
+ operations
1685
1729
  })
1686
1730
  ]
1687
1731
  })]
@@ -1716,9 +1760,9 @@ window.__ModuleLoader__.load({
1716
1760
  t,
1717
1761
  busy,
1718
1762
  submitDisabled: disabled || layout === "unknown" || props.credentialOnly !== true && modelFailure !== void 0 || shownKeyFailure !== void 0 || props.credentialRequired === true && keyValue.length === 0,
1719
- submitLabel: props.submitLabel ?? "apply",
1720
- submitBusyLabel: props.submitBusyLabel ?? "applying",
1721
- ...props.cancelLabel === void 0 ? {} : { cancelLabel: props.cancelLabel },
1763
+ submitLabelKey: props.submitLabelKey ?? "apply",
1764
+ submitBusyLabelKey: props.submitBusyLabelKey ?? "applying",
1765
+ ...props.cancelLabelKey === void 0 ? {} : { cancelLabelKey: props.cancelLabelKey },
1722
1766
  onCancel: () => {
1723
1767
  props.onClose(false);
1724
1768
  },
@@ -1760,33 +1804,26 @@ window.__ModuleLoader__.load({
1760
1804
  * and the whole operation safely retryable; both unsets are idempotent.
1761
1805
  * The settings removal names the profile rather than rebuilding its whole
1762
1806
  * namespace from a partial view.
1763
- * @param api - settings and credential wire faces.
1807
+ * @param operations - the page's Host operations.
1764
1808
  * @param controller - the page store to refresh.
1765
1809
  * @param target - the provider's settings address and optional managed credential.
1766
1810
  * @returns the failure message, or undefined once the write and reload landed.
1767
1811
  */
1768
- async function removeProviderProfile(api, controller, target) {
1769
- try {
1770
- if (target.credentialRef !== void 0) {
1771
- const credential = await api.credentials.unset({ ref: target.credentialRef });
1772
- if (!credential.result.ok) return credential.result.error.message;
1773
- }
1774
- const response = await api.settings.mutate({
1775
- ns: target.settingsNs,
1776
- ops: [{
1777
- op: "unset",
1778
- path: [...target.settingsPath]
1779
- }]
1780
- });
1781
- if (!response.result.ok) return response.result.error.message;
1782
- const typeResponse = await api.settings.mutate({
1783
- ns: CLAUDE_PROVIDER_SETTINGS_NS,
1784
- ops: [{ op: "unset", path: ["providerTypes", target.provider] }]
1785
- });
1786
- if (!typeResponse.result.ok) return typeResponse.result.error.message;
1787
- } catch (error) {
1788
- return messageOf(error);
1812
+ async function removeProviderProfile(operations, controller, target) {
1813
+ if (target.credentialRef !== void 0) {
1814
+ const credential = await operations.removeCredential(target.credentialRef);
1815
+ if (credential !== void 0) return credential;
1789
1816
  }
1817
+ const written = await operations.writeSettings(target.settingsNs, [{
1818
+ op: "unset",
1819
+ path: [...target.settingsPath]
1820
+ }], void 0);
1821
+ if (written.kind !== "written") return written.message;
1822
+ const typedRemoval = await operations.writeSettings(CLAUDE_PROVIDER_SETTINGS_NS, [{
1823
+ op: "unset",
1824
+ path: ["providerTypes", target.provider]
1825
+ }], void 0);
1826
+ if (typedRemoval.kind !== "written") return typedRemoval.message;
1790
1827
  await controller.load();
1791
1828
  }
1792
1829
  /**
@@ -1803,6 +1840,16 @@ window.__ModuleLoader__.load({
1803
1840
  if (row.entry.settingsPath.length > 0) return false;
1804
1841
  return row.credential?.configured !== true;
1805
1842
  }
1843
+ /**
1844
+ * The provider-card seat's credential fact: the reference this page would use
1845
+ * for the row — the profile's `apiKeyEnv`, or the page's derived
1846
+ * `<ROUTE>_API_KEY` while the profile names none — confirmed configured. The
1847
+ * derived half is what keeps the seat consistent with the editor on the
1848
+ * add-provider draft, whose dormant row names no reference yet.
1849
+ */
1850
+ function keyConfiguredOf(row) {
1851
+ return row.apiKeyEnv !== void 0 ? row.credential?.configured === true : row.derivedCredential?.configured === true;
1852
+ }
1806
1853
  function targetOf(row) {
1807
1854
  const managedRef = deriveKeyRef(row.entry.provider);
1808
1855
  const credentialRef = row.apiKeyEnv === managedRef && row.credential?.configured === true && row.credential.writable ? managedRef : void 0;
@@ -1818,7 +1865,6 @@ window.__ModuleLoader__.load({
1818
1865
  const CLAUDE_DISCOVERY_API = "mofeng-anthropic-models";
1819
1866
  const CLAUDE_PROVIDER_SETTINGS_NS = "dsh-claude-provider";
1820
1867
  const CLAUDE_PROVIDER_TYPE = "claude-adaptive";
1821
- const CLAUDE_PROVIDER_DIRECTORY_SENTINEL = "dsh-claude-provider-type";
1822
1868
  const CLAUDE_FIVE_EFFORTS = Object.freeze({ low: "low", medium: "medium", high: "high", xhigh: "xhigh", max: "max" });
1823
1869
  const CLAUDE_FOUR_EFFORTS = Object.freeze({ low: "low", medium: "medium", high: "high", max: "max" });
1824
1870
  const CLAUDE_TOGGLE_EFFORTS = Object.freeze({ off: null, high: "high" });
@@ -1948,18 +1994,21 @@ window.__ModuleLoader__.load({
1948
1994
  * @returns the section, or null while the shell has not injected yet.
1949
1995
  */
1950
1996
  function ModelsSection(props) {
1951
- const { controller, useSnapshot, api, schema, t } = props;
1952
- if (controller === void 0 || useSnapshot === void 0 || api === void 0 || schema === void 0 || t === void 0) return null;
1953
- return (0, react_jsx_runtime.jsx)(Loaded, { injected: {
1954
- controller,
1955
- useSnapshot,
1956
- api,
1957
- schema,
1958
- t
1959
- } });
1997
+ const { controller, useSnapshot, operations, schema, t, renderSlot } = props;
1998
+ if (controller === void 0 || useSnapshot === void 0 || operations === void 0 || schema === void 0 || t === void 0) return null;
1999
+ return (0, react_jsx_runtime.jsx)(Loaded, {
2000
+ injected: {
2001
+ controller,
2002
+ useSnapshot,
2003
+ operations,
2004
+ schema,
2005
+ t
2006
+ },
2007
+ renderSlot
2008
+ });
1960
2009
  }
1961
- function Loaded({ injected }) {
1962
- const { controller, api, schema, t } = injected;
2010
+ function Loaded({ injected, renderSlot }) {
2011
+ const { controller, operations, schema, t } = injected;
1963
2012
  const state = injected.useSnapshot((snapshot) => snapshot);
1964
2013
  const [editing, setEditing] = (0, react.useState)(void 0);
1965
2014
  const [adding, setAdding] = (0, react.useState)(false);
@@ -2001,7 +2050,7 @@ window.__ModuleLoader__.load({
2001
2050
  if (deleteTarget === void 0 || deleting) return;
2002
2051
  setDeleting(true);
2003
2052
  setDeleteFailure(void 0);
2004
- removeProviderProfile(api, controller, deleteTarget).then((failure) => {
2053
+ removeProviderProfile(operations, controller, deleteTarget).then((failure) => {
2005
2054
  if (failure !== void 0) {
2006
2055
  setDeleteFailure(failure);
2007
2056
  return;
@@ -2040,6 +2089,7 @@ window.__ModuleLoader__.load({
2040
2089
  const addable = state.rows.filter((row) => !row.configured && row.entry.settingsNs !== "");
2041
2090
  const addTarget = adding ? editing : void 0;
2042
2091
  const addNamespace = addTarget === void 0 ? void 0 : state.namespaces.get(addTarget.settingsNs);
2092
+ const addRow = addTarget === void 0 ? void 0 : state.rows.find((row) => row.entry.provider === addTarget.provider);
2043
2093
  const protocols = protocolChoices(state.namespaces.get("llm-pi-ai"), schema);
2044
2094
  return (0, react_jsx_runtime.jsxs)("div", {
2045
2095
  className: ModelsSection_module_css_default["section"],
@@ -2069,20 +2119,24 @@ window.__ModuleLoader__.load({
2069
2119
  const namespace = state.namespaces.get(target.settingsNs);
2070
2120
  /* v8 ignore next -- the join marks a row configured only when its namespace resolved */
2071
2121
  if (namespace === void 0) return null;
2072
- if (needsSetup(row, anyUsable) && !dismissedSetup.has(row.entry.provider)) return (0, react_jsx_runtime.jsx)("li", {
2122
+ if (needsSetup(row, anyUsable) && !dismissedSetup.has(row.entry.provider)) return (0, react_jsx_runtime.jsxs)("li", {
2073
2123
  className: ModelsSection_module_css_default["setupCard"],
2074
- children: renderProviderEditor({
2124
+ children: [renderProviderEditor({
2075
2125
  target,
2076
2126
  namespace,
2077
2127
  schema,
2078
2128
  thinkingPresets: isClaudeProvider(row, state),
2079
- api,
2129
+ operations,
2080
2130
  t,
2081
2131
  readOnly: !state.writable,
2082
2132
  onClose: (changed) => {
2083
2133
  closeSetup(changed, target);
2084
2134
  }
2085
- })
2135
+ }), renderSlot("settings.models.provider-card", {
2136
+ provider: row.entry,
2137
+ configured: row.configured,
2138
+ keyConfigured: keyConfiguredOf(row)
2139
+ }, { entryKey: row.entry.settingsNs })]
2086
2140
  }, row.entry.provider);
2087
2141
  const open = !adding && editing?.provider === row.entry.provider;
2088
2142
  const adaptiveClaude = isClaudeProvider(row, state);
@@ -2090,73 +2144,81 @@ window.__ModuleLoader__.load({
2090
2144
  const credentialMissing = !credentialConfigured && row.apiKeyEnv !== void 0 && row.credential?.configured === false;
2091
2145
  return (0, react_jsx_runtime.jsxs)("li", {
2092
2146
  className: ModelsSection_module_css_default["rowCard"],
2093
- children: [(0, react_jsx_runtime.jsxs)("div", {
2094
- className: ModelsSection_module_css_default["rowHead"],
2095
- children: [(0, react_jsx_runtime.jsxs)("span", {
2096
- className: ModelsSection_module_css_default["rowIdentity"],
2097
- children: [
2098
- (0, react_jsx_runtime.jsx)("span", {
2099
- className: ModelsSection_module_css_default["rowName"],
2100
- children: row.entry.displayName
2101
- }),
2102
- row.entry.declared === true ? (0, react_jsx_runtime.jsx)("span", {
2103
- className: ModelsSection_module_css_default["rowTag"],
2104
- children: t("customTag")
2105
- }) : null,
2106
- adaptiveClaude ? (0, react_jsx_runtime.jsx)("span", {
2107
- className: ModelsSection_module_css_default["rowTag"],
2108
- children: t("claudeTypeTag")
2109
- }) : null,
2110
- credentialConfigured ? (0, react_jsx_runtime.jsx)("span", {
2111
- className: `${ModelsSection_module_css_default["credentialDot"]} ${ModelsSection_module_css_default["credentialDotConfigured"]}`,
2112
- role: "img",
2113
- "aria-label": t("credentialConfigured"),
2114
- title: t("credentialConfigured")
2115
- }) : credentialMissing ? (0, react_jsx_runtime.jsx)("span", {
2116
- className: `${ModelsSection_module_css_default["credentialDot"]} ${ModelsSection_module_css_default["credentialDotMissing"]}`,
2117
- role: "img",
2118
- "aria-label": t("credentialMissing"),
2119
- title: t("credentialMissing")
2120
- }) : null
2121
- ]
2122
- }), (0, react_jsx_runtime.jsxs)("span", {
2123
- className: ModelsSection_module_css_default["rowActions"],
2124
- children: [(0, react_jsx_runtime.jsx)("button", {
2125
- type: "button",
2126
- className: ModelsSection_module_css_default["secondaryButton"],
2127
- "aria-label": providerCopy(t("editProvider"), target),
2128
- onClick: () => {
2129
- setSavedTarget(void 0);
2130
- setDeclaringType(void 0);
2131
- setAdding(false);
2132
- setEditing(open ? void 0 : target);
2133
- },
2134
- children: t("edit")
2135
- }), row.removable ? (0, react_jsx_runtime.jsx)("button", {
2136
- type: "button",
2137
- className: ModelsSection_module_css_default["dangerButton"],
2138
- "aria-label": providerCopy(t("removeProvider"), target),
2139
- disabled: !state.writable,
2140
- onClick: () => {
2141
- setSavedTarget(void 0);
2142
- setDeleteFailure(void 0);
2143
- setDeleteTarget(target);
2144
- },
2145
- children: t("remove")
2146
- }) : null]
2147
- })]
2148
- }), open ? renderProviderEditor({
2149
- target,
2150
- namespace,
2151
- schema,
2152
- thinkingPresets: isClaudeProvider(row, state),
2153
- api,
2154
- t,
2155
- readOnly: !state.writable,
2156
- onClose: (changed) => {
2157
- closeEditor(changed, target);
2158
- }
2159
- }) : null]
2147
+ children: [
2148
+ (0, react_jsx_runtime.jsxs)("div", {
2149
+ className: ModelsSection_module_css_default["rowHead"],
2150
+ children: [(0, react_jsx_runtime.jsxs)("span", {
2151
+ className: ModelsSection_module_css_default["rowIdentity"],
2152
+ children: [
2153
+ (0, react_jsx_runtime.jsx)("span", {
2154
+ className: ModelsSection_module_css_default["rowName"],
2155
+ children: row.entry.displayName
2156
+ }),
2157
+ row.entry.declared === true ? (0, react_jsx_runtime.jsx)("span", {
2158
+ className: ModelsSection_module_css_default["rowTag"],
2159
+ children: t("customTag")
2160
+ }) : null,
2161
+ adaptiveClaude ? (0, react_jsx_runtime.jsx)("span", {
2162
+ className: ModelsSection_module_css_default["rowTag"],
2163
+ children: t("claudeTypeTag")
2164
+ }) : null,
2165
+ credentialConfigured ? (0, react_jsx_runtime.jsx)("span", {
2166
+ className: `${ModelsSection_module_css_default["credentialDot"]} ${ModelsSection_module_css_default["credentialDotConfigured"]}`,
2167
+ role: "img",
2168
+ "aria-label": t("credentialConfigured"),
2169
+ title: t("credentialConfigured")
2170
+ }) : credentialMissing ? (0, react_jsx_runtime.jsx)("span", {
2171
+ className: `${ModelsSection_module_css_default["credentialDot"]} ${ModelsSection_module_css_default["credentialDotMissing"]}`,
2172
+ role: "img",
2173
+ "aria-label": t("credentialMissing"),
2174
+ title: t("credentialMissing")
2175
+ }) : null
2176
+ ]
2177
+ }), (0, react_jsx_runtime.jsxs)("span", {
2178
+ className: ModelsSection_module_css_default["rowActions"],
2179
+ children: [(0, react_jsx_runtime.jsx)("button", {
2180
+ type: "button",
2181
+ className: ModelsSection_module_css_default["secondaryButton"],
2182
+ "aria-label": providerCopy(t("editProvider"), target),
2183
+ onClick: () => {
2184
+ setSavedTarget(void 0);
2185
+ setDeclaringType(void 0);
2186
+ setAdding(false);
2187
+ setEditing(open ? void 0 : target);
2188
+ },
2189
+ children: t("edit")
2190
+ }), row.removable ? (0, react_jsx_runtime.jsx)("button", {
2191
+ type: "button",
2192
+ className: ModelsSection_module_css_default["dangerButton"],
2193
+ "aria-label": providerCopy(t("removeProvider"), target),
2194
+ disabled: !state.writable,
2195
+ onClick: () => {
2196
+ setSavedTarget(void 0);
2197
+ setDeleteFailure(void 0);
2198
+ setDeleteTarget(target);
2199
+ },
2200
+ children: t("remove")
2201
+ }) : null]
2202
+ })]
2203
+ }),
2204
+ renderSlot("settings.models.provider-card", {
2205
+ provider: row.entry,
2206
+ configured: row.configured,
2207
+ keyConfigured: keyConfiguredOf(row)
2208
+ }, { entryKey: row.entry.settingsNs }),
2209
+ open ? renderProviderEditor({
2210
+ target,
2211
+ namespace,
2212
+ schema,
2213
+ thinkingPresets: isClaudeProvider(row, state),
2214
+ operations,
2215
+ t,
2216
+ readOnly: !state.writable,
2217
+ onClose: (changed) => {
2218
+ closeEditor(changed, target);
2219
+ }
2220
+ }) : null
2221
+ ]
2160
2222
  }, row.entry.provider);
2161
2223
  })
2162
2224
  }),
@@ -2164,40 +2226,48 @@ window.__ModuleLoader__.load({
2164
2226
  className: ModelsSection_module_css_default["addBlock"],
2165
2227
  children: addTarget !== void 0 && addNamespace !== void 0 ? (0, react_jsx_runtime.jsxs)("div", {
2166
2228
  className: ModelsSection_module_css_default["addCard"],
2167
- children: [(0, react_jsx_runtime.jsxs)("div", {
2168
- className: ModelsSection_module_css_default["field"],
2169
- children: [(0, react_jsx_runtime.jsx)("span", {
2170
- className: ModelsSection_module_css_default["fieldLabel"],
2171
- children: t("provider")
2172
- }), (0, react_jsx_runtime.jsx)("select", {
2173
- className: `${ModelsSection_module_css_default["input"]} ${ModelsSection_module_css_default["selectInput"]}`,
2174
- value: addTarget.provider,
2175
- "aria-label": t("provider"),
2176
- onChange: (event) => {
2177
- const row = addable.find((candidate) => candidate.entry.provider === event.target.value);
2178
- /* v8 ignore next -- the select only lists addable rows */
2179
- if (row === void 0) return;
2180
- setEditing(targetOf(row));
2181
- },
2182
- children: addable.map((row) => (0, react_jsx_runtime.jsx)("option", {
2183
- value: row.entry.provider,
2184
- children: row.entry.displayName
2185
- }, row.entry.provider))
2186
- })]
2187
- }), (0, react_jsx_runtime.jsx)(ProviderEditor, {
2188
- provider: addTarget.provider,
2189
- displayName: addTarget.displayName,
2190
- hideTitle: true,
2191
- namespace: addNamespace,
2192
- schema,
2193
- settingsPath: addTarget.settingsPath,
2194
- api,
2195
- t,
2196
- readOnly: !state.writable,
2197
- onClose: (changed) => {
2198
- closeEditor(changed, addTarget);
2199
- }
2200
- }, addTarget.provider)]
2229
+ children: [
2230
+ (0, react_jsx_runtime.jsxs)("div", {
2231
+ className: ModelsSection_module_css_default["field"],
2232
+ children: [(0, react_jsx_runtime.jsx)("span", {
2233
+ className: ModelsSection_module_css_default["fieldLabel"],
2234
+ children: t("provider")
2235
+ }), (0, react_jsx_runtime.jsx)("select", {
2236
+ className: `${ModelsSection_module_css_default["input"]} ${ModelsSection_module_css_default["selectInput"]}`,
2237
+ value: addTarget.provider,
2238
+ "aria-label": t("provider"),
2239
+ onChange: (event) => {
2240
+ const row = addable.find((candidate) => candidate.entry.provider === event.target.value);
2241
+ /* v8 ignore next -- the select only lists addable rows */
2242
+ if (row === void 0) return;
2243
+ setEditing(targetOf(row));
2244
+ },
2245
+ children: addable.map((row) => (0, react_jsx_runtime.jsx)("option", {
2246
+ value: row.entry.provider,
2247
+ children: row.entry.displayName
2248
+ }, row.entry.provider))
2249
+ })]
2250
+ }),
2251
+ (0, react_jsx_runtime.jsx)(ProviderEditor, {
2252
+ provider: addTarget.provider,
2253
+ displayName: addTarget.displayName,
2254
+ hideTitle: true,
2255
+ namespace: addNamespace,
2256
+ schema,
2257
+ settingsPath: addTarget.settingsPath,
2258
+ operations,
2259
+ t,
2260
+ readOnly: !state.writable,
2261
+ onClose: (changed) => {
2262
+ closeEditor(changed, addTarget);
2263
+ }
2264
+ }, addTarget.provider),
2265
+ addRow === void 0 ? null : renderSlot("settings.models.provider-card", {
2266
+ provider: addRow.entry,
2267
+ configured: addRow.configured,
2268
+ keyConfigured: keyConfiguredOf(addRow)
2269
+ }, { entryKey: addRow.entry.settingsNs })
2270
+ ]
2201
2271
  }) : declaringType !== void 0 ? (0, react_jsx_runtime.jsx)("div", {
2202
2272
  className: ModelsSection_module_css_default["addCard"],
2203
2273
  children: (0, react_jsx_runtime.jsx)(CustomProviderCard, {
@@ -2206,7 +2276,7 @@ window.__ModuleLoader__.load({
2206
2276
  providerType: declaringType,
2207
2277
  /* v8 ignore next -- the card only opens from a button disabled without this namespace */
2208
2278
  revision: state.namespaces.get("llm-pi-ai")?.revision ?? 0,
2209
- api,
2279
+ operations,
2210
2280
  t,
2211
2281
  readOnly: !state.writable,
2212
2282
  onClose: (changed) => {
@@ -2255,6 +2325,7 @@ window.__ModuleLoader__.load({
2255
2325
  })]
2256
2326
  })
2257
2327
  }),
2328
+ renderSlot("settings.models.footer", {}),
2258
2329
  (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Modal, {
2259
2330
  open: deleteTarget !== void 0,
2260
2331
  onClose: closeDelete,
@@ -2380,7 +2451,7 @@ window.__ModuleLoader__.load({
2380
2451
  * @returns the onboarding modal or null when onboarding needs no intervention.
2381
2452
  */
2382
2453
  function DeepSeekOnboardingDialog(props) {
2383
- const { complete, controller, useModels, api, schema, t } = props;
2454
+ const { complete, controller, useModels, operations, schema, t } = props;
2384
2455
  const state = useModels((snapshot) => snapshot);
2385
2456
  const readiness = onboardingReadiness(state);
2386
2457
  (0, react.useEffect)(() => {
@@ -2422,16 +2493,16 @@ window.__ModuleLoader__.load({
2422
2493
  namespace,
2423
2494
  schema,
2424
2495
  settingsPath: row.entry.settingsPath,
2425
- api,
2496
+ operations,
2426
2497
  t,
2427
2498
  readOnly: false,
2428
2499
  hideTitle: true,
2429
2500
  credentialOnly: true,
2430
2501
  credentialRequired: true,
2431
2502
  autoFocusCredential: true,
2432
- cancelLabel: "onboardingLater",
2433
- submitLabel: "onboardingSave",
2434
- submitBusyLabel: "onboardingSaving",
2503
+ cancelLabelKey: "onboardingLater",
2504
+ submitLabelKey: "onboardingSave",
2505
+ submitBusyLabelKey: "onboardingSaving",
2435
2506
  onClose: finishCredential
2436
2507
  })
2437
2508
  })]
@@ -2521,19 +2592,6 @@ window.__ModuleLoader__.load({
2521
2592
  * again. The acknowledgement is compared for exact equality.
2522
2593
  */
2523
2594
  const WELCOME_NOTICE_VERSION = "2026-08-13.1";
2524
- /** The complete editable internal-testing notice in both supported GUI locales. */
2525
- const WELCOME_NOTICE_COPY = {
2526
- zh: {
2527
- title: "内测声明",
2528
- body: "DeepSeek Harness 目前的 0.1 版本仍处在面向 Harness 开发者进行测试的阶段,还有许多地方需要持续改进和打磨,希望听取广大开发者的反馈建议。预计 DeepSeek Harness 的核心插件以及基础 API 都会在接下来的一段时间内快速迭代、持续演化。\n\n我们期待与全球开发者一起,在开源、开放、可复用、可组合的基础设施之上,共同探索智能上限。欢迎全球 Harness 开发者加入 DSH 插件生态。",
2529
- continueLabel: "继续"
2530
- },
2531
- en: {
2532
- title: "Internal Testing Notice",
2533
- body: "DeepSeek Harness 0.1 remains in testing for Harness developers. Many areas need further improvement, and we welcome feedback from the developer community. DeepSeek Harness's core plugins and foundational APIs will continue to evolve rapidly over the coming months.\n\nWe look forward to exploring the limits of intelligence with developers around the world, building on open-source, open, reusable, and composable infrastructure. We welcome Harness developers everywhere to join the DSH plugin ecosystem.",
2534
- continueLabel: "Continue"
2535
- }
2536
- };
2537
2595
  //#endregion
2538
2596
  //#region lib/types/client/welcome-store.js
2539
2597
  /**
@@ -2560,7 +2618,7 @@ window.__ModuleLoader__.load({
2560
2618
  var WelcomeNoticeStore = class {
2561
2619
  scope;
2562
2620
  /** uSES-safe state source shared by the registered welcome step. */
2563
- store = (0, _deepseek_ai_dsh_client_runtime_client.createSnapshotStore)({
2621
+ store = (0, _deepseek_ai_dsh_client_store.createSnapshotStore)({
2564
2622
  status: "idle",
2565
2623
  acknowledged: false,
2566
2624
  error: null
@@ -2661,6 +2719,61 @@ window.__ModuleLoader__.load({
2661
2719
  }
2662
2720
  };
2663
2721
  //#endregion
2722
+ //#region lib/types/client/operations.js
2723
+ /**
2724
+ * The Host reads and writes the Models cards perform, as callbacks built in the
2725
+ * plugin body. Cards receive these instead of a context: the outcomes name what
2726
+ * a card renders — a stored view, a stale revision, a refusal message — so the
2727
+ * failure codes and Remote namespaces stay in the apply world.
2728
+ */
2729
+ /**
2730
+ * Bind the page's Host operations to the plugin's own Remote namespaces.
2731
+ * @param ctx - the page plugin's context, which declares `remote.credentials`,
2732
+ * `remote.llm`, and `remote.settings` in its own `inject`.
2733
+ * @returns the callbacks the section and its cards are injected with.
2734
+ */
2735
+ function createModelsOperations(ctx) {
2736
+ return {
2737
+ describeCredential: async (ref) => {
2738
+ const response = await ctx.remote.credentials.describe([ref]);
2739
+ return response.ok ? response.value[ref] : void 0;
2740
+ },
2741
+ storeCredential: async (ref, value) => {
2742
+ const response = await ctx.remote.credentials.set(ref, value);
2743
+ return response.ok ? void 0 : response.error.message;
2744
+ },
2745
+ removeCredential: async (ref) => {
2746
+ const response = await ctx.remote.credentials.unset(ref);
2747
+ return response.ok ? void 0 : response.error.message;
2748
+ },
2749
+ writeSettings: async (ns, ops, expectedRevision) => {
2750
+ const response = await ctx.remote.settings.mutate(ns, ops, expectedRevision);
2751
+ if (response.ok) return {
2752
+ kind: "written",
2753
+ view: response.value
2754
+ };
2755
+ const { code, message } = response.error;
2756
+ return code === "settings/conflict" ? {
2757
+ kind: "conflict",
2758
+ message
2759
+ } : {
2760
+ kind: "refused",
2761
+ message
2762
+ };
2763
+ },
2764
+ discoverModels: async (settingsNs, request) => {
2765
+ const response = await ctx.remote.llm.discoverModels(settingsNs, request);
2766
+ return response.ok ? {
2767
+ kind: "found",
2768
+ models: response.value
2769
+ } : {
2770
+ kind: "refused",
2771
+ message: response.error.message
2772
+ };
2773
+ }
2774
+ };
2775
+ }
2776
+ //#endregion
2664
2777
  //#region lib/types/client/schema-operations.js
2665
2778
  /**
2666
2779
  * Hide the Cordis service identity behind bound schema callbacks.
@@ -2751,6 +2864,8 @@ window.__ModuleLoader__.load({
2751
2864
  fetchEmpty: "The provider listed no models. Add them by hand.",
2752
2865
  fetchTitle: "Choose models to add",
2753
2866
  fetchDescription: "These are the models this provider has available. Choose the ones to add.",
2867
+ fetchSearch: "Search models",
2868
+ fetchNoMatches: "No matching models.",
2754
2869
  fetchSelectAll: "Select all",
2755
2870
  fetchDeselectAll: "Deselect all",
2756
2871
  fetchAdopt: "Add selected",
@@ -2779,11 +2894,13 @@ window.__ModuleLoader__.load({
2779
2894
  customApiUnset: "Not selected",
2780
2895
  customNeedsBaseUrl: "A custom provider needs a base URL.",
2781
2896
  customNeedsModels: "A custom provider needs at least one model.",
2897
+ customBaseUrlPlaceholder: "https://gateway.example/v1",
2898
+ settingsPathUnresolvable: "unresolvable settings path",
2782
2899
  create: "Create provider",
2783
2900
  creating: "Creating…",
2784
- welcomeTitle: WELCOME_NOTICE_COPY.en.title,
2785
- welcomeBody: WELCOME_NOTICE_COPY.en.body,
2786
- welcomeContinue: WELCOME_NOTICE_COPY.en.continueLabel,
2901
+ welcomeTitle: "Internal Testing Notice",
2902
+ welcomeBody: "DeepSeek Harness 0.1 remains in testing for Harness developers. Many areas need further improvement, and we welcome feedback from the developer community. DeepSeek Harness's core plugins and foundational APIs will continue to evolve rapidly over the coming months.\n\nWe look forward to exploring the limits of intelligence with developers around the world, building on open-source, open, reusable, and composable infrastructure. We welcome Harness developers everywhere to join the DSH plugin ecosystem.",
2903
+ welcomeContinue: "Continue",
2787
2904
  welcomeError: "The acknowledgement could not be saved. Please try again.",
2788
2905
  onboardingTitle: "Add an API key to get started",
2789
2906
  onboardingDescription: "Configure the official DeepSeek provider to start building.",
@@ -2862,6 +2979,8 @@ window.__ModuleLoader__.load({
2862
2979
  fetchEmpty: "该提供方没有列出任何模型,请手动添加。",
2863
2980
  fetchTitle: "选择要添加的模型",
2864
2981
  fetchDescription: "以下是模型提供方的可用模型,勾选要添加的模型。",
2982
+ fetchSearch: "搜索模型",
2983
+ fetchNoMatches: "没有匹配的模型。",
2865
2984
  fetchSelectAll: "全选",
2866
2985
  fetchDeselectAll: "取消全选",
2867
2986
  fetchAdopt: "添加所选",
@@ -2890,11 +3009,13 @@ window.__ModuleLoader__.load({
2890
3009
  customApiUnset: "未选择",
2891
3010
  customNeedsBaseUrl: "自定义提供方需要填写 API 地址。",
2892
3011
  customNeedsModels: "自定义提供方至少需要一个模型。",
3012
+ customBaseUrlPlaceholder: "https://gateway.example/v1",
3013
+ settingsPathUnresolvable: "无法解析设置路径",
2893
3014
  create: "创建提供方",
2894
3015
  creating: "创建中…",
2895
- welcomeTitle: WELCOME_NOTICE_COPY.zh.title,
2896
- welcomeBody: WELCOME_NOTICE_COPY.zh.body,
2897
- welcomeContinue: WELCOME_NOTICE_COPY.zh.continueLabel,
3016
+ welcomeTitle: "内测声明",
3017
+ welcomeBody: "DeepSeek Harness 目前的 0.1 版本仍处在面向 Harness 开发者进行测试的阶段,还有许多地方需要持续改进和打磨,希望听取广大开发者的反馈建议。预计 DeepSeek Harness 的核心插件以及基础 API 都会在接下来的一段时间内快速迭代、持续演化。\n\n我们期待与全球开发者一起,在开源、开放、可复用、可组合的基础设施之上,共同探索智能上限。欢迎全球 Harness 开发者加入 DSH 插件生态。",
3018
+ welcomeContinue: "继续",
2898
3019
  welcomeError: "暂时无法保存确认状态,请重试。",
2899
3020
  onboardingTitle: "添加一个 API Key 开始使用",
2900
3021
  onboardingDescription: "配置 DeepSeek 官方模型,即可开始使用。",
@@ -2924,8 +3045,10 @@ window.__ModuleLoader__.load({
2924
3045
  const inject = [
2925
3046
  "slots",
2926
3047
  "locale",
2927
- "connection",
2928
3048
  "remote",
3049
+ "remote.credentials",
3050
+ "remote.llm",
3051
+ "remote.settings",
2929
3052
  "settingsScope",
2930
3053
  "settingsSchema"
2931
3054
  ];
@@ -2940,21 +3063,21 @@ window.__ModuleLoader__.load({
2940
3063
  zh,
2941
3064
  en
2942
3065
  }), "ui-settings-models: copy dictionaries");
2943
- const connection = ctx.get("connection");
2944
3066
  const schema = createSettingsSchemaOperations(ctx.settingsSchema);
2945
- const controller = new ModelsSettingsStore(connection.api, schema, ctx.settingsScope.describe());
3067
+ const operations = createModelsOperations(ctx);
3068
+ const controller = new ModelsSettingsStore(ctx, schema, ctx.settingsScope.describe());
2946
3069
  const t = ctx.locale.bind(NS);
2947
3070
  const injected = () => ({
2948
3071
  controller,
2949
3072
  hooks: { snapshot: controller.store },
2950
- api: connection.api,
3073
+ operations,
2951
3074
  schema,
2952
3075
  t
2953
3076
  });
2954
3077
  const deepSeekOnboardingInjected = () => ({
2955
3078
  controller,
2956
3079
  hooks: { models: controller.store },
2957
- api: connection.api,
3080
+ operations,
2958
3081
  schema,
2959
3082
  t
2960
3083
  });
@@ -2990,7 +3113,17 @@ window.__ModuleLoader__.load({
2990
3113
  id: "models",
2991
3114
  order: 10,
2992
3115
  label: () => t("nav"),
2993
- inject: injected
3116
+ inject: injected,
3117
+ children: {
3118
+ "settings.models.provider-card": {
3119
+ kind: "keyed",
3120
+ scope: "root"
3121
+ },
3122
+ "settings.models.footer": {
3123
+ kind: "list",
3124
+ scope: "root"
3125
+ }
3126
+ }
2994
3127
  }, ModelsSection));
2995
3128
  ctx.slots.inject("settings.onboarding", () => ctx.slots.register({
2996
3129
  name: "settings.onboarding",