dsh-edge 0.9.0 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. package/THIRD_PARTY_NOTICES.md +1318 -1075
  2. package/dist/assets/index-Df-65__b.js +110 -0
  3. package/dist/assets/index-b24khbeK.css +1 -0
  4. package/dist/assets/langs/{php-DDkx9sim.js → php-DJl5gRdb.js} +2 -2
  5. package/dist/assets/langs/{ruby-DCxyoPen.js → ruby-5eNB0pDK.js} +2 -2
  6. package/dist/assets/vendor-BNsW4eBh.css +1 -0
  7. package/dist/assets/vendor-CCJJTK99.js +411 -0
  8. package/dist/index.html +8 -8
  9. package/dist/plugins/@deepseek-ai/dsh-api-gateway/client.js +1513 -77
  10. package/dist/plugins/@deepseek-ai/dsh-api-remotes/client.js +3608 -757
  11. package/dist/plugins/@deepseek-ai/dsh-api-session-controller/client.js +2777 -0
  12. package/dist/plugins/@deepseek-ai/dsh-api-workspace-controller/client.js +415 -0
  13. package/dist/plugins/@deepseek-ai/dsh-client-connection/client.js +1975 -7466
  14. package/dist/plugins/@deepseek-ai/dsh-client-locale/client.js +225 -76
  15. package/dist/plugins/@deepseek-ai/dsh-client-modules/client.js +67 -15
  16. package/dist/plugins/@deepseek-ai/dsh-client-ui-agent-preset/client.js +270 -460
  17. package/dist/plugins/@deepseek-ai/dsh-client-ui-approval/client.js +292 -0
  18. package/dist/plugins/@deepseek-ai/dsh-client-ui-attachment/client.js +42 -17
  19. package/dist/plugins/@deepseek-ai/dsh-client-ui-brand-official/client.js +7 -9
  20. package/dist/plugins/@deepseek-ai/dsh-client-ui-chat/client.js +8177 -0
  21. package/dist/plugins/@deepseek-ai/dsh-client-ui-commands/client.js +22 -10
  22. package/dist/plugins/@deepseek-ai/dsh-client-ui-conversation/client.js +14950 -8910
  23. package/dist/plugins/@deepseek-ai/dsh-client-ui-deliverables/client.js +161 -137
  24. package/dist/plugins/@deepseek-ai/dsh-client-ui-goal/client.js +6 -7
  25. package/dist/plugins/@deepseek-ai/dsh-client-ui-input-trigger/client.js +268 -40
  26. package/dist/plugins/@deepseek-ai/dsh-client-ui-jobs/client.js +1 -1
  27. package/dist/plugins/@deepseek-ai/dsh-client-ui-layout/client.js +45 -11
  28. package/dist/plugins/@deepseek-ai/dsh-client-ui-message-feedback/client.js +30 -58
  29. package/dist/plugins/@deepseek-ai/dsh-client-ui-model-selection/client.js +188 -89
  30. package/dist/plugins/@deepseek-ai/dsh-client-ui-permission-presets/client.js +105 -75
  31. package/dist/plugins/@deepseek-ai/dsh-client-ui-renderer/client.js +650 -188
  32. package/dist/plugins/@deepseek-ai/dsh-client-ui-schedule/client.js +307 -0
  33. package/dist/plugins/@deepseek-ai/dsh-client-ui-session/client.js +340 -0
  34. package/dist/plugins/@deepseek-ai/dsh-client-ui-settings/client.js +57 -50
  35. package/dist/plugins/@deepseek-ai/dsh-client-ui-settings-general/client.js +134 -69
  36. package/dist/plugins/@deepseek-ai/dsh-client-ui-settings-models/client.js +575 -442
  37. package/dist/plugins/@deepseek-ai/dsh-client-ui-sidebar/client.js +24 -11
  38. package/dist/plugins/@deepseek-ai/dsh-client-ui-skill/client.js +13 -9
  39. package/dist/plugins/@deepseek-ai/dsh-client-ui-subagent/client.js +44 -20
  40. package/dist/plugins/@deepseek-ai/dsh-client-ui-theme/client.js +265 -94
  41. package/dist/plugins/@deepseek-ai/dsh-client-ui-tool/client.js +899 -433
  42. package/dist/plugins/@deepseek-ai/dsh-client-ui-trajectory/client.js +1472 -613
  43. package/dist/plugins/@deepseek-ai/dsh-client-ui-user-questions/client.js +249 -95
  44. package/dist/plugins/@deepseek-ai/dsh-client-ui-workflow-run/client.js +5 -5
  45. package/dist/plugins/@deepseek-ai/dsh-client-ui-workspace/client.js +425 -146
  46. package/dist/plugins/@deepseek-ai/dsh-typert-registry/client.js +29 -14
  47. package/dist/plugins/dsh-edge-client-ui/client.js +28 -26
  48. package/package.json +62 -58
  49. package/scripts/verify-packed.mjs +1 -1
  50. package/worker/direct/index.js +2866 -1466
  51. package/worker/isolated/index.js +2438 -1038
  52. package/dist/assets/index-C6eRlFa6.css +0 -1
  53. package/dist/assets/index-ClqxG24t.js +0 -96
  54. package/dist/assets/vendor-CjyC-hUb.css +0 -1
  55. package/dist/assets/vendor-D22_Mp1f.js +0 -411
  56. package/dist/plugins/@deepseek-ai/dsh-client-runtime/client.js +0 -10574
@@ -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:.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}";
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");
@@ -72,10 +72,12 @@ window.__ModuleLoader__.load({
72
72
  "addModelButton": "zGbnIq_addModelButton",
73
73
  "advancedHint": "zGbnIq_advancedHint",
74
74
  "candidate": "zGbnIq_candidate",
75
- "candidateActions": "zGbnIq_candidateActions",
75
+ "candidateEmpty": "zGbnIq_candidateEmpty",
76
76
  "candidateId": "zGbnIq_candidateId",
77
77
  "candidateLabel": "zGbnIq_candidateLabel",
78
78
  "candidateList": "zGbnIq_candidateList",
79
+ "candidateSearch": "zGbnIq_candidateSearch",
80
+ "candidateToolbar": "zGbnIq_candidateToolbar",
79
81
  "credentialDot": "zGbnIq_credentialDot",
80
82
  "credentialDotConfigured": "zGbnIq_credentialDotConfigured",
81
83
  "credentialDotMissing": "zGbnIq_credentialDotMissing",
@@ -126,6 +128,7 @@ window.__ModuleLoader__.load({
126
128
  "section": "zGbnIq_section",
127
129
  "selectInput": "zGbnIq_selectInput",
128
130
  "setupCard": "zGbnIq_setupCard",
131
+ "switchThumb": "zGbnIq_switchThumb",
129
132
  "title": "zGbnIq_title"
130
133
  };
131
134
  //#endregion
@@ -144,13 +147,13 @@ window.__ModuleLoader__.load({
144
147
  className: ModelsSection_module_css_default["secondaryButton"],
145
148
  disabled: props.busy,
146
149
  onClick: props.onCancel,
147
- children: t(props.cancelLabel ?? "cancel")
150
+ children: t(props.cancelLabelKey ?? "cancel")
148
151
  }), (0, react_jsx_runtime.jsx)("button", {
149
152
  type: "button",
150
153
  className: ModelsSection_module_css_default["primaryButton"],
151
154
  disabled: props.submitDisabled,
152
155
  onClick: props.onSubmit,
153
- children: props.busy ? t(props.submitBusyLabel) : t(props.submitLabel)
156
+ children: props.busy ? t(props.submitBusyLabelKey) : t(props.submitLabelKey)
154
157
  })]
155
158
  });
