@deepseek-ai/dsh-client-ui-settings-models 0.1.1-rc.2 → 0.1.2-alpha.2

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
@@ -7,7 +7,7 @@ window.__ModuleLoader__.load({
7
7
  let react_jsx_runtime = require("react/jsx-runtime");
8
8
  let react = require("react");
9
9
  let _deepseek_ai_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
10
- let _deepseek_ai_dsh_client_runtime_client = require("@deepseek-ai/dsh-client-runtime/client");
10
+ let _deepseek_ai_dsh_client_store = require("@deepseek-ai/dsh-client-store");
11
11
  //#region lib/types/client/apiKey.js
12
12
  /**
13
13
  * Browser-side judgement of a typed API key.
@@ -55,7 +55,7 @@ window.__ModuleLoader__.load({
55
55
  }
56
56
  //#endregion
57
57
  //#region \0dsh-css:/home/runner/work/deepseek-harness/deepseek-harness/packages/client/ui-settings-models/src/client/ModelsSection.module.css.mjs
58
- 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}";
58
+ 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,.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_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
59
  const tagId$3 = "@deepseek-ai/dsh-client-ui-settings-models/ModelsSection.module.css";
60
60
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$3) + "]") === null) {
61
61
  const tag = document.createElement("style");
@@ -126,6 +126,7 @@ window.__ModuleLoader__.load({
126
126
  "section": "zGbnIq_section",
127
127
  "selectInput": "zGbnIq_selectInput",
128
128
  "setupCard": "zGbnIq_setupCard",
129
+ "switchThumb": "zGbnIq_switchThumb",
129
130
  "title": "zGbnIq_title"
130
131
  };
131
132
  //#endregion
@@ -144,13 +145,13 @@ window.__ModuleLoader__.load({
144
145
  className: ModelsSection_module_css_default["secondaryButton"],
145
146
  disabled: props.busy,
146
147
  onClick: props.onCancel,
147
- children: t(props.cancelLabel ?? "cancel")
148
+ children: t(props.cancelLabelKey ?? "cancel")
148
149
  }), (0, react_jsx_runtime.jsx)("button", {
149
150
  type: "button",
150
151
  className: ModelsSection_module_css_default["primaryButton"],
151
152
  disabled: props.submitDisabled,
152
153
  onClick: props.onSubmit,
153
- children: props.busy ? t(props.submitBusyLabel) : t(props.submitLabel)
154
+ children: props.busy ? t(props.submitBusyLabelKey) : t(props.submitLabelKey)
154
155
  })]
155
156
  });
156
157
  }
@@ -442,212 +443,6 @@ window.__ModuleLoader__.load({
442
443
  });
443
444
  }
444
445
  //#endregion
445
- //#region lib/types/client/store.js
446
- /**
447
- * Models settings page store: one snapshot joining the configurable-provider
448
- * directory (`llm.providers`), the settings namespaces (shared settings mirror),
449
- * and the referenced credentials (`credentials.describe`). The host stays the
450
- * single fact source — every mutation writes through the wire and the page
451
- * re-renders from the next describe, pushed or refetched.
452
- */
453
- /**
454
- * Any route key walks a dict schema to the same profile node, so the lookup
455
- * names one that cannot collide with a configured route.
456
- */
457
- const PROBE_ROUTE = "\0probe";
458
- /**
459
- * Human text for a rejected wire call. A transport failure rejects with an
460
- * Error; a host or a runtime can reject with anything, and the page still has
461
- * to say something.
462
- * @param error - the rejection value.
463
- * @returns the message to show.
464
- */
465
- function messageOf(error) {
466
- return error instanceof Error ? error.message : String(error);
467
- }
468
- /**
469
- * Derive the conventional credential reference for a provider route: the v1
470
- * page never asks for an environment-variable name, so a typed key stores
471
- * under this derived reference and the profile records it as `apiKeyEnv`.
472
- * @param provider - provider route id (e.g. `anthropic`, `minimax-cn`).
473
- * @returns the derived reference name (e.g. `MINIMAX_CN_API_KEY`).
474
- */
475
- function deriveKeyRef(provider) {
476
- return `${provider.toUpperCase().replace(/[^A-Z0-9]+/g, "_")}_API_KEY`;
477
- }
478
- /**
479
- * The wire protocols a hand-declared route may name, read out of the owning
480
- * namespace's own schema. This stays a schema read rather than a wire field so
481
- * the choices the page offers cannot drift from the ones the adapter accepts:
482
- * both come from the same `Config`.
483
- * @param namespace - the namespace view whose schema declares the profile shape.
484
- * @param schema - settings schema operations.
485
- * @returns the protocol identifiers, or an empty list when the schema has none.
486
- */
487
- function protocolChoices(namespace, schema) {
488
- if (namespace === void 0) return [];
489
- const list = schema.nodeAtPath(schema.rehydrate(namespace.schema), [
490
- "providers",
491
- PROBE_ROUTE,
492
- "api"
493
- ]);
494
- if (list?.type !== "union" || list.list === void 0) return [];
495
- return list.list.map((entry) => entry.value).filter((value) => typeof value === "string");
496
- }
497
- /** The credential reference a resolved profile names (its `apiKeyEnv` field). */
498
- function apiKeyEnvOf(namespace, path, schema) {
499
- if (namespace === void 0) return void 0;
500
- const profile = schema.getPath(namespace.value, path);
501
- if (typeof profile !== "object" || profile === null) return void 0;
502
- const ref = profile.apiKeyEnv;
503
- return typeof ref === "string" && ref.length > 0 ? ref : void 0;
504
- }
505
- /** The models settings page controller (one per settings surface). */
506
- var ModelsSettingsStore = class {
507
- api;
508
- schema;
509
- describeFace;
510
- /** The snapshot the section renders from (uSES-safe store). */
511
- store = (0, _deepseek_ai_dsh_client_runtime_client.createSnapshotStore)({
512
- status: "idle",
513
- error: null,
514
- credentialError: null,
515
- writable: false,
516
- rows: [],
517
- namespaces: /* @__PURE__ */ new Map()
518
- });
519
- /** Latest load wins; an older response never overwrites a newer one. */
520
- generation = 0;
521
- /**
522
- * @param api - the wire face (credentials/llm domains, and settings writes).
523
- * @param describeFace - the shared mirror's describe face (namespace views and writability).
524
- */
525
- constructor(api, schema, describeFace) {
526
- this.api = api;
527
- this.schema = schema;
528
- this.describeFace = describeFace;
529
- }
530
- /**
531
- * Refresh the whole page snapshot: the provider directory and the mirror's
532
- * settings answer in parallel, then one batched credential describe over
533
- * every referenced ref. Provider failure or absence of an initial settings
534
- * answer keeps the last good rows and surfaces an error; a failed settings
535
- * refresh reuses the mirror's held view.
536
- * @returns nothing; the snapshot carries the outcome.
537
- */
538
- async load() {
539
- const generation = ++this.generation;
540
- this.store.update((s) => {
541
- s.status = "loading";
542
- s.error = null;
543
- });
544
- let providers;
545
- let writable;
546
- let views;
547
- try {
548
- const [providersResponse] = await Promise.all([this.api.llm.providers({}), this.describeFace.ensure()]);
549
- if (!providersResponse.result.ok) throw new Error(providersResponse.result.error.message);
550
- const mirrored = this.describeFace.getSnapshot();
551
- if (mirrored.view === void 0) throw new Error(mirrored.error ?? "settings are unavailable in this browser");
552
- providers = providersResponse.result.value.providers;
553
- writable = mirrored.view.writable;
554
- views = mirrored.view.namespaces;
555
- } catch (error) {
556
- if (generation !== this.generation) return;
557
- this.store.update((s) => {
558
- s.status = "error";
559
- s.error = error instanceof Error ? error.message : String(error);
560
- });
561
- return;
562
- }
563
- const namespaces = new Map(views.map((view) => [view.ns, view]));
564
- const rows = providers.map((entry) => {
565
- const namespace = namespaces.get(entry.settingsNs);
566
- return {
567
- entry,
568
- configured: namespace !== void 0 && (entry.settingsPath.length === 0 || this.schema.getPath(namespace.value, entry.settingsPath) !== void 0),
569
- removable: namespace !== void 0 && entry.settingsPath.length > 0 && this.schema.hasPath(namespace.user, entry.settingsPath) && !this.schema.hasPath(namespace.base, entry.settingsPath),
570
- apiKeyEnv: apiKeyEnvOf(namespace, entry.settingsPath, this.schema),
571
- credential: void 0
572
- };
573
- });
574
- const refs = [...new Set(rows.flatMap((row) => row.apiKeyEnv === void 0 ? [] : [row.apiKeyEnv]))];
575
- let credentials = {};
576
- let credentialError = null;
577
- if (refs.length > 0) try {
578
- const response = await this.api.credentials.describe({ refs });
579
- if (response.result.ok) credentials = response.result.value.credentials;
580
- else credentialError = response.result.error.message;
581
- } catch (error) {
582
- credentialError = messageOf(error);
583
- }
584
- if (generation !== this.generation) return;
585
- this.store.update((s) => {
586
- s.status = "ready";
587
- s.error = null;
588
- s.credentialError = credentialError;
589
- s.writable = writable;
590
- s.rows = rows.map((row) => ({
591
- ...row,
592
- ...row.apiKeyEnv !== void 0 && credentials[row.apiKeyEnv] !== void 0 ? { credential: credentials[row.apiKeyEnv] } : {}
593
- }));
594
- s.namespaces = namespaces;
595
- });
596
- }
597
- };
598
- /**
599
- * Whether a joined row can serve model requests as it stands: the route is
600
- * registered with the adapter registry, and whatever credential its resolved
601
- * profile names is stored. A profile naming no reference authenticates through
602
- * the provider's own path (the Bedrock chain, Vertex ADC, a gateway that needs
603
- * nothing), as does a live route with no settings address at all, so neither
604
- * owes this page a key.
605
- * @param row - one joined provider row.
606
- * @returns whether the user already has this provider to talk to.
607
- */
608
- function providerUsable(row) {
609
- if (!row.entry.active) return false;
610
- if (row.apiKeyEnv === void 0) return true;
611
- return row.credential?.configured === true;
612
- }
613
- /**
614
- * Project first-run readiness from the provider/settings/credential join used
615
- * by the Models page. The step exists to leave the user with a model to talk
616
- * to, so ANY usable provider ends it; only when none exists does the official
617
- * DeepSeek route — the one route the prompt can offer a key field for — decide
618
- * whether prompting can help. A missing official configurable-provider
619
- * declaration means the adapter is not repairable by navigating to Models.
620
- * @param state - current shared Models join snapshot.
621
- * @returns the onboarding state without reading a parallel fact source.
622
- */
623
- function onboardingReadiness(state) {
624
- if ((state.status === "idle" || state.status === "loading") && state.rows.length === 0) return { kind: "loading" };
625
- if (state.status === "error") return {
626
- kind: "unavailable",
627
- reason: "load-failed"
628
- };
629
- if (state.rows.some(providerUsable)) return { kind: "provider-ready" };
630
- const row = state.rows.find((candidate) => candidate.entry.provider === "deepseek-official" && candidate.entry.settingsNs === "llm-deepseek" && candidate.entry.settingsPath.length === 0);
631
- if (row === void 0) return { kind: "adapter-absent" };
632
- if (!row.entry.active) return {
633
- kind: "unavailable",
634
- reason: "provider-inactive"
635
- };
636
- if (state.credentialError !== null || row.credential === void 0) return {
637
- kind: "unavailable",
638
- reason: "credentials-unavailable"
639
- };
640
- if (!state.writable) return {
641
- kind: "unavailable",
642
- reason: "settings-read-only"
643
- };
644
- if (!row.credential.writable) return {
645
- kind: "unavailable",
646
- reason: "credential-read-only"
647
- };
648
- return { kind: "credential-missing" };
649
- }
650
- //#endregion
651
446
  //#region lib/types/client/ModelListEditor.js
652
447
  /**
653
448
  * The model list of one pi-ai provider profile, plus the action that asks the
@@ -752,7 +547,7 @@ window.__ModuleLoader__.load({
752
547
  * @returns the model-list editor.
753
548
  */
754
549
  function ModelListEditor(props) {
755
- const { models, onChange, probe, api, t, disabled } = props;
550
+ const { models, onChange, probe, operations, t, disabled } = props;
756
551
  const [busy, setBusy] = (0, react.useState)(false);
757
552
  const [failure, setFailure] = (0, react.useState)(void 0);
758
553
  const [candidates, setCandidates] = (0, react.useState)(void 0);
@@ -798,18 +593,17 @@ window.__ModuleLoader__.load({
798
593
  setBusy(true);
799
594
  setFailure(void 0);
800
595
  try {
801
- const response = await api.llm.discoverModels({
802
- settingsNs: probe.settingsNs,
596
+ const answer = await operations.discoverModels(probe.settingsNs, {
803
597
  ...probe.provider === void 0 ? {} : { provider: probe.provider },
804
598
  ...probe.baseURL === void 0 || probe.baseURL.length === 0 ? {} : { baseURL: probe.baseURL },
805
599
  ...probe.api === void 0 ? {} : { api: probe.api },
806
600
  ...probe.apiKey === void 0 ? {} : { apiKey: probe.apiKey }
807
601
  });
808
- if (!response.result.ok) {
809
- setFailure(response.result.error.message);
602
+ if (answer.kind === "refused") {
603
+ setFailure(answer.message);
810
604
  return;
811
605
  }
812
- const found = response.result.value.models;
606
+ const found = answer.models;
813
607
  if (found.length === 0) {
814
608
  setFailure(t("fetchEmpty"));
815
609
  return;
@@ -817,8 +611,6 @@ window.__ModuleLoader__.load({
817
611
  const known = new Set(models.map((model) => textOf(model, "id")));
818
612
  setCandidates(found);
819
613
  setPicked(new Set(found.filter((model) => !known.has(model.id)).map((model) => model.id)));
820
- } catch (error) {
821
- setFailure(messageOf(error));
822
614
  } finally {
823
615
  setBusy(false);
824
616
  }
@@ -1050,6 +842,247 @@ window.__ModuleLoader__.load({
1050
842
  });
1051
843
  }
1052
844
  //#endregion
845
+ //#region lib/types/client/store.js
846
+ /**
847
+ * Models settings page store: one snapshot joining the configurable-provider
848
+ * directory (`llm/listProviders` joined with `llm/listConfigurableProviders`),
849
+ * the settings namespaces (shared settings mirror),
850
+ * and the referenced credentials (`credentials/describe`). The host stays the
851
+ * single fact source — every mutation writes through the wire and the page
852
+ * re-renders from the next describe, pushed or refetched.
853
+ */
854
+ /**
855
+ * Any route key walks a dict schema to the same profile node, so the lookup
856
+ * names one that cannot collide with a configured route.
857
+ */
858
+ const PROBE_ROUTE = "\0probe";
859
+ /**
860
+ * Join declared configurable providers with the currently registered routes.
861
+ * @param registered - live provider routes in registration order.
862
+ * @param directory - declared configurable providers in declaration order.
863
+ * @returns declared rows followed by live routes with no declaration.
864
+ */
865
+ function joinProviderDirectory(registered, directory) {
866
+ const active = new Set(registered.map((provider) => provider.id));
867
+ const declared = new Set(directory.map((entry) => entry.provider));
868
+ const rows = directory.map((entry) => ({
869
+ provider: entry.provider,
870
+ displayName: entry.displayName,
871
+ settingsNs: entry.settingsNs,
872
+ settingsPath: [...entry.settingsPath],
873
+ active: active.has(entry.provider),
874
+ ...entry.declared === void 0 ? {} : { declared: entry.declared }
875
+ }));
876
+ for (const provider of registered) {
877
+ if (declared.has(provider.id)) continue;
878
+ rows.push({
879
+ provider: provider.id,
880
+ displayName: provider.name,
881
+ settingsNs: "",
882
+ settingsPath: [],
883
+ active: true
884
+ });
885
+ }
886
+ return rows;
887
+ }
888
+ /**
889
+ * Derive the conventional credential reference for a provider route: the v1
890
+ * page never asks for an environment-variable name, so a typed key stores
891
+ * under this derived reference and the profile records it as `apiKeyEnv`.
892
+ * @param provider - provider route id (e.g. `anthropic`, `minimax-cn`).
893
+ * @returns the derived reference name (e.g. `MINIMAX_CN_API_KEY`).
894
+ */
895
+ function deriveKeyRef(provider) {
896
+ return `${provider.toUpperCase().replace(/[^A-Z0-9]+/g, "_")}_API_KEY`;
897
+ }
898
+ /**
899
+ * The wire protocols a hand-declared route may name, read out of the owning
900
+ * namespace's own schema. This stays a schema read rather than a wire field so
901
+ * the choices the page offers cannot drift from the ones the adapter accepts:
902
+ * both come from the same `Config`.
903
+ * @param namespace - the namespace view whose schema declares the profile shape.
904
+ * @param schema - settings schema operations.
905
+ * @returns the protocol identifiers, or an empty list when the schema has none.
906
+ */
907
+ function protocolChoices(namespace, schema) {
908
+ if (namespace === void 0) return [];
909
+ const list = schema.nodeAtPath(schema.rehydrate(namespace.schema), [
910
+ "providers",
911
+ PROBE_ROUTE,
912
+ "api"
913
+ ]);
914
+ if (list?.type !== "union" || list.list === void 0) return [];
915
+ return list.list.map((entry) => entry.value).filter((value) => typeof value === "string");
916
+ }
917
+ /** The credential reference a resolved profile names (its `apiKeyEnv` field). */
918
+ function apiKeyEnvOf(namespace, path, schema) {
919
+ if (namespace === void 0) return void 0;
920
+ const profile = schema.getPath(namespace.value, path);
921
+ if (typeof profile !== "object" || profile === null) return void 0;
922
+ const ref = profile.apiKeyEnv;
923
+ return typeof ref === "string" && ref.length > 0 ? ref : void 0;
924
+ }
925
+ /** The models settings page controller (one per settings surface). */
926
+ var ModelsSettingsStore = class {
927
+ ctx;
928
+ schema;
929
+ describeFace;
930
+ /** The snapshot the section renders from (uSES-safe store). */
931
+ store = (0, _deepseek_ai_dsh_client_store.createSnapshotStore)({
932
+ status: "idle",
933
+ error: null,
934
+ credentialError: null,
935
+ writable: false,
936
+ rows: [],
937
+ namespaces: /* @__PURE__ */ new Map()
938
+ });
939
+ /** Latest load wins; an older response never overwrites a newer one. */
940
+ generation = 0;
941
+ /**
942
+ * @param ctx - the page plugin's context, whose `remote.llm` and
943
+ * `remote.credentials` namespaces carry the directory and credential reads.
944
+ * @param schema - settings-owned schema and immutable path operations.
945
+ * @param describeFace - the shared mirror's describe face (namespace views and writability).
946
+ */
947
+ constructor(ctx, schema, describeFace) {
948
+ this.ctx = ctx;
949
+ this.schema = schema;
950
+ this.describeFace = describeFace;
951
+ }
952
+ /**
953
+ * Refresh the whole page snapshot: the provider directory and the mirror's
954
+ * settings answer in parallel, then one batched credential describe over
955
+ * every referenced ref. Provider failure or absence of an initial settings
956
+ * answer keeps the last good rows and surfaces an error; a failed settings
957
+ * refresh reuses the mirror's held view.
958
+ * @returns nothing; the snapshot carries the outcome.
959
+ */
960
+ async load() {
961
+ const generation = ++this.generation;
962
+ this.store.update((s) => {
963
+ s.status = "loading";
964
+ s.error = null;
965
+ });
966
+ const [registered, declared] = await Promise.all([
967
+ this.ctx.remote.llm.listProviders(),
968
+ this.ctx.remote.llm.listConfigurableProviders(),
969
+ this.describeFace.ensure()
970
+ ]);
971
+ if (!registered.ok) {
972
+ this.failLoad(generation, registered.error.message);
973
+ return;
974
+ }
975
+ if (!declared.ok) {
976
+ this.failLoad(generation, declared.error.message);
977
+ return;
978
+ }
979
+ const mirrored = this.describeFace.getSnapshot();
980
+ if (mirrored.view === void 0) {
981
+ this.failLoad(generation, mirrored.error ?? "settings are unavailable in this browser");
982
+ return;
983
+ }
984
+ const providers = joinProviderDirectory(registered.value, declared.value);
985
+ const writable = mirrored.view.writable;
986
+ const views = mirrored.view.namespaces;
987
+ const namespaces = new Map(views.map((view) => [view.ns, view]));
988
+ const rows = providers.map((entry) => {
989
+ const namespace = namespaces.get(entry.settingsNs);
990
+ return {
991
+ entry,
992
+ configured: namespace !== void 0 && (entry.settingsPath.length === 0 || this.schema.getPath(namespace.value, entry.settingsPath) !== void 0),
993
+ removable: namespace !== void 0 && entry.settingsPath.length > 0 && this.schema.hasPath(namespace.user, entry.settingsPath) && !this.schema.hasPath(namespace.base, entry.settingsPath),
994
+ apiKeyEnv: apiKeyEnvOf(namespace, entry.settingsPath, this.schema),
995
+ credential: void 0
996
+ };
997
+ });
998
+ const refs = [...new Set(rows.map((row) => row.apiKeyEnv ?? deriveKeyRef(row.entry.provider)))];
999
+ let credentials = {};
1000
+ let credentialError = null;
1001
+ if (refs.length > 0) {
1002
+ const response = await this.ctx.remote.credentials.describe(refs);
1003
+ if (response.ok) credentials = response.value;
1004
+ else credentialError = response.error.message;
1005
+ }
1006
+ if (generation !== this.generation) return;
1007
+ this.store.update((s) => {
1008
+ s.status = "ready";
1009
+ s.error = null;
1010
+ s.credentialError = credentialError;
1011
+ s.writable = writable;
1012
+ s.rows = rows.map((row) => {
1013
+ const named = row.apiKeyEnv === void 0 ? void 0 : credentials[row.apiKeyEnv];
1014
+ const derived = row.apiKeyEnv !== void 0 ? void 0 : credentials[deriveKeyRef(row.entry.provider)];
1015
+ return {
1016
+ ...row,
1017
+ ...named === void 0 ? {} : { credential: named },
1018
+ ...derived === void 0 ? {} : { derivedCredential: derived }
1019
+ };
1020
+ });
1021
+ s.namespaces = namespaces;
1022
+ });
1023
+ }
1024
+ /** Publish one load's failure text, unless a newer load already took over. */
1025
+ failLoad(generation, message) {
1026
+ if (generation !== this.generation) return;
1027
+ this.store.update((s) => {
1028
+ s.status = "error";
1029
+ s.error = message;
1030
+ });
1031
+ }
1032
+ };
1033
+ /**
1034
+ * Whether a joined row can serve model requests as it stands: the route is
1035
+ * registered with the adapter registry, and whatever credential its resolved
1036
+ * profile names is stored. A profile naming no reference authenticates through
1037
+ * the provider's own path (the Bedrock chain, Vertex ADC, a gateway that needs
1038
+ * nothing), as does a live route with no settings address at all, so neither
1039
+ * owes this page a key.
1040
+ * @param row - one joined provider row.
1041
+ * @returns whether the user already has this provider to talk to.
1042
+ */
1043
+ function providerUsable(row) {
1044
+ if (!row.entry.active) return false;
1045
+ if (row.apiKeyEnv === void 0) return true;
1046
+ return row.credential?.configured === true;
1047
+ }
1048
+ /**
1049
+ * Project first-run readiness from the provider/settings/credential join used
1050
+ * by the Models page. The step exists to leave the user with a model to talk
1051
+ * to, so ANY usable provider ends it; only when none exists does the official
1052
+ * DeepSeek route — the one route the prompt can offer a key field for — decide
1053
+ * whether prompting can help. A missing official configurable-provider
1054
+ * declaration means the adapter is not repairable by navigating to Models.
1055
+ * @param state - current shared Models join snapshot.
1056
+ * @returns the onboarding state without reading a parallel fact source.
1057
+ */
1058
+ function onboardingReadiness(state) {
1059
+ if ((state.status === "idle" || state.status === "loading") && state.rows.length === 0) return { kind: "loading" };
1060
+ if (state.status === "error") return {
1061
+ kind: "unavailable",
1062
+ reason: "load-failed"
1063
+ };
1064
+ if (state.rows.some(providerUsable)) return { kind: "provider-ready" };
1065
+ const row = state.rows.find((candidate) => candidate.entry.provider === "deepseek-official" && candidate.entry.settingsNs === "llm-deepseek" && candidate.entry.settingsPath.length === 0);
1066
+ if (row === void 0) return { kind: "adapter-absent" };
1067
+ if (!row.entry.active) return {
1068
+ kind: "unavailable",
1069
+ reason: "provider-inactive"
1070
+ };
1071
+ if (state.credentialError !== null || row.credential === void 0) return {
1072
+ kind: "unavailable",
1073
+ reason: "credentials-unavailable"
1074
+ };
1075
+ if (!state.writable) return {
1076
+ kind: "unavailable",
1077
+ reason: "settings-read-only"
1078
+ };
1079
+ if (!row.credential.writable) return {
1080
+ kind: "unavailable",
1081
+ reason: "credential-read-only"
1082
+ };
1083
+ return { kind: "credential-missing" };
1084
+ }
1085
+ //#endregion
1053
1086
  //#region lib/types/client/CustomProviderCard.js
1054
1087
  /**
1055
1088
  * The card that declares a provider pi-ai does not ship — an OpenAI-compatible
@@ -1060,7 +1093,7 @@ window.__ModuleLoader__.load({
1060
1093
  * the provider editor with extra fields: the route id is being *chosen* here,
1061
1094
  * and the settings address does not exist until it is. One `settings.mutate`
1062
1095
  * sets the whole profile at `providers.<route>`; the key travels separately
1063
- * through `credentials.set` under the reference the profile records, exactly as
1096
+ * through `credentials/set` under the reference the profile records, exactly as
1064
1097
  * an existing provider's key does.
1065
1098
  *
1066
1099
  * The three fields a hand-declared route cannot default — endpoint, protocol,
@@ -1090,7 +1123,7 @@ window.__ModuleLoader__.load({
1090
1123
  * @returns the creation card.
1091
1124
  */
1092
1125
  function CustomProviderCard(props) {
1093
- const { taken, protocols, api, t } = props;
1126
+ const { taken, protocols, operations, t } = props;
1094
1127
  const [openedAt] = (0, react.useState)(() => props.revision);
1095
1128
  const [route, setRoute] = (0, react.useState)("");
1096
1129
  const [displayName, setDisplayName] = (0, react.useState)("");
@@ -1128,24 +1161,17 @@ window.__ModuleLoader__.load({
1128
1161
  baseURL,
1129
1162
  models: models.map((model) => ({ ...model }))
1130
1163
  };
1131
- const response = await api.settings.mutate({
1132
- ns: NS$1,
1133
- ops: [{
1134
- op: "set",
1135
- path: ["providers", route],
1136
- value: profile
1137
- }],
1138
- expectedRevision: openedAt
1139
- });
1140
- if (!response.result.ok) return response.result.error.message;
1164
+ const written = await operations.writeSettings(NS$1, [{
1165
+ op: "set",
1166
+ path: ["providers", route],
1167
+ value: profile
1168
+ }], openedAt);
1169
+ if (written.kind !== "written") return written.kind === "conflict" ? t("conflict") : written.message;
1141
1170
  setCommitted(true);
1142
1171
  }
1143
1172
  if (storesKey) {
1144
- const stored = await api.credentials.set({
1145
- ref: keyRef,
1146
- value: keyValue
1147
- });
1148
- if (!stored.result.ok) return stored.result.error.message;
1173
+ const stored = await operations.storeCredential(keyRef, keyValue);
1174
+ if (stored !== void 0) return stored;
1149
1175
  }
1150
1176
  };
1151
1177
  const create = async () => {
@@ -1158,8 +1184,6 @@ window.__ModuleLoader__.load({
1158
1184
  return;
1159
1185
  }
1160
1186
  props.onClose(true);
1161
- } catch (error) {
1162
- setFailure(messageOf(error));
1163
1187
  } finally {
1164
1188
  setBusy(false);
1165
1189
  }
@@ -1224,7 +1248,7 @@ window.__ModuleLoader__.load({
1224
1248
  className: ModelsSection_module_css_default["input"],
1225
1249
  type: "text",
1226
1250
  value: baseURL,
1227
- placeholder: "https://gateway.example/v1",
1251
+ placeholder: t("customBaseUrlPlaceholder"),
1228
1252
  "aria-label": t("baseUrl"),
1229
1253
  disabled: profileDisabled,
1230
1254
  onChange: (event) => {
@@ -1286,7 +1310,7 @@ window.__ModuleLoader__.load({
1286
1310
  ...keyValue.length === 0 ? {} : { apiKey: keyValue }
1287
1311
  },
1288
1312
  probeBlocked: keyFailure === "keyBlank" ? "keyBlankNew" : keyFailure,
1289
- api,
1313
+ operations,
1290
1314
  t,
1291
1315
  disabled: profileDisabled
1292
1316
  }),
@@ -1302,8 +1326,8 @@ window.__ModuleLoader__.load({
1302
1326
  t,
1303
1327
  busy,
1304
1328
  submitDisabled: disabled || !ready,
1305
- submitLabel: "create",
1306
- submitBusyLabel: "creating",
1329
+ submitLabelKey: "create",
1330
+ submitBusyLabelKey: "creating",
1307
1331
  onCancel: () => {
1308
1332
  props.onClose(committed);
1309
1333
  },
@@ -1319,7 +1343,7 @@ window.__ModuleLoader__.load({
1319
1343
  /**
1320
1344
  * One provider's editor card, hand-written per adapter family: the primary
1321
1345
  * field is a single write-only **API key** input (the page never asks for an
1322
- * environment-variable name — a typed key stores through `credentials.set`
1346
+ * environment-variable name — a typed key stores through `credentials/set`
1323
1347
  * under the profile's reference, deriving `<ROUTE>_API_KEY` when the profile
1324
1348
  * has none. The pi-ai profile records that derivation as `apiKeyEnv` only when
1325
1349
  * a key is entered; a blank key materializes a reference-free profile for
@@ -1391,7 +1415,7 @@ window.__ModuleLoader__.load({
1391
1415
  * @returns the editor card.
1392
1416
  */
1393
1417
  function ProviderEditor(props) {
1394
- const { namespace, schema, settingsPath, api, t } = props;
1418
+ const { namespace, schema, settingsPath, operations, t } = props;
1395
1419
  const [draft, setDraft] = (0, react.useState)(() => draftAt(schema, namespace, settingsPath));
1396
1420
  const [keyDraft, setKeyDraft] = (0, react.useState)("");
1397
1421
  const [keyState, setKeyState] = (0, react.useState)(void 0);
@@ -1417,14 +1441,14 @@ window.__ModuleLoader__.load({
1417
1441
  (0, react.useEffect)(() => {
1418
1442
  let stale = false;
1419
1443
  setKeyState(void 0);
1420
- api.credentials.describe({ refs: [keyRef] }).then((response) => {
1421
- if (stale || !response.result.ok) return;
1422
- setKeyState(response.result.value.credentials[keyRef]);
1423
- }, () => void 0);
1444
+ operations.describeCredential(keyRef).then((described) => {
1445
+ if (stale) return;
1446
+ setKeyState(described);
1447
+ });
1424
1448
  return () => {
1425
1449
  stale = true;
1426
1450
  };
1427
- }, [api.credentials, keyRef]);
1451
+ }, [operations, keyRef]);
1428
1452
  const stringAt = (source, key) => {
1429
1453
  const value = schema.getPath(source, [key]);
1430
1454
  return typeof value === "string" && value.trim().length > 0 ? value : void 0;
@@ -1472,22 +1496,15 @@ window.__ModuleLoader__.load({
1472
1496
  value: {}
1473
1497
  }] : pathOps(settingsPath, committedOriginal, next);
1474
1498
  if (ops.length > 0) {
1475
- const response = await api.settings.mutate({
1476
- ns,
1477
- ops,
1478
- expectedRevision
1479
- });
1480
- if (!response.result.ok) return response.result.error.code === "settings-conflict" ? t("conflict") : response.result.error.message;
1481
- setCommittedOriginal(schema.getPath(response.result.value.user, settingsPath));
1482
- setExpectedRevision(response.result.value.revision);
1499
+ const written = await operations.writeSettings(ns, ops, expectedRevision);
1500
+ if (written.kind !== "written") return written.kind === "conflict" ? t("conflict") : written.message;
1501
+ setCommittedOriginal(schema.getPath(written.view.user, settingsPath));
1502
+ setExpectedRevision(written.view.revision);
1483
1503
  setDraft(next);
1484
1504
  }
1485
1505
  if (keyValue.length > 0) {
1486
- const stored = await api.credentials.set({
1487
- ref: keyRef,
1488
- value: keyValue
1489
- });
1490
- if (!stored.result.ok) return stored.result.error.message;
1506
+ const stored = await operations.storeCredential(keyRef, keyValue);
1507
+ if (stored !== void 0) return stored;
1491
1508
  }
1492
1509
  setKeyDraft("");
1493
1510
  };
@@ -1501,15 +1518,17 @@ window.__ModuleLoader__.load({
1501
1518
  return;
1502
1519
  }
1503
1520
  props.onClose(true);
1504
- } catch (error) {
1505
- setFailure(messageOf(error));
1506
1521
  } finally {
1507
1522
  setBusy(false);
1508
1523
  }
1509
1524
  };
1510
- if (node === void 0) return (0, react_jsx_runtime.jsx)("p", {
1525
+ if (node === void 0) return (0, react_jsx_runtime.jsxs)("p", {
1511
1526
  className: ModelsSection_module_css_default["error"],
1512
- children: `${props.provider}: unresolvable settings path`
1527
+ children: [
1528
+ props.provider,
1529
+ ": ",
1530
+ props.t("settingsPathUnresolvable")
1531
+ ]
1513
1532
  });
1514
1533
  const keyLocked = keyState?.writable === false;
1515
1534
  /**
@@ -1647,7 +1666,7 @@ window.__ModuleLoader__.load({
1647
1666
  ...catalogProps,
1648
1667
  probe,
1649
1668
  probeBlocked: keyFailure,
1650
- api
1669
+ operations
1651
1670
  })
1652
1671
  ]
1653
1672
  })]
@@ -1682,9 +1701,9 @@ window.__ModuleLoader__.load({
1682
1701
  t,
1683
1702
  busy,
1684
1703
  submitDisabled: disabled || layout === "unknown" || props.credentialOnly !== true && modelFailure !== void 0 || shownKeyFailure !== void 0 || props.credentialRequired === true && keyValue.length === 0,
1685
- submitLabel: props.submitLabel ?? "apply",
1686
- submitBusyLabel: props.submitBusyLabel ?? "applying",
1687
- ...props.cancelLabel === void 0 ? {} : { cancelLabel: props.cancelLabel },
1704
+ submitLabelKey: props.submitLabelKey ?? "apply",
1705
+ submitBusyLabelKey: props.submitBusyLabelKey ?? "applying",
1706
+ ...props.cancelLabelKey === void 0 ? {} : { cancelLabelKey: props.cancelLabelKey },
1688
1707
  onCancel: () => {
1689
1708
  props.onClose(false);
1690
1709
  },
@@ -1726,28 +1745,21 @@ window.__ModuleLoader__.load({
1726
1745
  * and the whole operation safely retryable; both unsets are idempotent.
1727
1746
  * The settings removal names the profile rather than rebuilding its whole
1728
1747
  * namespace from a partial view.
1729
- * @param api - settings and credential wire faces.
1748
+ * @param operations - the page's Host operations.
1730
1749
  * @param controller - the page store to refresh.
1731
1750
  * @param target - the provider's settings address and optional managed credential.
1732
1751
  * @returns the failure message, or undefined once the write and reload landed.
1733
1752
  */
1734
- async function removeProviderProfile(api, controller, target) {
1735
- try {
1736
- if (target.credentialRef !== void 0) {
1737
- const credential = await api.credentials.unset({ ref: target.credentialRef });
1738
- if (!credential.result.ok) return credential.result.error.message;
1739
- }
1740
- const response = await api.settings.mutate({
1741
- ns: target.settingsNs,
1742
- ops: [{
1743
- op: "unset",
1744
- path: [...target.settingsPath]
1745
- }]
1746
- });
1747
- if (!response.result.ok) return response.result.error.message;
1748
- } catch (error) {
1749
- return messageOf(error);
1753
+ async function removeProviderProfile(operations, controller, target) {
1754
+ if (target.credentialRef !== void 0) {
1755
+ const credential = await operations.removeCredential(target.credentialRef);
1756
+ if (credential !== void 0) return credential;
1750
1757
  }
1758
+ const written = await operations.writeSettings(target.settingsNs, [{
1759
+ op: "unset",
1760
+ path: [...target.settingsPath]
1761
+ }], void 0);
1762
+ if (written.kind !== "written") return written.message;
1751
1763
  await controller.load();
1752
1764
  }
1753
1765
  /**
@@ -1764,6 +1776,16 @@ window.__ModuleLoader__.load({
1764
1776
  if (row.entry.settingsPath.length > 0) return false;
1765
1777
  return row.credential?.configured !== true;
1766
1778
  }
1779
+ /**
1780
+ * The provider-card seat's credential fact: the reference this page would use
1781
+ * for the row — the profile's `apiKeyEnv`, or the page's derived
1782
+ * `<ROUTE>_API_KEY` while the profile names none — confirmed configured. The
1783
+ * derived half is what keeps the seat consistent with the editor on the
1784
+ * add-provider draft, whose dormant row names no reference yet.
1785
+ */
1786
+ function keyConfiguredOf(row) {
1787
+ return row.apiKeyEnv !== void 0 ? row.credential?.configured === true : row.derivedCredential?.configured === true;
1788
+ }
1767
1789
  function targetOf(row) {
1768
1790
  const managedRef = deriveKeyRef(row.entry.provider);
1769
1791
  const credentialRef = row.apiKeyEnv === managedRef && row.credential?.configured === true && row.credential.writable ? managedRef : void 0;
@@ -1790,18 +1812,21 @@ window.__ModuleLoader__.load({
1790
1812
  * @returns the section, or null while the shell has not injected yet.
1791
1813
  */
1792
1814
  function ModelsSection(props) {
1793
- const { controller, useSnapshot, api, schema, t } = props;
1794
- if (controller === void 0 || useSnapshot === void 0 || api === void 0 || schema === void 0 || t === void 0) return null;
1795
- return (0, react_jsx_runtime.jsx)(Loaded, { injected: {
1796
- controller,
1797
- useSnapshot,
1798
- api,
1799
- schema,
1800
- t
1801
- } });
1815
+ const { controller, useSnapshot, operations, schema, t, renderSlot } = props;
1816
+ if (controller === void 0 || useSnapshot === void 0 || operations === void 0 || schema === void 0 || t === void 0) return null;
1817
+ return (0, react_jsx_runtime.jsx)(Loaded, {
1818
+ injected: {
1819
+ controller,
1820
+ useSnapshot,
1821
+ operations,
1822
+ schema,
1823
+ t
1824
+ },
1825
+ renderSlot
1826
+ });
1802
1827
  }
1803
- function Loaded({ injected }) {
1804
- const { controller, api, schema, t } = injected;
1828
+ function Loaded({ injected, renderSlot }) {
1829
+ const { controller, operations, schema, t } = injected;
1805
1830
  const state = injected.useSnapshot((snapshot) => snapshot);
1806
1831
  const [editing, setEditing] = (0, react.useState)(void 0);
1807
1832
  const [adding, setAdding] = (0, react.useState)(false);
@@ -1843,7 +1868,7 @@ window.__ModuleLoader__.load({
1843
1868
  if (deleteTarget === void 0 || deleting) return;
1844
1869
  setDeleting(true);
1845
1870
  setDeleteFailure(void 0);
1846
- removeProviderProfile(api, controller, deleteTarget).then((failure) => {
1871
+ removeProviderProfile(operations, controller, deleteTarget).then((failure) => {
1847
1872
  if (failure !== void 0) {
1848
1873
  setDeleteFailure(failure);
1849
1874
  return;
@@ -1882,6 +1907,7 @@ window.__ModuleLoader__.load({
1882
1907
  const addable = state.rows.filter((row) => !row.configured && row.entry.settingsNs !== "");
1883
1908
  const addTarget = adding ? editing : void 0;
1884
1909
  const addNamespace = addTarget === void 0 ? void 0 : state.namespaces.get(addTarget.settingsNs);
1910
+ const addRow = addTarget === void 0 ? void 0 : state.rows.find((row) => row.entry.provider === addTarget.provider);
1885
1911
  const protocols = protocolChoices(state.namespaces.get("llm-pi-ai"), schema);
1886
1912
  return (0, react_jsx_runtime.jsxs)("div", {
1887
1913
  className: ModelsSection_module_css_default["section"],
@@ -1911,87 +1937,99 @@ window.__ModuleLoader__.load({
1911
1937
  const namespace = state.namespaces.get(target.settingsNs);
1912
1938
  /* v8 ignore next -- the join marks a row configured only when its namespace resolved */
1913
1939
  if (namespace === void 0) return null;
1914
- if (needsSetup(row, anyUsable) && !dismissedSetup.has(row.entry.provider)) return (0, react_jsx_runtime.jsx)("li", {
1940
+ if (needsSetup(row, anyUsable) && !dismissedSetup.has(row.entry.provider)) return (0, react_jsx_runtime.jsxs)("li", {
1915
1941
  className: ModelsSection_module_css_default["setupCard"],
1916
- children: renderProviderEditor({
1942
+ children: [renderProviderEditor({
1917
1943
  target,
1918
1944
  namespace,
1919
1945
  schema,
1920
- api,
1946
+ operations,
1921
1947
  t,
1922
1948
  readOnly: !state.writable,
1923
1949
  onClose: (changed) => {
1924
1950
  closeSetup(changed, target);
1925
1951
  }
1926
- })
1952
+ }), renderSlot("settings.models.provider-card", {
1953
+ provider: row.entry,
1954
+ configured: row.configured,
1955
+ keyConfigured: keyConfiguredOf(row)
1956
+ }, { entryKey: row.entry.settingsNs })]
1927
1957
  }, row.entry.provider);
1928
1958
  const open = !adding && editing?.provider === row.entry.provider;
1929
1959
  const credentialConfigured = row.credential?.configured === true;
1930
1960
  const credentialMissing = !credentialConfigured && row.apiKeyEnv !== void 0 && row.credential?.configured === false;
1931
1961
  return (0, react_jsx_runtime.jsxs)("li", {
1932
1962
  className: ModelsSection_module_css_default["rowCard"],
1933
- children: [(0, react_jsx_runtime.jsxs)("div", {
1934
- className: ModelsSection_module_css_default["rowHead"],
1935
- children: [(0, react_jsx_runtime.jsxs)("span", {
1936
- className: ModelsSection_module_css_default["rowIdentity"],
1937
- children: [
1938
- (0, react_jsx_runtime.jsx)("span", {
1939
- className: ModelsSection_module_css_default["rowName"],
1940
- children: row.entry.displayName
1941
- }),
1942
- row.entry.declared === true ? (0, react_jsx_runtime.jsx)("span", {
1943
- className: ModelsSection_module_css_default["rowTag"],
1944
- children: t("customTag")
1945
- }) : null,
1946
- credentialConfigured ? (0, react_jsx_runtime.jsx)("span", {
1947
- className: `${ModelsSection_module_css_default["credentialDot"]} ${ModelsSection_module_css_default["credentialDotConfigured"]}`,
1948
- role: "img",
1949
- "aria-label": t("credentialConfigured"),
1950
- title: t("credentialConfigured")
1951
- }) : credentialMissing ? (0, react_jsx_runtime.jsx)("span", {
1952
- className: `${ModelsSection_module_css_default["credentialDot"]} ${ModelsSection_module_css_default["credentialDotMissing"]}`,
1953
- role: "img",
1954
- "aria-label": t("credentialMissing"),
1955
- title: t("credentialMissing")
1956
- }) : null
1957
- ]
1958
- }), (0, react_jsx_runtime.jsxs)("span", {
1959
- className: ModelsSection_module_css_default["rowActions"],
1960
- children: [(0, react_jsx_runtime.jsx)("button", {
1961
- type: "button",
1962
- className: ModelsSection_module_css_default["secondaryButton"],
1963
- "aria-label": providerCopy(t("editProvider"), target),
1964
- onClick: () => {
1965
- setSavedTarget(void 0);
1966
- setDeclaring(false);
1967
- setAdding(false);
1968
- setEditing(open ? void 0 : target);
1969
- },
1970
- children: t("edit")
1971
- }), row.removable ? (0, react_jsx_runtime.jsx)("button", {
1972
- type: "button",
1973
- className: ModelsSection_module_css_default["dangerButton"],
1974
- "aria-label": providerCopy(t("removeProvider"), target),
1975
- disabled: !state.writable,
1976
- onClick: () => {
1977
- setSavedTarget(void 0);
1978
- setDeleteFailure(void 0);
1979
- setDeleteTarget(target);
1980
- },
1981
- children: t("remove")
1982
- }) : null]
1983
- })]
1984
- }), open ? renderProviderEditor({
1985
- target,
1986
- namespace,
1987
- schema,
1988
- api,
1989
- t,
1990
- readOnly: !state.writable,
1991
- onClose: (changed) => {
1992
- closeEditor(changed, target);
1993
- }
1994
- }) : null]
1963
+ children: [
1964
+ (0, react_jsx_runtime.jsxs)("div", {
1965
+ className: ModelsSection_module_css_default["rowHead"],
1966
+ children: [(0, react_jsx_runtime.jsxs)("span", {
1967
+ className: ModelsSection_module_css_default["rowIdentity"],
1968
+ children: [
1969
+ (0, react_jsx_runtime.jsx)("span", {
1970
+ className: ModelsSection_module_css_default["rowName"],
1971
+ children: row.entry.displayName
1972
+ }),
1973
+ row.entry.declared === true ? (0, react_jsx_runtime.jsx)("span", {
1974
+ className: ModelsSection_module_css_default["rowTag"],
1975
+ children: t("customTag")
1976
+ }) : null,
1977
+ credentialConfigured ? (0, react_jsx_runtime.jsx)("span", {
1978
+ className: `${ModelsSection_module_css_default["credentialDot"]} ${ModelsSection_module_css_default["credentialDotConfigured"]}`,
1979
+ role: "img",
1980
+ "aria-label": t("credentialConfigured"),
1981
+ title: t("credentialConfigured")
1982
+ }) : credentialMissing ? (0, react_jsx_runtime.jsx)("span", {
1983
+ className: `${ModelsSection_module_css_default["credentialDot"]} ${ModelsSection_module_css_default["credentialDotMissing"]}`,
1984
+ role: "img",
1985
+ "aria-label": t("credentialMissing"),
1986
+ title: t("credentialMissing")
1987
+ }) : null
1988
+ ]
1989
+ }), (0, react_jsx_runtime.jsxs)("span", {
1990
+ className: ModelsSection_module_css_default["rowActions"],
1991
+ children: [(0, react_jsx_runtime.jsx)("button", {
1992
+ type: "button",
1993
+ className: ModelsSection_module_css_default["secondaryButton"],
1994
+ "aria-label": providerCopy(t("editProvider"), target),
1995
+ onClick: () => {
1996
+ setSavedTarget(void 0);
1997
+ setDeclaring(false);
1998
+ setAdding(false);
1999
+ setEditing(open ? void 0 : target);
2000
+ },
2001
+ children: t("edit")
2002
+ }), row.removable ? (0, react_jsx_runtime.jsx)("button", {
2003
+ type: "button",
2004
+ className: ModelsSection_module_css_default["dangerButton"],
2005
+ "aria-label": providerCopy(t("removeProvider"), target),
2006
+ disabled: !state.writable,
2007
+ onClick: () => {
2008
+ setSavedTarget(void 0);
2009
+ setDeleteFailure(void 0);
2010
+ setDeleteTarget(target);
2011
+ },
2012
+ children: t("remove")
2013
+ }) : null]
2014
+ })]
2015
+ }),
2016
+ renderSlot("settings.models.provider-card", {
2017
+ provider: row.entry,
2018
+ configured: row.configured,
2019
+ keyConfigured: keyConfiguredOf(row)
2020
+ }, { entryKey: row.entry.settingsNs }),
2021
+ open ? renderProviderEditor({
2022
+ target,
2023
+ namespace,
2024
+ schema,
2025
+ operations,
2026
+ t,
2027
+ readOnly: !state.writable,
2028
+ onClose: (changed) => {
2029
+ closeEditor(changed, target);
2030
+ }
2031
+ }) : null
2032
+ ]
1995
2033
  }, row.entry.provider);
1996
2034
  })
1997
2035
  }),
@@ -1999,40 +2037,48 @@ window.__ModuleLoader__.load({
1999
2037
  className: ModelsSection_module_css_default["addBlock"],
2000
2038
  children: addTarget !== void 0 && addNamespace !== void 0 ? (0, react_jsx_runtime.jsxs)("div", {
2001
2039
  className: ModelsSection_module_css_default["addCard"],
2002
- children: [(0, react_jsx_runtime.jsxs)("div", {
2003
- className: ModelsSection_module_css_default["field"],
2004
- children: [(0, react_jsx_runtime.jsx)("span", {
2005
- className: ModelsSection_module_css_default["fieldLabel"],
2006
- children: t("provider")
2007
- }), (0, react_jsx_runtime.jsx)("select", {
2008
- className: `${ModelsSection_module_css_default["input"]} ${ModelsSection_module_css_default["selectInput"]}`,
2009
- value: addTarget.provider,
2010
- "aria-label": t("provider"),
2011
- onChange: (event) => {
2012
- const row = addable.find((candidate) => candidate.entry.provider === event.target.value);
2013
- /* v8 ignore next -- the select only lists addable rows */
2014
- if (row === void 0) return;
2015
- setEditing(targetOf(row));
2016
- },
2017
- children: addable.map((row) => (0, react_jsx_runtime.jsx)("option", {
2018
- value: row.entry.provider,
2019
- children: row.entry.displayName
2020
- }, row.entry.provider))
2021
- })]
2022
- }), (0, react_jsx_runtime.jsx)(ProviderEditor, {
2023
- provider: addTarget.provider,
2024
- displayName: addTarget.displayName,
2025
- hideTitle: true,
2026
- namespace: addNamespace,
2027
- schema,
2028
- settingsPath: addTarget.settingsPath,
2029
- api,
2030
- t,
2031
- readOnly: !state.writable,
2032
- onClose: (changed) => {
2033
- closeEditor(changed, addTarget);
2034
- }
2035
- }, addTarget.provider)]
2040
+ children: [
2041
+ (0, react_jsx_runtime.jsxs)("div", {
2042
+ className: ModelsSection_module_css_default["field"],
2043
+ children: [(0, react_jsx_runtime.jsx)("span", {
2044
+ className: ModelsSection_module_css_default["fieldLabel"],
2045
+ children: t("provider")
2046
+ }), (0, react_jsx_runtime.jsx)("select", {
2047
+ className: `${ModelsSection_module_css_default["input"]} ${ModelsSection_module_css_default["selectInput"]}`,
2048
+ value: addTarget.provider,
2049
+ "aria-label": t("provider"),
2050
+ onChange: (event) => {
2051
+ const row = addable.find((candidate) => candidate.entry.provider === event.target.value);
2052
+ /* v8 ignore next -- the select only lists addable rows */
2053
+ if (row === void 0) return;
2054
+ setEditing(targetOf(row));
2055
+ },
2056
+ children: addable.map((row) => (0, react_jsx_runtime.jsx)("option", {
2057
+ value: row.entry.provider,
2058
+ children: row.entry.displayName
2059
+ }, row.entry.provider))
2060
+ })]
2061
+ }),
2062
+ (0, react_jsx_runtime.jsx)(ProviderEditor, {
2063
+ provider: addTarget.provider,
2064
+ displayName: addTarget.displayName,
2065
+ hideTitle: true,
2066
+ namespace: addNamespace,
2067
+ schema,
2068
+ settingsPath: addTarget.settingsPath,
2069
+ operations,
2070
+ t,
2071
+ readOnly: !state.writable,
2072
+ onClose: (changed) => {
2073
+ closeEditor(changed, addTarget);
2074
+ }
2075
+ }, addTarget.provider),
2076
+ addRow === void 0 ? null : renderSlot("settings.models.provider-card", {
2077
+ provider: addRow.entry,
2078
+ configured: addRow.configured,
2079
+ keyConfigured: keyConfiguredOf(addRow)
2080
+ }, { entryKey: addRow.entry.settingsNs })
2081
+ ]
2036
2082
  }) : declaring ? (0, react_jsx_runtime.jsx)("div", {
2037
2083
  className: ModelsSection_module_css_default["addCard"],
2038
2084
  children: (0, react_jsx_runtime.jsx)(CustomProviderCard, {
@@ -2040,7 +2086,7 @@ window.__ModuleLoader__.load({
2040
2086
  protocols,
2041
2087
  /* v8 ignore next -- the card only opens from a button disabled without this namespace */
2042
2088
  revision: state.namespaces.get("llm-pi-ai")?.revision ?? 0,
2043
- api,
2089
+ operations,
2044
2090
  t,
2045
2091
  readOnly: !state.writable,
2046
2092
  onClose: (changed) => {
@@ -2078,6 +2124,7 @@ window.__ModuleLoader__.load({
2078
2124
  })]
2079
2125
  })
2080
2126
  }),
2127
+ renderSlot("settings.models.footer", {}),
2081
2128
  (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Modal, {
2082
2129
  open: deleteTarget !== void 0,
2083
2130
  onClose: closeDelete,
@@ -2203,7 +2250,7 @@ window.__ModuleLoader__.load({
2203
2250
  * @returns the onboarding modal or null when onboarding needs no intervention.
2204
2251
  */
2205
2252
  function DeepSeekOnboardingDialog(props) {
2206
- const { complete, controller, useModels, api, schema, t } = props;
2253
+ const { complete, controller, useModels, operations, schema, t } = props;
2207
2254
  const state = useModels((snapshot) => snapshot);
2208
2255
  const readiness = onboardingReadiness(state);
2209
2256
  (0, react.useEffect)(() => {
@@ -2245,16 +2292,16 @@ window.__ModuleLoader__.load({
2245
2292
  namespace,
2246
2293
  schema,
2247
2294
  settingsPath: row.entry.settingsPath,
2248
- api,
2295
+ operations,
2249
2296
  t,
2250
2297
  readOnly: false,
2251
2298
  hideTitle: true,
2252
2299
  credentialOnly: true,
2253
2300
  credentialRequired: true,
2254
2301
  autoFocusCredential: true,
2255
- cancelLabel: "onboardingLater",
2256
- submitLabel: "onboardingSave",
2257
- submitBusyLabel: "onboardingSaving",
2302
+ cancelLabelKey: "onboardingLater",
2303
+ submitLabelKey: "onboardingSave",
2304
+ submitBusyLabelKey: "onboardingSaving",
2258
2305
  onClose: finishCredential
2259
2306
  })
2260
2307
  })]
@@ -2344,19 +2391,6 @@ window.__ModuleLoader__.load({
2344
2391
  * again. The acknowledgement is compared for exact equality.
2345
2392
  */
2346
2393
  const WELCOME_NOTICE_VERSION = "2026-08-13.1";
2347
- /** The complete editable internal-testing notice in both supported GUI locales. */
2348
- const WELCOME_NOTICE_COPY = {
2349
- zh: {
2350
- title: "内测声明",
2351
- body: "DeepSeek Harness 目前的 0.1 版本仍处在面向 Harness 开发者进行测试的阶段,还有许多地方需要持续改进和打磨,希望听取广大开发者的反馈建议。预计 DeepSeek Harness 的核心插件以及基础 API 都会在接下来的一段时间内快速迭代、持续演化。\n\n我们期待与全球开发者一起,在开源、开放、可复用、可组合的基础设施之上,共同探索智能上限。欢迎全球 Harness 开发者加入 DSH 插件生态。",
2352
- continueLabel: "继续"
2353
- },
2354
- en: {
2355
- title: "Internal Testing Notice",
2356
- 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.",
2357
- continueLabel: "Continue"
2358
- }
2359
- };
2360
2394
  //#endregion
2361
2395
  //#region lib/types/client/welcome-store.js
2362
2396
  /**
@@ -2383,7 +2417,7 @@ window.__ModuleLoader__.load({
2383
2417
  var WelcomeNoticeStore = class {
2384
2418
  scope;
2385
2419
  /** uSES-safe state source shared by the registered welcome step. */
2386
- store = (0, _deepseek_ai_dsh_client_runtime_client.createSnapshotStore)({
2420
+ store = (0, _deepseek_ai_dsh_client_store.createSnapshotStore)({
2387
2421
  status: "idle",
2388
2422
  acknowledged: false,
2389
2423
  error: null
@@ -2484,6 +2518,61 @@ window.__ModuleLoader__.load({
2484
2518
  }
2485
2519
  };
2486
2520
  //#endregion
2521
+ //#region lib/types/client/operations.js
2522
+ /**
2523
+ * The Host reads and writes the Models cards perform, as callbacks built in the
2524
+ * plugin body. Cards receive these instead of a context: the outcomes name what
2525
+ * a card renders — a stored view, a stale revision, a refusal message — so the
2526
+ * failure codes and Remote namespaces stay in the apply world.
2527
+ */
2528
+ /**
2529
+ * Bind the page's Host operations to the plugin's own Remote namespaces.
2530
+ * @param ctx - the page plugin's context, which declares `remote.credentials`,
2531
+ * `remote.llm`, and `remote.settings` in its own `inject`.
2532
+ * @returns the callbacks the section and its cards are injected with.
2533
+ */
2534
+ function createModelsOperations(ctx) {
2535
+ return {
2536
+ describeCredential: async (ref) => {
2537
+ const response = await ctx.remote.credentials.describe([ref]);
2538
+ return response.ok ? response.value[ref] : void 0;
2539
+ },
2540
+ storeCredential: async (ref, value) => {
2541
+ const response = await ctx.remote.credentials.set(ref, value);
2542
+ return response.ok ? void 0 : response.error.message;
2543
+ },
2544
+ removeCredential: async (ref) => {
2545
+ const response = await ctx.remote.credentials.unset(ref);
2546
+ return response.ok ? void 0 : response.error.message;
2547
+ },
2548
+ writeSettings: async (ns, ops, expectedRevision) => {
2549
+ const response = await ctx.remote.settings.mutate(ns, ops, expectedRevision);
2550
+ if (response.ok) return {
2551
+ kind: "written",
2552
+ view: response.value
2553
+ };
2554
+ const { code, message } = response.error;
2555
+ return code === "settings/conflict" ? {
2556
+ kind: "conflict",
2557
+ message
2558
+ } : {
2559
+ kind: "refused",
2560
+ message
2561
+ };
2562
+ },
2563
+ discoverModels: async (settingsNs, request) => {
2564
+ const response = await ctx.remote.llm.discoverModels(settingsNs, request);
2565
+ return response.ok ? {
2566
+ kind: "found",
2567
+ models: response.value
2568
+ } : {
2569
+ kind: "refused",
2570
+ message: response.error.message
2571
+ };
2572
+ }
2573
+ };
2574
+ }
2575
+ //#endregion
2487
2576
  //#region lib/types/client/schema-operations.js
2488
2577
  /**
2489
2578
  * Hide the Cordis service identity behind bound schema callbacks.
@@ -2589,11 +2678,13 @@ window.__ModuleLoader__.load({
2589
2678
  customApiUnset: "Not selected",
2590
2679
  customNeedsBaseUrl: "A custom provider needs a base URL.",
2591
2680
  customNeedsModels: "A custom provider needs at least one model.",
2681
+ customBaseUrlPlaceholder: "https://gateway.example/v1",
2682
+ settingsPathUnresolvable: "unresolvable settings path",
2592
2683
  create: "Create provider",
2593
2684
  creating: "Creating…",
2594
- welcomeTitle: WELCOME_NOTICE_COPY.en.title,
2595
- welcomeBody: WELCOME_NOTICE_COPY.en.body,
2596
- welcomeContinue: WELCOME_NOTICE_COPY.en.continueLabel,
2685
+ welcomeTitle: "Internal Testing Notice",
2686
+ 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.",
2687
+ welcomeContinue: "Continue",
2597
2688
  welcomeError: "The acknowledgement could not be saved. Please try again.",
2598
2689
  onboardingTitle: "Add an API key to get started",
2599
2690
  onboardingDescription: "Configure the official DeepSeek provider to start building.",
@@ -2687,11 +2778,13 @@ window.__ModuleLoader__.load({
2687
2778
  customApiUnset: "未选择",
2688
2779
  customNeedsBaseUrl: "自定义提供方需要填写 API 地址。",
2689
2780
  customNeedsModels: "自定义提供方至少需要一个模型。",
2781
+ customBaseUrlPlaceholder: "https://gateway.example/v1",
2782
+ settingsPathUnresolvable: "无法解析设置路径",
2690
2783
  create: "创建提供方",
2691
2784
  creating: "创建中…",
2692
- welcomeTitle: WELCOME_NOTICE_COPY.zh.title,
2693
- welcomeBody: WELCOME_NOTICE_COPY.zh.body,
2694
- welcomeContinue: WELCOME_NOTICE_COPY.zh.continueLabel,
2785
+ welcomeTitle: "内测声明",
2786
+ welcomeBody: "DeepSeek Harness 目前的 0.1 版本仍处在面向 Harness 开发者进行测试的阶段,还有许多地方需要持续改进和打磨,希望听取广大开发者的反馈建议。预计 DeepSeek Harness 的核心插件以及基础 API 都会在接下来的一段时间内快速迭代、持续演化。\n\n我们期待与全球开发者一起,在开源、开放、可复用、可组合的基础设施之上,共同探索智能上限。欢迎全球 Harness 开发者加入 DSH 插件生态。",
2787
+ welcomeContinue: "继续",
2695
2788
  welcomeError: "暂时无法保存确认状态,请重试。",
2696
2789
  onboardingTitle: "添加一个 API Key 开始使用",
2697
2790
  onboardingDescription: "配置 DeepSeek 官方模型,即可开始使用。",
@@ -2721,8 +2814,10 @@ window.__ModuleLoader__.load({
2721
2814
  const inject = [
2722
2815
  "slots",
2723
2816
  "locale",
2724
- "connection",
2725
2817
  "remote",
2818
+ "remote.credentials",
2819
+ "remote.llm",
2820
+ "remote.settings",
2726
2821
  "settingsScope",
2727
2822
  "settingsSchema"
2728
2823
  ];
@@ -2737,21 +2832,21 @@ window.__ModuleLoader__.load({
2737
2832
  zh,
2738
2833
  en
2739
2834
  }), "ui-settings-models: copy dictionaries");
2740
- const connection = ctx.get("connection");
2741
2835
  const schema = createSettingsSchemaOperations(ctx.settingsSchema);
2742
- const controller = new ModelsSettingsStore(connection.api, schema, ctx.settingsScope.describe());
2836
+ const operations = createModelsOperations(ctx);
2837
+ const controller = new ModelsSettingsStore(ctx, schema, ctx.settingsScope.describe());
2743
2838
  const t = ctx.locale.bind(NS);
2744
2839
  const injected = () => ({
2745
2840
  controller,
2746
2841
  hooks: { snapshot: controller.store },
2747
- api: connection.api,
2842
+ operations,
2748
2843
  schema,
2749
2844
  t
2750
2845
  });
2751
2846
  const deepSeekOnboardingInjected = () => ({
2752
2847
  controller,
2753
2848
  hooks: { models: controller.store },
2754
- api: connection.api,
2849
+ operations,
2755
2850
  schema,
2756
2851
  t
2757
2852
  });
@@ -2786,7 +2881,17 @@ window.__ModuleLoader__.load({
2786
2881
  id: "models",
2787
2882
  order: 10,
2788
2883
  label: () => t("nav"),
2789
- inject: injected
2884
+ inject: injected,
2885
+ children: {
2886
+ "settings.models.provider-card": {
2887
+ kind: "keyed",
2888
+ scope: "root"
2889
+ },
2890
+ "settings.models.footer": {
2891
+ kind: "list",
2892
+ scope: "root"
2893
+ }
2894
+ }
2790
2895
  }, ModelsSection));
2791
2896
  ctx.slots.inject("settings.onboarding", () => ctx.slots.register({
2792
2897
  name: "settings.onboarding",