156
159
  }
@@ -442,212 +445,6 @@ window.__ModuleLoader__.load({
442
445
  });
443
446
  }
444
447
  //#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
448
  //#region lib/types/client/ModelListEditor.js
652
449
  /**
653
450
  * The model list of one pi-ai provider profile, plus the action that asks the
@@ -752,11 +549,12 @@ window.__ModuleLoader__.load({
752
549
  * @returns the model-list editor.
753
550
  */
754
551
  function ModelListEditor(props) {
755
- const { models, onChange, probe, api, t, disabled } = props;
552
+ const { models, onChange, probe, operations, t, disabled } = props;
756
553
  const [busy, setBusy] = (0, react.useState)(false);
757
554
  const [failure, setFailure] = (0, react.useState)(void 0);
758
555
  const [candidates, setCandidates] = (0, react.useState)(void 0);
759
556
  const [picked, setPicked] = (0, react.useState)(/* @__PURE__ */ new Set());
557
+ const [candidateQuery, setCandidateQuery] = (0, react.useState)("");
760
558
  const [expanded, setExpanded] = (0, react.useState)(/* @__PURE__ */ new Set());
761
559
  const [editing, setEditing] = (0, react.useState)(/* @__PURE__ */ new Map());
762
560
  /** Buffer key for one capacity field; the row half moves when rows do. */
@@ -798,27 +596,25 @@ window.__ModuleLoader__.load({
798
596
  setBusy(true);
799
597
  setFailure(void 0);
800
598
  try {
801
- const response = await api.llm.discoverModels({
802
- settingsNs: probe.settingsNs,
599
+ const answer = await operations.discoverModels(probe.settingsNs, {
803
600
  ...probe.provider === void 0 ? {} : { provider: probe.provider },
804
601
  ...probe.baseURL === void 0 || probe.baseURL.length === 0 ? {} : { baseURL: probe.baseURL },
805
602
  ...probe.api === void 0 ? {} : { api: probe.api },
806
603
  ...probe.apiKey === void 0 ? {} : { apiKey: probe.apiKey }
807
604
  });
808
- if (!response.result.ok) {
809
- setFailure(response.result.error.message);
605
+ if (answer.kind === "refused") {
606
+ setFailure(answer.message);
810
607
  return;
811
608
  }
812
- const found = response.result.value.models;
609
+ const found = answer.models;
813
610
  if (found.length === 0) {
814
611
  setFailure(t("fetchEmpty"));
815
612
  return;
816
613
  }
817
614
  const known = new Set(models.map((model) => textOf(model, "id")));
615
+ setCandidateQuery("");
818
616
  setCandidates(found);
819
617
  setPicked(new Set(found.filter((model) => !known.has(model.id)).map((model) => model.id)));
820
- } catch (error) {
821
- setFailure(messageOf(error));
822
618
  } finally {
823
619
  setBusy(false);
824
620
  }
@@ -826,6 +622,7 @@ window.__ModuleLoader__.load({
826
622
  const closePicker = () => {
827
623
  setCandidates(void 0);
828
624
  setPicked(/* @__PURE__ */ new Set());
625
+ setCandidateQuery("");
829
626
  };
830
627
  const adoptPicked = () => {
831
628
  /* v8 ignore next -- the dialog only renders with candidates loaded */
@@ -846,10 +643,15 @@ window.__ModuleLoader__.load({
846
643
  });
847
644
  };
848
645
  const activeCandidates = candidates ?? [];
849
- const allCandidatesPicked = activeCandidates.length > 0 && activeCandidates.every((candidate) => picked.has(candidate.id));
850
- const toggleAllCandidates = () => {
646
+ const normalizedCandidateQuery = candidateQuery.trim().toLowerCase();
647
+ const visibleCandidates = normalizedCandidateQuery.length === 0 ? activeCandidates : activeCandidates.filter((candidate) => candidate.id.toLowerCase().includes(normalizedCandidateQuery) || candidate.name?.toLowerCase().includes(normalizedCandidateQuery) === true);
648
+ const allVisibleCandidatesPicked = visibleCandidates.length > 0 && visibleCandidates.every((candidate) => picked.has(candidate.id));
649
+ const toggleVisibleCandidates = () => {
851
650
  setPicked((current) => {
852
- return activeCandidates.every((candidate) => current.has(candidate.id)) ? /* @__PURE__ */ new Set() : new Set(activeCandidates.map((candidate) => candidate.id));
651
+ const next = new Set(current);
652
+ if (visibleCandidates.every((candidate) => current.has(candidate.id))) for (const candidate of visibleCandidates) next.delete(candidate.id);
653
+ else for (const candidate of visibleCandidates) next.add(candidate.id);
654
+ return next;
853
655
  });
854
656
  };
855
657
  const askable = probe.provider !== void 0 || probe.baseURL !== void 0 && probe.baseURL.length > 0;
@@ -1018,17 +820,31 @@ window.__ModuleLoader__.load({
1018
820
  onClick: adoptPicked,
1019
821
  children: t("fetchAdopt")
1020
822
  })] }),
1021
- children: [(0, react_jsx_runtime.jsx)("div", {
1022
- className: ModelsSection_module_css_default["candidateActions"],
1023
- children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
823
+ children: [(0, react_jsx_runtime.jsxs)("div", {
824
+ className: ModelsSection_module_css_default["candidateToolbar"],
825
+ children: [(0, react_jsx_runtime.jsx)("input", {
826
+ className: `${ModelsSection_module_css_default["input"]} ${ModelsSection_module_css_default["candidateSearch"]}`,
827
+ type: "search",
828
+ value: candidateQuery,
829
+ placeholder: t("fetchSearch"),
830
+ "aria-label": t("fetchSearch"),
831
+ onChange: (event) => {
832
+ setCandidateQuery(event.target.value);
833
+ }
834
+ }), (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
1024
835
  variant: "ghost",
1025
836
  size: "sm",
1026
- onClick: toggleAllCandidates,
1027
- children: t(allCandidatesPicked ? "fetchDeselectAll" : "fetchSelectAll")
1028
- })
1029
- }), (0, react_jsx_runtime.jsx)("ul", {
837
+ disabled: visibleCandidates.length === 0,
838
+ onClick: toggleVisibleCandidates,
839
+ children: t(allVisibleCandidatesPicked ? "fetchDeselectAll" : "fetchSelectAll")
840
+ })]
841
+ }), visibleCandidates.length === 0 ? (0, react_jsx_runtime.jsx)("p", {
842
+ className: ModelsSection_module_css_default["candidateEmpty"],
843
+ role: "status",
844
+ children: t("fetchNoMatches")
845
+ }) : (0, react_jsx_runtime.jsx)("ul", {
1030
846
  className: ModelsSection_module_css_default["candidateList"],
1031
- children: (candidates ?? []).map((candidate) => (0, react_jsx_runtime.jsx)("li", {
847
+ children: visibleCandidates.map((candidate) => (0, react_jsx_runtime.jsx)("li", {
1032
848
  className: ModelsSection_module_css_default["candidate"],
1033
849
  children: (0, react_jsx_runtime.jsxs)("label", {
1034
850
  className: ModelsSection_module_css_default["candidateLabel"],
@@ -1050,6 +866,247 @@ window.__ModuleLoader__.load({
1050
866
  });
1051
867
  }
1052
868
  //#endregion
869
+ //#region lib/types/client/store.js
870
+ /**
871
+ * Models settings page store: one snapshot joining the configurable-provider
872
+ * directory (`llm/listProviders` joined with `llm/listConfigurableProviders`),
873
+ * the settings namespaces (shared settings mirror),
874
+ * and the referenced credentials (`credentials/describe`). The host stays the
875
+ * single fact source — every mutation writes through the wire and the page
876
+ * re-renders from the next describe, pushed or refetched.
877
+ */
878
+ /**
879
+ * Any route key walks a dict schema to the same profile node, so the lookup
880
+ * names one that cannot collide with a configured route.
881
+ */
882
+ const PROBE_ROUTE = "\0probe";
883
+ /**
884
+ * Join declared configurable providers with the currently registered routes.
885
+ * @param registered - live provider routes in registration order.
886
+ * @param directory - declared configurable providers in declaration order.
887
+ * @returns declared rows followed by live routes with no declaration.
888
+ */
889
+ function joinProviderDirectory(registered, directory) {
890
+ const active = new Set(registered.map((provider) => provider.id));
891
+ const declared = new Set(directory.map((entry) => entry.provider));
892
+ const rows = directory.map((entry) => ({
893
+ provider: entry.provider,
894
+ displayName: entry.displayName,
895
+ settingsNs: entry.settingsNs,
896
+ settingsPath: [...entry.settingsPath],
897
+ active: active.has(entry.provider),
898
+ ...entry.declared === void 0 ? {} : { declared: entry.declared }
899
+ }));
900
+ for (const provider of registered) {
901
+ if (declared.has(provider.id)) continue;
902
+ rows.push({
903
+ provider: provider.id,
904
+ displayName: provider.name,
905
+ settingsNs: "",
906
+ settingsPath: [],
907
+ active: true
908
+ });
909
+ }
910
+ return rows;
911
+ }
912
+ /**
913
+ * Derive the conventional credential reference for a provider route: the v1
914
+ * page never asks for an environment-variable name, so a typed key stores
915
+ * under this derived reference and the profile records it as `apiKeyEnv`.
916
+ * @param provider - provider route id (e.g. `anthropic`, `minimax-cn`).
917
+ * @returns the derived reference name (e.g. `MINIMAX_CN_API_KEY`).
918
+ */
919
+ function deriveKeyRef(provider) {
920
+ return `${provider.toUpperCase().replace(/[^A-Z0-9]+/g, "_")}_API_KEY`;
921
+ }
922
+ /**
923
+ * The wire protocols a hand-declared route may name, read out of the owning
924
+ * namespace's own schema. This stays a schema read rather than a wire field so
925
+ * the choices the page offers cannot drift from the ones the adapter accepts:
926
+ * both come from the same `Config`.
927
+ * @param namespace - the namespace view whose schema declares the profile shape.
928
+ * @param schema - settings schema operations.
929
+ * @returns the protocol identifiers, or an empty list when the schema has none.
930
+ */
931
+ function protocolChoices(namespace, schema) {
932
+ if (namespace === void 0) return [];
933
+ const list = schema.nodeAtPath(schema.rehydrate(namespace.schema), [
934
+ "providers",
935
+ PROBE_ROUTE,
936
+ "api"
937
+ ]);
938
+ if (list?.type !== "union" || list.list === void 0) return [];
939
+ return list.list.map((entry) => entry.value).filter((value) => typeof value === "string");
940
+ }
941
+ /** The credential reference a resolved profile names (its `apiKeyEnv` field). */
942
+ function apiKeyEnvOf(namespace, path, schema) {
943
+ if (namespace === void 0) return void 0;
944
+ const profile = schema.getPath(namespace.value, path);
945
+ if (typeof profile !== "object" || profile === null) return void 0;
946
+ const ref = profile.apiKeyEnv;
947
+ return typeof ref === "string" && ref.length > 0 ? ref : void 0;
948
+ }
949
+ /** The models settings page controller (one per settings surface). */
950
+ var ModelsSettingsStore = class {
951
+ ctx;
952
+ schema;
953
+ describeFace;
954
+ /** The snapshot the section renders from (uSES-safe store). */
955
+ store = (0, _deepseek_ai_dsh_client_store.createSnapshotStore)({
956
+ status: "idle",
957
+ error: null,
958
+ credentialError: null,
959
+ writable: false,
960
+ rows: [],
961
+ namespaces: /* @__PURE__ */ new Map()
962
+ });
963
+ /** Latest load wins; an older response never overwrites a newer one. */
964
+ generation = 0;
965
+ /**
966
+ * @param ctx - the page plugin's context, whose `remote.llm` and
967
+ * `remote.credentials` namespaces carry the directory and credential reads.
968
+ * @param schema - settings-owned schema and immutable path operations.
969
+ * @param describeFace - the shared mirror's describe face (namespace views and writability).
970
+ */
971
+ constructor(ctx, schema, describeFace) {
972
+ this.ctx = ctx;
973
+ this.schema = schema;
974
+ this.describeFace = describeFace;
975
+ }
976
+ /**
977
+ * Refresh the whole page snapshot: the provider directory and the mirror's
978
+ * settings answer in parallel, then one batched credential describe over
979
+ * every referenced ref. Provider failure or absence of an initial settings
980
+ * answer keeps the last good rows and surfaces an error; a failed settings
981
+ * refresh reuses the mirror's held view.
982
+ * @returns nothing; the snapshot carries the outcome.
983
+ */
984
+ async load() {
985
+ const generation = ++this.generation;
986
+ this.store.update((s) => {
987
+ s.status = "loading";
988
+ s.error = null;
989
+ });
990
+ const [registered, declared] = await Promise.all([
991
+ this.ctx.remote.llm.listProviders(),
992
+ this.ctx.remote.llm.listConfigurableProviders(),
993
+ this.describeFace.ensure()
994
+ ]);
995
+ if (!registered.ok) {
996
+ this.failLoad(generation, registered.error.message);
997
+ return;
998
+ }
999
+ if (!declared.ok) {
1000
+ this.failLoad(generation, declared.error.message);
1001
+ return;
1002
+ }
1003
+ const mirrored = this.describeFace.getSnapshot();
1004
+ if (mirrored.view === void 0) {
1005
+ this.failLoad(generation, mirrored.error ?? "settings are unavailable in this browser");
1006
+ return;
1007
+ }
1008
+ const providers = joinProviderDirectory(registered.value, declared.value);
1009
+ const writable = mirrored.view.writable;
1010
+ const views = mirrored.view.namespaces;
1011
+ const namespaces = new Map(views.map((view) => [view.ns, view]));
1012
+ const rows = providers.map((entry) => {
1013
+ const namespace = namespaces.get(entry.settingsNs);
1014
+ return {
1015
+ entry,
1016
+ configured: namespace !== void 0 && (entry.settingsPath.length === 0 || this.schema.getPath(namespace.value, entry.settingsPath) !== void 0),
1017
+ removable: namespace !== void 0 && entry.settingsPath.length > 0 && this.schema.hasPath(namespace.user, entry.settingsPath) && !this.schema.hasPath(namespace.base, entry.settingsPath),
1018
+ apiKeyEnv: apiKeyEnvOf(namespace, entry.settingsPath, this.schema),
1019
+ credential: void 0
1020
+ };
1021
+ });
1022
+ const refs = [...new Set(rows.map((row) => row.apiKeyEnv ?? deriveKeyRef(row.entry.provider)))];
1023
+ let credentials = {};
1024
+ let credentialError = null;
1025
+ if (refs.length > 0) {
1026
+ const response = await this.ctx.remote.credentials.describe(refs);
1027
+ if (response.ok) credentials = response.value;
1028
+ else credentialError = response.error.message;
1029
+ }
1030
+ if (generation !== this.generation) return;
1031
+ this.store.update((s) => {
1032
+ s.status = "ready";
1033
+ s.error = null;
1034
+ s.credentialError = credentialError;
1035
+ s.writable = writable;
1036
+ s.rows = rows.map((row) => {
1037
+ const named = row.apiKeyEnv === void 0 ? void 0 : credentials[row.apiKeyEnv];
1038
+ const derived = row.apiKeyEnv !== void 0 ? void 0 : credentials[deriveKeyRef(row.entry.provider)];
1039
+ return {
1040
+ ...row,
1041
+ ...named === void 0 ? {} : { credential: named },
1042
+ ...derived === void 0 ? {} : { derivedCredential: derived }
1043
+ };
1044
+ });
1045
+ s.namespaces = namespaces;
1046
+ });
1047
+ }
1048
+ /** Publish one load's failure text, unless a newer load already took over. */
1049
+ failLoad(generation, message) {
1050
+ if (generation !== this.generation) return;
1051
+ this.store.update((s) => {
1052
+ s.status = "error";
1053
+ s.error = message;
1054
+ });
1055
+ }
1056
+ };
1057
+ /**
1058
+ * Whether a joined row can serve model requests as it stands: the route is
1059
+ * registered with the adapter registry, and whatever credential its resolved
1060
+ * profile names is stored. A profile naming no reference authenticates through
1061
+ * the provider's own path (the Bedrock chain, Vertex ADC, a gateway that needs
1062
+ * nothing), as does a live route with no settings address at all, so neither
1063
+ * owes this page a key.
1064
+ * @param row - one joined provider row.
1065
+ * @returns whether the user already has this provider to talk to.
1066
+ */
1067
+ function providerUsable(row) {
1068
+ if (!row.entry.active) return false;
1069
+ if (row.apiKeyEnv === void 0) return true;
1070
+ return row.credential?.configured === true;
1071
+ }
1072
+ /**
1073
+ * Project first-run readiness from the provider/settings/credential join used
1074
+ * by the Models page. The step exists to leave the user with a model to talk
1075
+ * to, so ANY usable provider ends it; only when none exists does the official
1076
+ * DeepSeek route — the one route the prompt can offer a key field for — decide
1077
+ * whether prompting can help. A missing official configurable-provider
1078
+ * declaration means the adapter is not repairable by navigating to Models.
1079
+ * @param state - current shared Models join snapshot.
1080
+ * @returns the onboarding state without reading a parallel fact source.
1081
+ */
1082
+ function onboardingReadiness(state) {
1083
+ if ((state.status === "idle" || state.status === "loading") && state.rows.length === 0) return { kind: "loading" };
1084
+ if (state.status === "error") return {
1085
+ kind: "unavailable",
1086
+ reason: "load-failed"
1087
+ };
1088
+ if (state.rows.some(providerUsable)) return { kind: "provider-ready" };
1089
+ const row = state.rows.find((candidate) => candidate.entry.provider === "deepseek-official" && candidate.entry.settingsNs === "llm-deepseek" && candidate.entry.settingsPath.length === 0);
1090
+ if (row === void 0) return { kind: "adapter-absent" };
1091
+ if (!row.entry.active) return {
1092
+ kind: "unavailable",
1093
+ reason: "provider-inactive"
1094
+ };
1095
+ if (state.credentialError !== null || row.credential === void 0) return {
1096
+ kind: "unavailable",
1097
+ reason: "credentials-unavailable"
1098
+ };
1099
+ if (!state.writable) return {
1100
+ kind: "unavailable",
1101
+ reason: "settings-read-only"
1102
+ };
1103
+ if (!row.credential.writable) return {
1104
+ kind: "unavailable",
1105
+ reason: "credential-read-only"
1106
+ };
1107
+ return { kind: "credential-missing" };
1108
+ }
1109
+ //#endregion
1053
1110
  //#region lib/types/client/CustomProviderCard.js
1054
1111
  /**
1055
1112
  * The card that declares a provider pi-ai does not ship — an OpenAI-compatible
@@ -1060,7 +1117,7 @@ window.__ModuleLoader__.load({
1060
1117
  * the provider editor with extra fields: the route id is being *chosen* here,
1061
1118
  * and the settings address does not exist until it is. One `settings.mutate`
1062
1119
  * sets the whole profile at `providers.<route>`; the key travels separately
1063
- * through `credentials.set` under the reference the profile records, exactly as
1120
+ * through `credentials/set` under the reference the profile records, exactly as
1064
1121
  * an existing provider's key does.
1065
1122
  *
1066
1123
  * The three fields a hand-declared route cannot default — endpoint, protocol,
@@ -1090,7 +1147,7 @@ window.__ModuleLoader__.load({
1090
1147
  * @returns the creation card.
1091
1148
  */
1092
1149
  function CustomProviderCard(props) {
1093
- const { taken, protocols, api, t } = props;
1150
+ const { taken, protocols, operations, t } = props;
1094
1151
  const [openedAt] = (0, react.useState)(() => props.revision);
1095
1152
  const [route, setRoute] = (0, react.useState)("");
1096
1153
  const [displayName, setDisplayName] = (0, react.useState)("");
@@ -1128,24 +1185,17 @@ window.__ModuleLoader__.load({
1128
1185
  baseURL,
1129
1186
  models: models.map((model) => ({ ...model }))
1130
1187
  };
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;
1188
+ const written = await operations.writeSettings(NS$1, [{
1189
+ op: "set",
1190
+ path: ["providers", route],
1191
+ value: profile
1192
+ }], openedAt);
1193
+ if (written.kind !== "written") return written.kind === "conflict" ? t("conflict") : written.message;
1141
1194
  setCommitted(true);
1142
1195
  }
1143
1196
  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;
1197
+ const stored = await operations.storeCredential(keyRef, keyValue);
1198
+ if (stored !== void 0) return stored;
1149
1199
  }
1150
1200
  };
1151
1201
  const create = async () => {
@@ -1158,8 +1208,6 @@ window.__ModuleLoader__.load({
1158
1208
  return;
1159
1209
  }
1160
1210
  props.onClose(true);
1161
- } catch (error) {
1162
- setFailure(messageOf(error));
1163
1211
  } finally {
1164
1212
  setBusy(false);
1165
1213
  }
@@ -1224,7 +1272,7 @@ window.__ModuleLoader__.load({
1224
1272
  className: ModelsSection_module_css_default["input"],
1225
1273
  type: "text",
1226
1274
  value: baseURL,
1227
- placeholder: "https://gateway.example/v1",
1275
+ placeholder: t("customBaseUrlPlaceholder"),
1228
1276
  "aria-label": t("baseUrl"),
1229
1277
  disabled: profileDisabled,
1230
1278
  onChange: (event) => {
@@ -1286,7 +1334,7 @@ window.__ModuleLoader__.load({
1286
1334
  ...keyValue.length === 0 ? {} : { apiKey: keyValue }
1287
1335
  },
1288
1336
  probeBlocked: keyFailure === "keyBlank" ? "keyBlankNew" : keyFailure,
1289
- api,
1337
+ operations,
1290
1338
  t,
1291
1339
  disabled: profileDisabled
1292
1340
  }),
@@ -1302,8 +1350,8 @@ window.__ModuleLoader__.load({
1302
1350
  t,
1303
1351
  busy,
1304
1352
  submitDisabled: disabled || !ready,
1305
- submitLabel: "create",
1306
- submitBusyLabel: "creating",
1353
+ submitLabelKey: "create",
1354
+ submitBusyLabelKey: "creating",
1307
1355
  onCancel: () => {
1308
1356
  props.onClose(committed);
1309
1357
  },
@@ -1319,7 +1367,7 @@ window.__ModuleLoader__.load({
1319
1367
  /**
1320
1368
  * One provider's editor card, hand-written per adapter family: the primary
1321
1369
  * 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`
1370
+ * environment-variable name — a typed key stores through `credentials/set`
1323
1371
  * under the profile's reference, deriving `<ROUTE>_API_KEY` when the profile
1324
1372
  * has none. The pi-ai profile records that derivation as `apiKeyEnv` only when
1325
1373
  * a key is entered; a blank key materializes a reference-free profile for
@@ -1391,7 +1439,7 @@ window.__ModuleLoader__.load({
1391
1439
  * @returns the editor card.
1392
1440
  */
1393
1441
  function ProviderEditor(props) {
1394
- const { namespace, schema, settingsPath, api, t } = props;
1442
+ const { namespace, schema, settingsPath, operations, t } = props;
1395
1443
  const [draft, setDraft] = (0, react.useState)(() => draftAt(schema, namespace, settingsPath));
1396
1444
  const [keyDraft, setKeyDraft] = (0, react.useState)("");
1397
1445
  const [keyState, setKeyState] = (0, react.useState)(void 0);
@@ -1417,14 +1465,14 @@ window.__ModuleLoader__.load({
1417
1465
  (0, react.useEffect)(() => {
1418
1466
  let stale = false;
1419
1467
  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);
1468
+ operations.describeCredential(keyRef).then((described) => {
1469
+ if (stale) return;
1470
+ setKeyState(described);
1471
+ });
1424
1472
  return () => {
1425
1473
  stale = true;
1426
1474
  };
1427
- }, [api.credentials, keyRef]);
1475
+ }, [operations, keyRef]);
1428
1476
  const stringAt = (source, key) => {
1429
1477
  const value = schema.getPath(source, [key]);
1430
1478
  return typeof value === "string" && value.trim().length > 0 ? value : void 0;
@@ -1472,22 +1520,15 @@ window.__ModuleLoader__.load({
1472
1520
  value: {}
1473
1521
  }] : pathOps(settingsPath, committedOriginal, next);
1474
1522
  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);
1523
+ const written = await operations.writeSettings(ns, ops, expectedRevision);
1524
+ if (written.kind !== "written") return written.kind === "conflict" ? t("conflict") : written.message;
1525
+ setCommittedOriginal(schema.getPath(written.view.user, settingsPath));
1526
+ setExpectedRevision(written.view.revision);
1483
1527
  setDraft(next);
1484
1528
  }
1485
1529
  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;
1530
+ const stored = await operations.storeCredential(keyRef, keyValue);
1531
+ if (stored !== void 0) return stored;
1491
1532
  }
1492
1533
  setKeyDraft("");
1493
1534
  };
@@ -1501,15 +1542,17 @@ window.__ModuleLoader__.load({
1501
1542
  return;
1502
1543
  }
1503
1544
  props.onClose(true);
1504
- } catch (error) {
1505
- setFailure(messageOf(error));
1506
1545
  } finally {
1507
1546
  setBusy(false);
1508
1547
  }
1509
1548
  };
1510
- if (node === void 0) return (0, react_jsx_runtime.jsx)("p", {
1549
+ if (node === void 0) return (0, react_jsx_runtime.jsxs)("p", {
1511
1550
  className: ModelsSection_module_css_default["error"],
1512
- children: `${props.provider}: unresolvable settings path`
1551
+ children: [
1552
+ props.provider,
1553
+ ": ",
1554
+ props.t("settingsPathUnresolvable")
1555
+ ]
1513
1556
  });
1514
1557
  const keyLocked = keyState?.writable === false;
1515
1558
  /**
@@ -1647,7 +1690,7 @@ window.__ModuleLoader__.load({
1647
1690
  ...catalogProps,
1648
1691
  probe,
1649
1692
  probeBlocked: keyFailure,
1650
- api
1693
+ operations
1651
1694
  })
1652
1695
  ]
1653
1696
  })]
@@ -1682,9 +1725,9 @@ window.__ModuleLoader__.load({
1682
1725
  t,
1683
1726
  busy,
1684
1727
  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 },
1728
+ submitLabelKey: props.submitLabelKey ?? "apply",
1729
+ submitBusyLabelKey: props.submitBusyLabelKey ?? "applying",
1730
+ ...props.cancelLabelKey === void 0 ? {} : { cancelLabelKey: props.cancelLabelKey },
1688
1731
  onCancel: () => {
1689
1732
  props.onClose(false);
1690
1733
  },
@@ -1726,28 +1769,21 @@ window.__ModuleLoader__.load({
1726
1769
  * and the whole operation safely retryable; both unsets are idempotent.
1727
1770
  * The settings removal names the profile rather than rebuilding its whole
1728
1771
  * namespace from a partial view.
1729
- * @param api - settings and credential wire faces.
1772
+ * @param operations - the page's Host operations.
1730
1773
  * @param controller - the page store to refresh.
1731
1774
  * @param target - the provider's settings address and optional managed credential.
1732
1775
  * @returns the failure message, or undefined once the write and reload landed.
1733
1776
  */
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);
1777
+ async function removeProviderProfile(operations, controller, target) {
1778
+ if (target.credentialRef !== void 0) {
1779
+ const credential = await operations.removeCredential(target.credentialRef);
1780
+ if (credential !== void 0) return credential;
1750
1781
  }
1782
+ const written = await operations.writeSettings(target.settingsNs, [{
1783
+ op: "unset",
1784
+ path: [...target.settingsPath]
1785
+ }], void 0);
1786
+ if (written.kind !== "written") return written.message;
1751
1787
  await controller.load();
1752
1788
  }
1753
1789
  /**
@@ -1764,6 +1800,16 @@ window.__ModuleLoader__.load({
1764
1800
  if (row.entry.settingsPath.length > 0) return false;
1765
1801
  return row.credential?.configured !== true;
1766
1802
  }
1803
+ /**
1804
+ * The provider-card seat's credential fact: the reference this page would use
1805
+ * for the row — the profile's `apiKeyEnv`, or the page's derived
1806
+ * `<ROUTE>_API_KEY` while the profile names none — confirmed configured. The
1807
+ * derived half is what keeps the seat consistent with the editor on the
1808
+ * add-provider draft, whose dormant row names no reference yet.
1809
+ */
1810
+ function keyConfiguredOf(row) {
1811
+ return row.apiKeyEnv !== void 0 ? row.credential?.configured === true : row.derivedCredential?.configured === true;
1812
+ }
1767
1813
  function targetOf(row) {
1768
1814
  const managedRef = deriveKeyRef(row.entry.provider);
1769
1815
  const credentialRef = row.apiKeyEnv === managedRef && row.credential?.configured === true && row.credential.writable ? managedRef : void 0;
@@ -1790,18 +1836,21 @@ window.__ModuleLoader__.load({
1790
1836
  * @returns the section, or null while the shell has not injected yet.
1791
1837
  */
1792
1838
  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
- } });
1839
+ const { controller, useSnapshot, operations, schema, t, renderSlot } = props;
1840
+ if (controller === void 0 || useSnapshot === void 0 || operations === void 0 || schema === void 0 || t === void 0) return null;
1841
+ return (0, react_jsx_runtime.jsx)(Loaded, {
1842
+ injected: {
1843
+ controller,
1844
+ useSnapshot,
1845
+ operations,
1846
+ schema,
1847
+ t
1848
+ },
1849
+ renderSlot
1850
+ });
1802
1851
  }
1803
- function Loaded({ injected }) {
1804
- const { controller, api, schema, t } = injected;
1852
+ function Loaded({ injected, renderSlot }) {
1853
+ const { controller, operations, schema, t } = injected;
1805
1854
  const state = injected.useSnapshot((snapshot) => snapshot);
1806
1855
  const [editing, setEditing] = (0, react.useState)(void 0);
1807
1856
  const [adding, setAdding] = (0, react.useState)(false);
@@ -1843,7 +1892,7 @@ window.__ModuleLoader__.load({
1843
1892
  if (deleteTarget === void 0 || deleting) return;
1844
1893
  setDeleting(true);
1845
1894
  setDeleteFailure(void 0);
1846
- removeProviderProfile(api, controller, deleteTarget).then((failure) => {
1895
+ removeProviderProfile(operations, controller, deleteTarget).then((failure) => {
1847
1896
  if (failure !== void 0) {
1848
1897
  setDeleteFailure(failure);
1849
1898
  return;
@@ -1882,6 +1931,7 @@ window.__ModuleLoader__.load({
1882
1931
  const addable = state.rows.filter((row) => !row.configured && row.entry.settingsNs !== "");
1883
1932
  const addTarget = adding ? editing : void 0;
1884
1933
  const addNamespace = addTarget === void 0 ? void 0 : state.namespaces.get(addTarget.settingsNs);
1934
+ const addRow = addTarget === void 0 ? void 0 : state.rows.find((row) => row.entry.provider === addTarget.provider);
1885
1935
  const protocols = protocolChoices(state.namespaces.get("llm-pi-ai"), schema);
1886
1936
  return (0, react_jsx_runtime.jsxs)("div", {
1887
1937
  className: ModelsSection_module_css_default["section"],
@@ -1911,87 +1961,99 @@ window.__ModuleLoader__.load({
1911
1961
  const namespace = state.namespaces.get(target.settingsNs);
1912
1962
  /* v8 ignore next -- the join marks a row configured only when its namespace resolved */
1913
1963
  if (namespace === void 0) return null;
1914
- if (needsSetup(row, anyUsable) && !dismissedSetup.has(row.entry.provider)) return (0, react_jsx_runtime.jsx)("li", {
1964
+ if (needsSetup(row, anyUsable) && !dismissedSetup.has(row.entry.provider)) return (0, react_jsx_runtime.jsxs)("li", {
1915
1965
  className: ModelsSection_module_css_default["setupCard"],
1916
- children: renderProviderEditor({
1966
+ children: [renderProviderEditor({
1917
1967
  target,
1918
1968
  namespace,
1919
1969
  schema,
1920
- api,
1970
+ operations,
1921
1971
  t,
1922
1972
  readOnly: !state.writable,
1923
1973
  onClose: (changed) => {
1924
1974
  closeSetup(changed, target);
1925
1975
  }
1926
- })
1976
+ }), renderSlot("settings.models.provider-card", {
1977
+ provider: row.entry,
1978
+ configured: row.configured,
1979
+ keyConfigured: keyConfiguredOf(row)
1980
+ }, { entryKey: row.entry.settingsNs })]
1927
1981
  }, row.entry.provider);
1928
1982
  const open = !adding && editing?.provider === row.entry.provider;
1929
1983
  const credentialConfigured = row.credential?.configured === true;
1930
1984
  const credentialMissing = !credentialConfigured && row.apiKeyEnv !== void 0 && row.credential?.configured === false;
1931
1985
  return (0, react_jsx_runtime.jsxs)("li", {
1932
1986
  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]
1987
+ children: [
1988
+ (0, react_jsx_runtime.jsxs)("div", {
1989
+ className: ModelsSection_module_css_default["rowHead"],
1990
+ children: [(0, react_jsx_runtime.jsxs)("span", {
1991
+ className: ModelsSection_module_css_default["rowIdentity"],
1992
+ children: [
1993
+ (0, react_jsx_runtime.jsx)("span", {
1994
+ className: ModelsSection_module_css_default["rowName"],
1995
+ children: row.entry.displayName
1996
+ }),
1997
+ row.entry.declared === true ? (0, react_jsx_runtime.jsx)("span", {
1998
+ className: ModelsSection_module_css_default["rowTag"],
1999
+ children: t("customTag")
2000
+ }) : null,
2001
+ credentialConfigured ? (0, react_jsx_runtime.jsx)("span", {
2002
+ className: `${ModelsSection_module_css_default["credentialDot"]} ${ModelsSection_module_css_default["credentialDotConfigured"]}`,
2003
+ role: "img",
2004
+ "aria-label": t("credentialConfigured"),
2005
+ title: t("credentialConfigured")
2006
+ }) : credentialMissing ? (0, react_jsx_runtime.jsx)("span", {
2007
+ className: `${ModelsSection_module_css_default["credentialDot"]} ${ModelsSection_module_css_default["credentialDotMissing"]}`,
2008
+ role: "img",
2009
+ "aria-label": t("credentialMissing"),
2010
+ title: t("credentialMissing")
2011
+ }) : null
2012
+ ]
2013
+ }), (0, react_jsx_runtime.jsxs)("span", {
2014
+ className: ModelsSection_module_css_default["rowActions"],
2015
+ children: [(0, react_jsx_runtime.jsx)("button", {
2016
+ type: "button",
2017
+ className: ModelsSection_module_css_default["secondaryButton"],
2018
+ "aria-label": providerCopy(t("editProvider"), target),
2019
+ onClick: () => {
2020
+ setSavedTarget(void 0);
2021
+ setDeclaring(false);
2022
+ setAdding(false);
2023
+ setEditing(open ? void 0 : target);
2024
+ },
2025
+ children: t("edit")
2026
+ }), row.removable ? (0, react_jsx_runtime.jsx)("button", {
2027
+ type: "button",
2028
+ className: ModelsSection_module_css_default["dangerButton"],
2029
+ "aria-label": providerCopy(t("removeProvider"), target),
2030
+ disabled: !state.writable,
2031
+ onClick: () => {
2032
+ setSavedTarget(void 0);
2033
+ setDeleteFailure(void 0);
2034
+ setDeleteTarget(target);
2035
+ },
2036
+ children: t("remove")
2037
+ }) : null]
2038
+ })]
2039
+ }),
2040
+ renderSlot("settings.models.provider-card", {
2041
+ provider: row.entry,
2042
+ configured: row.configured,
2043
+ keyConfigured: keyConfiguredOf(row)
2044
+ }, { entryKey: row.entry.settingsNs }),
2045
+ open ? renderProviderEditor({
2046
+ target,
2047
+ namespace,
2048
+ schema,
2049
+ operations,
2050
+ t,
2051
+ readOnly: !state.writable,
2052
+ onClose: (changed) => {
2053
+ closeEditor(changed, target);
2054
+ }
2055
+ }) : null
2056
+ ]
1995
2057
  }, row.entry.provider);
1996
2058
  })
1997
2059
  }),
@@ -1999,40 +2061,48 @@ window.__ModuleLoader__.load({
1999
2061
  className: ModelsSection_module_css_default["addBlock"],
2000
2062
  children: addTarget !== void 0 && addNamespace !== void 0 ? (0, react_jsx_runtime.jsxs)("div", {
2001
2063
  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)]
2064
+ children: [
2065
+ (0, react_jsx_runtime.jsxs)("div", {
2066
+ className: ModelsSection_module_css_default["field"],
2067
+ children: [(0, react_jsx_runtime.jsx)("span", {
2068
+ className: ModelsSection_module_css_default["fieldLabel"],
2069
+ children: t("provider")
2070
+ }), (0, react_jsx_runtime.jsx)("select", {
2071
+ className: `${ModelsSection_module_css_default["input"]} ${ModelsSection_module_css_default["selectInput"]}`,
2072
+ value: addTarget.provider,
2073
+ "aria-label": t("provider"),
2074
+ onChange: (event) => {
2075
+ const row = addable.find((candidate) => candidate.entry.provider === event.target.value);
2076
+ /* v8 ignore next -- the select only lists addable rows */
2077
+ if (row === void 0) return;
2078
+ setEditing(targetOf(row));
2079
+ },
2080
+ children: addable.map((row) => (0, react_jsx_runtime.jsx)("option", {
2081
+ value: row.entry.provider,
2082
+ children: row.entry.displayName
2083
+ }, row.entry.provider))
2084
+ })]
2085
+ }),
2086
+ (0, react_jsx_runtime.jsx)(ProviderEditor, {
2087
+ provider: addTarget.provider,
2088
+ displayName: addTarget.displayName,
2089
+ hideTitle: true,
2090
+ namespace: addNamespace,
2091
+ schema,
2092
+ settingsPath: addTarget.settingsPath,
2093
+ operations,
2094
+ t,
2095
+ readOnly: !state.writable,
2096
+ onClose: (changed) => {
2097
+ closeEditor(changed, addTarget);
2098
+ }
2099
+ }, addTarget.provider),
2100
+ addRow === void 0 ? null : renderSlot("settings.models.provider-card", {
2101
+ provider: addRow.entry,
2102
+ configured: addRow.configured,
2103
+ keyConfigured: keyConfiguredOf(addRow)
2104
+ }, { entryKey: addRow.entry.settingsNs })
2105
+ ]
2036
2106
  }) : declaring ? (0, react_jsx_runtime.jsx)("div", {
2037
2107
  className: ModelsSection_module_css_default["addCard"],
2038
2108
  children: (0, react_jsx_runtime.jsx)(CustomProviderCard, {
@@ -2040,7 +2110,7 @@ window.__ModuleLoader__.load({
2040
2110
  protocols,
2041
2111
  /* v8 ignore next -- the card only opens from a button disabled without this namespace */
2042
2112
  revision: state.namespaces.get("llm-pi-ai")?.revision ?? 0,
2043
- api,
2113
+ operations,
2044
2114
  t,
2045
2115
  readOnly: !state.writable,
2046
2116
  onClose: (changed) => {
@@ -2078,6 +2148,7 @@ window.__ModuleLoader__.load({
2078
2148
  })]
2079
2149
  })
2080
2150
  }),
2151
+ renderSlot("settings.models.footer", {}),
2081
2152
  (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Modal, {
2082
2153
  open: deleteTarget !== void 0,
2083
2154
  onClose: closeDelete,
@@ -2203,7 +2274,7 @@ window.__ModuleLoader__.load({
2203
2274
  * @returns the onboarding modal or null when onboarding needs no intervention.
2204
2275
  */
2205
2276
  function DeepSeekOnboardingDialog(props) {
2206
- const { complete, controller, useModels, api, schema, t } = props;
2277
+ const { complete, controller, useModels, operations, schema, t } = props;
2207
2278
  const state = useModels((snapshot) => snapshot);
2208
2279
  const readiness = onboardingReadiness(state);
2209
2280
  (0, react.useEffect)(() => {
@@ -2245,16 +2316,16 @@ window.__ModuleLoader__.load({
2245
2316
  namespace,
2246
2317
  schema,
2247
2318
  settingsPath: row.entry.settingsPath,
2248
- api,
2319
+ operations,
2249
2320
  t,
2250
2321
  readOnly: false,
2251
2322
  hideTitle: true,
2252
2323
  credentialOnly: true,
2253
2324
  credentialRequired: true,
2254
2325
  autoFocusCredential: true,
2255
- cancelLabel: "onboardingLater",
2256
- submitLabel: "onboardingSave",
2257
- submitBusyLabel: "onboardingSaving",
2326
+ cancelLabelKey: "onboardingLater",
2327
+ submitLabelKey: "onboardingSave",
2328
+ submitBusyLabelKey: "onboardingSaving",
2258
2329
  onClose: finishCredential
2259
2330
  })
2260
2331
  })]
@@ -2344,19 +2415,6 @@ window.__ModuleLoader__.load({
2344
2415
  * again. The acknowledgement is compared for exact equality.
2345
2416
  */
2346
2417
  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
2418
  //#endregion
2361
2419
  //#region lib/types/client/welcome-store.js
2362
2420
  /**
@@ -2383,7 +2441,7 @@ window.__ModuleLoader__.load({
2383
2441
  var WelcomeNoticeStore = class {
2384
2442
  scope;
2385
2443
  /** uSES-safe state source shared by the registered welcome step. */
2386
- store = (0, _deepseek_ai_dsh_client_runtime_client.createSnapshotStore)({
2444
+ store = (0, _deepseek_ai_dsh_client_store.createSnapshotStore)({
2387
2445
  status: "idle",
2388
2446
  acknowledged: false,
2389
2447
  error: null
@@ -2484,6 +2542,61 @@ window.__ModuleLoader__.load({
2484
2542
  }
2485
2543
  };
2486
2544
  //#endregion
2545
+ //#region lib/types/client/operations.js
2546
+ /**
2547
+ * The Host reads and writes the Models cards perform, as callbacks built in the
2548
+ * plugin body. Cards receive these instead of a context: the outcomes name what
2549
+ * a card renders — a stored view, a stale revision, a refusal message — so the
2550
+ * failure codes and Remote namespaces stay in the apply world.
2551
+ */
2552
+ /**
2553
+ * Bind the page's Host operations to the plugin's own Remote namespaces.
2554
+ * @param ctx - the page plugin's context, which declares `remote.credentials`,
2555
+ * `remote.llm`, and `remote.settings` in its own `inject`.
2556
+ * @returns the callbacks the section and its cards are injected with.
2557
+ */
2558
+ function createModelsOperations(ctx) {
2559
+ return {
2560
+ describeCredential: async (ref) => {
2561
+ const response = await ctx.remote.credentials.describe([ref]);
2562
+ return response.ok ? response.value[ref] : void 0;
2563
+ },
2564
+ storeCredential: async (ref, value) => {
2565
+ const response = await ctx.remote.credentials.set(ref, value);
2566
+ return response.ok ? void 0 : response.error.message;
2567
+ },
2568
+ removeCredential: async (ref) => {
2569
+ const response = await ctx.remote.credentials.unset(ref);
2570
+ return response.ok ? void 0 : response.error.message;
2571
+ },
2572
+ writeSettings: async (ns, ops, expectedRevision) => {
2573
+ const response = await ctx.remote.settings.mutate(ns, ops, expectedRevision);
2574
+ if (response.ok) return {
2575
+ kind: "written",
2576
+ view: response.value
2577
+ };
2578
+ const { code, message } = response.error;
2579
+ return code === "settings/conflict" ? {
2580
+ kind: "conflict",
2581
+ message
2582
+ } : {
2583
+ kind: "refused",
2584
+ message
2585
+ };
2586
+ },
2587
+ discoverModels: async (settingsNs, request) => {
2588
+ const response = await ctx.remote.llm.discoverModels(settingsNs, request);
2589
+ return response.ok ? {
2590
+ kind: "found",
2591
+ models: response.value
2592
+ } : {
2593
+ kind: "refused",
2594
+ message: response.error.message
2595
+ };
2596
+ }
2597
+ };
2598
+ }
2599
+ //#endregion
2487
2600
  //#region lib/types/client/schema-operations.js
2488
2601
  /**
2489
2602
  * Hide the Cordis service identity behind bound schema callbacks.
@@ -2574,6 +2687,8 @@ window.__ModuleLoader__.load({
2574
2687
  fetchEmpty: "The provider listed no models. Add them by hand.",
2575
2688
  fetchTitle: "Choose models to add",
2576
2689
  fetchDescription: "These are the models this provider has available. Choose the ones to add.",
2690
+ fetchSearch: "Search models",
2691
+ fetchNoMatches: "No matching models.",
2577
2692
  fetchSelectAll: "Select all",
2578
2693
  fetchDeselectAll: "Deselect all",
2579
2694
  fetchAdopt: "Add selected",
@@ -2589,11 +2704,13 @@ window.__ModuleLoader__.load({
2589
2704
  customApiUnset: "Not selected",
2590
2705
  customNeedsBaseUrl: "A custom provider needs a base URL.",
2591
2706
  customNeedsModels: "A custom provider needs at least one model.",
2707
+ customBaseUrlPlaceholder: "https://gateway.example/v1",
2708
+ settingsPathUnresolvable: "unresolvable settings path",
2592
2709
  create: "Create provider",
2593
2710
  creating: "Creating…",
2594
- welcomeTitle: WELCOME_NOTICE_COPY.en.title,
2595
- welcomeBody: WELCOME_NOTICE_COPY.en.body,
2596
- welcomeContinue: WELCOME_NOTICE_COPY.en.continueLabel,
2711
+ welcomeTitle: "Internal Testing Notice",
2712
+ 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.",
2713
+ welcomeContinue: "Continue",
2597
2714
  welcomeError: "The acknowledgement could not be saved. Please try again.",
2598
2715
  onboardingTitle: "Add an API key to get started",
2599
2716
  onboardingDescription: "Configure the official DeepSeek provider to start building.",
@@ -2672,6 +2789,8 @@ window.__ModuleLoader__.load({
2672
2789
  fetchEmpty: "该提供方没有列出任何模型,请手动添加。",
2673
2790
  fetchTitle: "选择要添加的模型",
2674
2791
  fetchDescription: "以下是模型提供方的可用模型,勾选要添加的模型。",
2792
+ fetchSearch: "搜索模型",
2793
+ fetchNoMatches: "没有匹配的模型。",
2675
2794
  fetchSelectAll: "全选",
2676
2795
  fetchDeselectAll: "取消全选",
2677
2796
  fetchAdopt: "添加所选",
@@ -2687,11 +2806,13 @@ window.__ModuleLoader__.load({
2687
2806
  customApiUnset: "未选择",
2688
2807
  customNeedsBaseUrl: "自定义提供方需要填写 API 地址。",
2689
2808
  customNeedsModels: "自定义提供方至少需要一个模型。",
2809
+ customBaseUrlPlaceholder: "https://gateway.example/v1",
2810
+ settingsPathUnresolvable: "无法解析设置路径",
2690
2811
  create: "创建提供方",
2691
2812
  creating: "创建中…",
2692
- welcomeTitle: WELCOME_NOTICE_COPY.zh.title,
2693
- welcomeBody: WELCOME_NOTICE_COPY.zh.body,
2694
- welcomeContinue: WELCOME_NOTICE_COPY.zh.continueLabel,
2813
+ welcomeTitle: "内测声明",
2814
+ welcomeBody: "DeepSeek Harness 目前的 0.1 版本仍处在面向 Harness 开发者进行测试的阶段,还有许多地方需要持续改进和打磨,希望听取广大开发者的反馈建议。预计 DeepSeek Harness 的核心插件以及基础 API 都会在接下来的一段时间内快速迭代、持续演化。\n\n我们期待与全球开发者一起,在开源、开放、可复用、可组合的基础设施之上,共同探索智能上限。欢迎全球 Harness 开发者加入 DSH 插件生态。",
2815
+ welcomeContinue: "继续",
2695
2816
  welcomeError: "暂时无法保存确认状态,请重试。",
2696
2817
  onboardingTitle: "添加一个 API Key 开始使用",
2697
2818
  onboardingDescription: "配置 DeepSeek 官方模型,即可开始使用。",
@@ -2721,8 +2842,10 @@ window.__ModuleLoader__.load({
2721
2842
  const inject = [
2722
2843
  "slots",
2723
2844
  "locale",
2724
- "connection",
2725
2845
  "remote",
2846
+ "remote.credentials",
2847
+ "remote.llm",
2848
+ "remote.settings",
2726
2849
  "settingsScope",
2727
2850
  "settingsSchema"
2728
2851
  ];
@@ -2737,21 +2860,21 @@ window.__ModuleLoader__.load({
2737
2860
  zh,
2738
2861
  en
2739
2862
  }), "ui-settings-models: copy dictionaries");
2740
- const connection = ctx.get("connection");
2741
2863
  const schema = createSettingsSchemaOperations(ctx.settingsSchema);
2742
- const controller = new ModelsSettingsStore(connection.api, schema, ctx.settingsScope.describe());
2864
+ const operations = createModelsOperations(ctx);
2865
+ const controller = new ModelsSettingsStore(ctx, schema, ctx.settingsScope.describe());
2743
2866
  const t = ctx.locale.bind(NS);
2744
2867
  const injected = () => ({
2745
2868
  controller,
2746
2869
  hooks: { snapshot: controller.store },
2747
- api: connection.api,
2870
+ operations,
2748
2871
  schema,
2749
2872
  t
2750
2873
  });
2751
2874
  const deepSeekOnboardingInjected = () => ({
2752
2875
  controller,
2753
2876
  hooks: { models: controller.store },
2754
- api: connection.api,
2877
+ operations,
2755
2878
  schema,
2756
2879
  t
2757
2880
  });
@@ -2786,7 +2909,17 @@ window.__ModuleLoader__.load({
2786
2909
  id: "models",
2787
2910
  order: 10,
2788
2911
  label: () => t("nav"),
2789
- inject: injected
2912
+ inject: injected,
2913
+ children: {
2914
+ "settings.models.provider-card": {
2915
+ kind: "keyed",
2916
+ scope: "root"
2917
+ },
2918
+ "settings.models.footer": {
2919
+ kind: "list",
2920
+ scope: "root"
2921
+ }
2922
+ }
2790
2923
  }, ModelsSection));
2791
2924
  ctx.slots.inject("settings.onboarding", () => ctx.slots.register({
2792
2925
  name: "settings.onboarding",