dsh-model-extension 1.2.0 → 1.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -0
- package/lib/client.js +418 -233
- package/lib/client.js.map +1 -1
- package/package.json +3 -2
package/lib/client.js
CHANGED
|
@@ -3,7 +3,7 @@ window.__ModuleLoader__.load({
|
|
|
3
3
|
factory: (require) => {
|
|
4
4
|
var module = { exports: {} };
|
|
5
5
|
var exports = module.exports;
|
|
6
|
-
var __extCss = ".J84-9a_section{max-width:720px;color:var(--dsw-alias-label-primary);flex-direction:column;gap:12px;display:flex}.J84-9a_titleRow{align-items:center;gap:10px;display:flex}.J84-9a_title{color:var(--dsw-alias-label-primary);margin:0;font-size:16px;font-weight:500;line-height:24px}.J84-9a_intro{color:var(--dsw-alias-label-tertiary);margin:0;font-size:14px;line-height:22px}.J84-9a_savedNotice{color:var(--dsw-alias-state-success-primary);margin:0;font-size:12px;line-height:18px}.J84-9a_error{color:var(--dsw-alias-state-error-primary);margin:0;font-size:12px;line-height:18px}.J84-9a_rows{flex-direction:column;gap:8px;margin:12px 0 0;padding:0;list-style:none;display:flex}.J84-9a_rowCard{border:.5px solid var(--dsw-alias-border-l4);border-radius:16px;flex-direction:column;gap:12px;padding:12px 14px;display:flex}.J84-9a_rowHead{align-items:center;gap:10px;display:flex}.J84-9a_rowIdentity{align-items:center;gap:6px;min-width:0;display:inline-flex}.J84-9a_rowName{color:var(--dsw-alias-label-primary);font-size:14px;font-weight:500;line-height:22px}.J84-9a_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}.J84-9a_credentialDot{box-sizing:border-box;border-radius:50%;flex:none;width:8px;height:8px;display:inline-block}.J84-9a_credentialDotConfigured{background:var(--dsw-alias-state-success-primary)}.J84-9a_credentialDotMissing{background:var(--dsw-alias-state-error-primary)}.J84-9a_rowActions{align-items:center;gap:4px;margin-left:auto;display:inline-flex}.J84-9a_primaryButton,.J84-9a_secondaryButton,.J84-9a_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}.J84-9a_primaryButton{background:var(--dsw-alias-button-primary-fill);color:var(--dsw-alias-label-primary-foreground)}.J84-9a_primaryButton:hover:not(:disabled){background:var(--dsw-alias-button-primary-hover)}.J84-9a_secondaryButton,.J84-9a_addButton{border:.5px solid var(--dsw-alias-border-l3);color:var(--dsw-alias-label-primary);background:0 0}.J84-9a_secondaryButton:hover:not(:disabled),.J84-9a_addButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.J84-9a_secondaryButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover-solid)}.J84-9a_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}.J84-9a_dangerButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover-danger)}.J84-9a_rowActions .J84-9a_secondaryButton,.J84-9a_rowActions .J84-9a_dangerButton{border-radius:14px;height:28px;padding:0 10px;font-size:12px;line-height:18px}.J84-9a_primaryButton:disabled,.J84-9a_secondaryButton:disabled,.J84-9a_dangerButton:disabled,.J84-9a_addButton:disabled,.J84-9a_linkButton:disabled,.J84-9a_addModelButton:disabled{opacity:.4;cursor:default}.J84-9a_primaryButton:focus-visible,.J84-9a_secondaryButton:focus-visible,.J84-9a_dangerButton:focus-visible,.J84-9a_addButton:focus-visible,.J84-9a_linkButton:focus-visible,.J84-9a_addModelButton:focus-visible,.J84-9a_iconButton:focus-visible,.J84-9a_customizedSummary:focus-visible{box-shadow:0 0 0 2px var(--dsw-alias-border-l3);outline:none}.J84-9a_editor{background:var(--dsw-alias-bg-module-platform);border-radius:12px;flex-direction:column;gap:14px;padding:14px 16px;display:flex}.J84-9a_field{flex-direction:column;gap:6px;display:flex}.J84-9a_fieldLabel{color:var(--dsw-alias-label-secondary);align-items:center;gap:10px;font-size:12px;font-weight:500;line-height:18px;display:inline-flex}.J84-9a_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}.J84-9a_linkButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-secondary)}.J84-9a_advancedHint{color:var(--dsw-alias-label-tertiary);margin:0;font-size:12px;line-height:18px}.J84-9a_editorActions{justify-content:flex-end;gap:8px;display:flex}.J84-9a_addBlock{flex-direction:column;gap:12px;display:flex}.J84-9a_addActions{flex-wrap:wrap;gap:10px;display:flex}.J84-9a_addButton{border:1px dashed var(--dsw-alias-border-l3);border-radius:16px;flex:1 1 0;gap:6px;min-width:180px;height:44px}.J84-9a_addCard{background:var(--dsw-alias-bg-module-platform);border-radius:12px;flex-direction:column;gap:14px;padding:14px 16px;list-style:none;display:flex}.J84-9a_addCard .J84-9a_editor,.J84-9a_setupCard .J84-9a_editor{background:0 0;padding:0}.J84-9a_tabs{flex-direction:column;gap:12px;display:flex}.J84-9a_tabBar{border-bottom:.5px solid var(--dsw-alias-border-l2);gap:4px;display:flex}.J84-9a_tabButton{appearance:none;font:inherit;color:var(--dsw-alias-label-tertiary);cursor:pointer;background:0 0;border:none;padding:6px 12px 8px;font-size:13px;line-height:20px;position:relative}.J84-9a_tabButton:hover{color:var(--dsw-alias-label-primary)}.J84-9a_tabButton:disabled{opacity:.4;cursor:default}.J84-9a_tabButtonActive{color:var(--dsw-alias-label-primary);font-weight:500}.J84-9a_tabButtonActive:after{content:\"\";background:var(--dsw-alias-brand-primary);border-radius:2px;height:2px;position:absolute;bottom:-1px;left:10px;right:10px}.J84-9a_tabPanel{flex-direction:column;gap:12px;display:flex}.J84-9a_modelCatalog{flex-direction:column;gap:10px;display:flex}.J84-9a_modelCatalogHeading{flex-direction:column;gap:2px;display:flex}.J84-9a_modelCatalogTitle{color:var(--dsw-alias-label-secondary);font-size:12px;font-weight:500;line-height:18px}.J84-9a_modelCatalogMeta,.J84-9a_modelEmpty{color:var(--dsw-alias-label-tertiary);margin:0;font-size:12px;line-height:18px}.J84-9a_modelList{flex-direction:column;gap:8px;display:flex}.J84-9a_modelListHead{justify-content:space-between;align-items:flex-start;gap:12px;display:flex}.J84-9a_modelEntry{border:.5px solid var(--dsw-alias-border-l4);border-radius:10px;padding:6px}.J84-9a_modelRow{grid-template-columns:minmax(0,1.4fr) minmax(0,1fr) auto auto;align-items:center;gap:6px;display:grid}.J84-9a_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}.J84-9a_iconButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.J84-9a_iconButton:disabled{cursor:default;opacity:.4}.J84-9a_iconButtonDanger:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover-danger);color:var(--dsw-alias-state-error-primary)}.J84-9a_modelAdvanced{grid-template-columns:repeat(auto-fit,minmax(160px,1fr));gap:8px;padding:8px 4px 2px;display:grid}.J84-9a_modelField{flex-direction:column;gap:4px;display:flex}.J84-9a_modelFieldLabel{color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:18px}.J84-9a_modelEmpty{border:1px dashed var(--dsw-alias-border-l3);text-align:center;border-radius:8px;padding:12px}.J84-9a_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}.J84-9a_addModelButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.J84-9a_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.J84-9a_input{cursor:pointer;max-width:240px}.J84-9a_input:focus{border-color:var(--dsw-alias-brand-primary);outline:none}.J84-9a_input::placeholder{color:var(--dsw-alias-label-dimmed)}.J84-9a_input:disabled{opacity:.6;cursor:default}.J84-9a_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}.J84-9a_deleteDialog{width:min(480px,100%)}.J84-9a_deleteConfirm:not(:disabled){border-color:var(--dsw-alias-state-error-primary);color:var(--dsw-alias-state-error-primary)}.J84-9a_deleteConfirm:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover-danger)}.J84-9a_fetchDialog{max-width:520px}.J84-9a_candidateToolbar{align-items:center;gap:8px;margin-bottom:6px;display:flex}.J84-9a_candidateSearch{flex:240px;min-width:0}.J84-9a_candidateList{flex-direction:column;gap:2px;max-height:320px;margin:0;padding:0;list-style:none;display:flex;overflow-y:auto}.J84-9a_candidate{border-radius:6px}.J84-9a_candidateLabel{cursor:pointer;align-items:center;gap:8px;padding:6px 8px;display:flex}.J84-9a_candidateId{overflow-wrap:anywhere;flex:auto;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:13px}.J84-9a_candidateEmpty{color:var(--dsw-alias-label-secondary);text-align:center;margin:24px 0;font-size:13px;line-height:20px}[hidden]{display:none!important}.J84-9a_extBlock{border:.5px solid var(--dsw-alias-border-l3);background:var(--dsw-alias-bg-layer-1);border-radius:10px;flex-direction:column;gap:10px;margin:8px 4px 2px;padding:10px;display:flex}.J84-9a_extGroup{border-top:.5px solid var(--dsw-alias-border-l2);padding-top:12px}.J84-9a_extGroupFirst{border-top:none;padding-top:0}.J84-9a_extCheck{cursor:pointer;align-items:flex-start;gap:8px;display:flex}.J84-9a_extCheckLabel{color:var(--dsw-alias-label-primary);font-size:14px;line-height:22px}.J84-9a_extHint{color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:18px}.J84-9a_extGated{flex-direction:column;gap:12px;padding-left:2px;display:flex}.J84-9a_extField{flex-direction:column;gap:6px;display:flex}.J84-9a_extLabel{color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:18px}.J84-9a_extTable{border:.5px solid var(--dsw-alias-border-l4);border-radius:8px;overflow:hidden}.J84-9a_extTHead{color:var(--dsw-alias-label-tertiary);background:var(--dsw-alias-bg-module-platform);grid-template-columns:64px minmax(0,1fr) minmax(0,1.2fr);font-size:12px;line-height:18px;display:grid}.J84-9a_extTHead>div{padding:6px 10px}.J84-9a_extTHead>div+div{border-left:.5px solid var(--dsw-alias-border-l2)}.J84-9a_extTRow{border-top:.5px solid var(--dsw-alias-border-l2);grid-template-columns:64px minmax(0,1fr) minmax(0,1.2fr);align-items:center;display:grid}.J84-9a_extTRow>div{padding:6px 10px;font-size:14px}.J84-9a_extTRow>div+div{border-left:.5px solid var(--dsw-alias-border-l2)}.J84-9a_extTRow input[type=text]{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}.J84-9a_extTRow input[type=text]:disabled{opacity:.6;cursor:default}.J84-9a_extCheckbox{accent-color:var(--dsw-alias-brand-primary);flex:none;width:15px;height:15px}.J84-9a_switchRow{cursor:pointer;align-items:center;gap:8px;font-size:14px;line-height:22px;display:flex}.J84-9a_extTag{background:var(--dsw-static-deepseek-100);color:var(--dsw-static-deepseek-600);border:.5px solid #4176e659;border-radius:4px;flex:none;padding:1px 6px;font-size:11px;font-weight:500;line-height:16px}.J84-9a_modalMask{background:var(--dsw-alias-bg-mask-1);z-index:100;justify-content:center;align-items:center;padding:24px;display:flex;position:fixed;inset:0}.J84-9a_modal{background:var(--dsw-specific-menu);border-radius:16px;width:100%;padding:20px;box-shadow:0 12px 40px #0000002e}.J84-9a_modalTitle{color:var(--dsw-alias-label-primary);margin-bottom:8px;font-size:16px;font-weight:500;line-height:24px}.J84-9a_modalDesc{color:var(--dsw-alias-label-secondary);margin-bottom:16px;font-size:14px;line-height:22px}.J84-9a_modalFoot{justify-content:flex-end;gap:8px;display:flex}.J84-9a_quickWrap{flex-direction:column;gap:6px;display:flex;position:relative}.J84-9a_quickList{z-index:20;border:.5px solid var(--dsw-alias-border-l3);background:var(--dsw-specific-menu);border-radius:8px;max-height:264px;margin-top:2px;padding:4px;position:absolute;top:100%;left:0;right:0;overflow-y:auto;box-shadow:0 8px 24px #0000001f}.J84-9a_quickItem{width:100%;color:var(--dsw-alias-label-primary);text-align:left;cursor:pointer;overflow-wrap:anywhere;background:0 0;border:none;border-radius:6px;padding:6px 8px;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:13px;display:block}.J84-9a_quickItem:hover{background:var(--dsw-alias-interactive-bg-hover)}.J84-9a_quickEmpty{color:var(--dsw-alias-label-tertiary);padding:6px 8px;font-size:12px;line-height:18px}@media (prefers-reduced-motion:reduce){.J84-9a_customizedSummary:before{transition:none}}\n";
|
|
6
|
+
var __extCss = ".J84-9a_section{max-width:720px;color:var(--dsw-alias-label-primary);flex-direction:column;gap:12px;display:flex}.J84-9a_titleRow{align-items:center;gap:10px;display:flex}.J84-9a_title{color:var(--dsw-alias-label-primary);margin:0;font-size:16px;font-weight:500;line-height:24px}.J84-9a_intro{color:var(--dsw-alias-label-tertiary);margin:0;font-size:14px;line-height:22px}.J84-9a_savedNotice{color:var(--dsw-alias-state-success-primary);margin:0;font-size:12px;line-height:18px}.J84-9a_error{color:var(--dsw-alias-state-error-primary);margin:0;font-size:12px;line-height:18px}.J84-9a_rows{flex-direction:column;gap:8px;margin:12px 0 0;padding:0;list-style:none;display:flex}.J84-9a_rowCard{border:.5px solid var(--dsw-alias-border-l4);border-radius:16px;flex-direction:column;gap:12px;padding:12px 14px;display:flex}.J84-9a_rowHead{align-items:center;gap:10px;display:flex}.J84-9a_rowIdentity{align-items:center;gap:6px;min-width:0;display:inline-flex}.J84-9a_rowName{color:var(--dsw-alias-label-primary);font-size:14px;font-weight:500;line-height:22px}.J84-9a_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}.J84-9a_credentialDot{box-sizing:border-box;border-radius:50%;flex:none;width:8px;height:8px;display:inline-block}.J84-9a_credentialDotConfigured{background:var(--dsw-alias-state-success-primary)}.J84-9a_credentialDotMissing{background:var(--dsw-alias-state-error-primary)}.J84-9a_rowActions{align-items:center;gap:4px;margin-left:auto;display:inline-flex}.J84-9a_primaryButton,.J84-9a_secondaryButton,.J84-9a_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}.J84-9a_primaryButton{background:var(--dsw-alias-button-primary-fill);color:var(--dsw-alias-label-primary-foreground)}.J84-9a_primaryButton:hover:not(:disabled){background:var(--dsw-alias-button-primary-hover)}.J84-9a_secondaryButton,.J84-9a_addButton{border:.5px solid var(--dsw-alias-border-l3);color:var(--dsw-alias-label-primary);background:0 0}.J84-9a_secondaryButton:hover:not(:disabled),.J84-9a_addButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.J84-9a_secondaryButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover-solid)}.J84-9a_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}.J84-9a_dangerButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover-danger)}.J84-9a_rowActions .J84-9a_secondaryButton,.J84-9a_rowActions .J84-9a_dangerButton{border-radius:14px;height:28px;padding:0 10px;font-size:12px;line-height:18px}.J84-9a_primaryButton:disabled,.J84-9a_secondaryButton:disabled,.J84-9a_dangerButton:disabled,.J84-9a_addButton:disabled,.J84-9a_linkButton:disabled,.J84-9a_addModelButton:disabled{opacity:.4;cursor:default}.J84-9a_primaryButton:focus-visible,.J84-9a_secondaryButton:focus-visible,.J84-9a_dangerButton:focus-visible,.J84-9a_addButton:focus-visible,.J84-9a_linkButton:focus-visible,.J84-9a_addModelButton:focus-visible,.J84-9a_iconButton:focus-visible,.J84-9a_customizedSummary:focus-visible{box-shadow:0 0 0 2px var(--dsw-alias-border-l3);outline:none}.J84-9a_editor{background:var(--dsw-alias-bg-module-platform);border-radius:12px;flex-direction:column;gap:14px;padding:14px 16px;display:flex}.J84-9a_field{flex-direction:column;gap:6px;display:flex}.J84-9a_fieldLabel{color:var(--dsw-alias-label-secondary);align-items:center;gap:10px;font-size:12px;font-weight:500;line-height:18px;display:inline-flex}.J84-9a_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}.J84-9a_linkButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-secondary)}.J84-9a_advancedHint{color:var(--dsw-alias-label-tertiary);margin:0;font-size:12px;line-height:18px}.J84-9a_editorActions{justify-content:flex-end;gap:8px;display:flex}.J84-9a_addBlock{flex-direction:column;gap:12px;display:flex}.J84-9a_addActions{flex-wrap:wrap;gap:10px;display:flex}.J84-9a_addButton{border:1px dashed var(--dsw-alias-border-l3);border-radius:16px;flex:1 1 0;gap:6px;min-width:180px;height:44px}.J84-9a_addCard{background:var(--dsw-alias-bg-module-platform);border-radius:12px;flex-direction:column;gap:14px;padding:14px 16px;list-style:none;display:flex}.J84-9a_addCard .J84-9a_editor,.J84-9a_setupCard .J84-9a_editor{background:0 0;padding:0}.J84-9a_tabs{flex-direction:column;gap:12px;display:flex}.J84-9a_tabBar{border-bottom:.5px solid var(--dsw-alias-border-l2);gap:4px;display:flex}.J84-9a_tabButton{appearance:none;font:inherit;color:var(--dsw-alias-label-tertiary);cursor:pointer;background:0 0;border:none;padding:6px 12px 8px;font-size:13px;line-height:20px;position:relative}.J84-9a_tabButton:hover{color:var(--dsw-alias-label-primary)}.J84-9a_tabButton:disabled{opacity:.4;cursor:default}.J84-9a_tabButtonActive{color:var(--dsw-alias-label-primary);font-weight:500}.J84-9a_tabButtonActive:after{content:\"\";background:var(--dsw-alias-brand-primary);border-radius:2px;height:2px;position:absolute;bottom:-1px;left:10px;right:10px}.J84-9a_tabPanel{flex-direction:column;gap:12px;display:flex}.J84-9a_modelCatalog{flex-direction:column;gap:10px;display:flex}.J84-9a_modelCatalogHeading{flex-direction:column;gap:2px;display:flex}.J84-9a_modelCatalogTitle{color:var(--dsw-alias-label-secondary);font-size:12px;font-weight:500;line-height:18px}.J84-9a_modelCatalogMeta,.J84-9a_modelEmpty{color:var(--dsw-alias-label-tertiary);margin:0;font-size:12px;line-height:18px}.J84-9a_modelList{flex-direction:column;gap:8px;display:flex}.J84-9a_modelListHead{justify-content:space-between;align-items:flex-start;gap:12px;display:flex}.J84-9a_modelEntry{border:.5px solid var(--dsw-alias-border-l4);border-radius:10px;padding:6px}.J84-9a_modelRow{grid-template-columns:minmax(0,1.4fr) minmax(0,1fr) auto auto;align-items:center;gap:6px;display:grid}.J84-9a_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}.J84-9a_iconButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.J84-9a_iconButton:disabled{cursor:default;opacity:.4}.J84-9a_iconButtonDanger:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover-danger);color:var(--dsw-alias-state-error-primary)}.J84-9a_modelAdvanced{grid-template-columns:repeat(auto-fit,minmax(160px,1fr));gap:8px;padding:8px 4px 2px;display:grid}.J84-9a_modelField{flex-direction:column;gap:4px;display:flex}.J84-9a_modelFieldLabel{color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:18px}.J84-9a_modelEmpty{border:1px dashed var(--dsw-alias-border-l3);text-align:center;border-radius:8px;padding:12px}.J84-9a_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}.J84-9a_addModelButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.J84-9a_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.J84-9a_input{cursor:pointer;max-width:240px}.J84-9a_input:focus{border-color:var(--dsw-alias-brand-primary);outline:none}.J84-9a_input::placeholder{color:var(--dsw-alias-label-dimmed)}.J84-9a_input:disabled{opacity:.6;cursor:default}.J84-9a_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}.J84-9a_deleteDialog{width:min(480px,100%)}.J84-9a_deleteConfirm:not(:disabled){border-color:var(--dsw-alias-state-error-primary);color:var(--dsw-alias-state-error-primary)}.J84-9a_deleteConfirm:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover-danger)}.J84-9a_fetchDialog{max-width:520px}.J84-9a_candidateToolbar{align-items:center;gap:8px;margin-bottom:6px;display:flex}.J84-9a_candidateSearch{flex:240px;min-width:0}.J84-9a_candidateList{flex-direction:column;gap:2px;max-height:320px;margin:0;padding:0;list-style:none;display:flex;overflow-y:auto}.J84-9a_candidate{border-radius:6px}.J84-9a_candidateLabel{cursor:pointer;align-items:center;gap:8px;padding:6px 8px;display:flex}.J84-9a_candidateId{overflow-wrap:anywhere;flex:auto;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:13px}.J84-9a_candidateEmpty{color:var(--dsw-alias-label-secondary);text-align:center;margin:24px 0;font-size:13px;line-height:20px}[hidden]{display:none!important}.J84-9a_extBlock{border:.5px solid var(--dsw-alias-border-l3);background:var(--dsw-alias-bg-layer-1);border-radius:10px;flex-direction:column;gap:10px;margin:8px 4px 2px;padding:10px;display:flex}.J84-9a_extGroup{border-top:.5px solid var(--dsw-alias-border-l2);padding-top:12px}.J84-9a_extGroupFirst{border-top:none;padding-top:0}.J84-9a_extCheck{cursor:pointer;align-items:flex-start;gap:8px;display:flex}.J84-9a_extCheckLabel{color:var(--dsw-alias-label-primary);font-size:14px;line-height:22px}.J84-9a_extHint{color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:18px}.J84-9a_extGated{flex-direction:column;gap:12px;padding-left:2px;display:flex}.J84-9a_extField{flex-direction:column;gap:6px;display:flex}.J84-9a_extLabel{color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:18px}.J84-9a_extTable{border:.5px solid var(--dsw-alias-border-l4);border-radius:8px;overflow:hidden}.J84-9a_extTHead{color:var(--dsw-alias-label-tertiary);background:var(--dsw-alias-bg-module-platform);grid-template-columns:64px minmax(0,1fr) minmax(0,1.2fr);font-size:12px;line-height:18px;display:grid}.J84-9a_extTHead>div{padding:6px 10px}.J84-9a_extTHead>div+div{border-left:.5px solid var(--dsw-alias-border-l2)}.J84-9a_extTRow{border-top:.5px solid var(--dsw-alias-border-l2);grid-template-columns:64px minmax(0,1fr) minmax(0,1.2fr);align-items:center;display:grid}.J84-9a_extTRow>div{padding:6px 10px;font-size:14px}.J84-9a_extTRow>div+div{border-left:.5px solid var(--dsw-alias-border-l2)}.J84-9a_extTRow input[type=text]{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}.J84-9a_extTRow input[type=text]:disabled{opacity:.6;cursor:default}.J84-9a_extCheckbox{accent-color:var(--dsw-alias-brand-primary);flex:none;width:15px;height:15px}.J84-9a_switchRow{cursor:pointer;align-items:center;gap:8px;font-size:14px;line-height:22px;display:flex}.J84-9a_extTag{background:var(--dsw-static-deepseek-100);color:var(--dsw-static-deepseek-600);border:.5px solid #4176e659;border-radius:4px;flex:none;padding:1px 6px;font-size:11px;font-weight:500;line-height:16px}.J84-9a_modalMask{background:var(--dsw-alias-bg-mask-1);z-index:100;justify-content:center;align-items:center;padding:24px;display:flex;position:fixed;inset:0}.J84-9a_modal{background:var(--dsw-specific-menu);border-radius:16px;width:100%;padding:20px;box-shadow:0 12px 40px #0000002e}.J84-9a_modalTitle{color:var(--dsw-alias-label-primary);margin-bottom:8px;font-size:16px;font-weight:500;line-height:24px}.J84-9a_modalDesc{color:var(--dsw-alias-label-secondary);margin-bottom:16px;font-size:14px;line-height:22px}.J84-9a_modalFoot{justify-content:flex-end;gap:8px;display:flex}.J84-9a_quickWrap{flex-direction:column;gap:6px;display:flex;position:relative}.J84-9a_quickList{z-index:20;border:.5px solid var(--dsw-alias-border-l3);background:var(--dsw-specific-menu);border-radius:8px;max-height:264px;margin-top:2px;padding:4px;position:absolute;top:100%;left:0;right:0;overflow-y:auto;box-shadow:0 8px 24px #0000001f}.J84-9a_quickItem{width:100%;color:var(--dsw-alias-label-primary);text-align:left;cursor:pointer;background:0 0;border:none;border-radius:6px;flex-direction:column;gap:1px;padding:6px 8px;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:13px;display:flex}.J84-9a_quickItemId{overflow-wrap:anywhere}.J84-9a_quickItemApi{color:var(--dsw-alias-label-tertiary);letter-spacing:.2px;font-size:11px;line-height:14px}.J84-9a_quickItem:hover{background:var(--dsw-alias-interactive-bg-hover)}.J84-9a_quickEmpty{color:var(--dsw-alias-label-tertiary);padding:6px 8px;font-size:12px;line-height:18px}@media (prefers-reduced-motion:reduce){.J84-9a_customizedSummary:before{transition:none}}\n";
|
|
7
7
|
if (typeof document !== 'undefined' && document.querySelector('style[data-plugin-css="dsh-model-extension"]') === null) {
|
|
8
8
|
var __tag = document.createElement('style');
|
|
9
9
|
__tag.dataset.plugin = "dsh-model-extension";
|
|
@@ -369,6 +369,29 @@ if (typeof document !== 'undefined' && document.querySelector('style[data-plugin
|
|
|
369
369
|
return cachedIndex;
|
|
370
370
|
}
|
|
371
371
|
/**
|
|
372
|
+
* The one wire protocol one catalog provider's entries agree on.
|
|
373
|
+
*
|
|
374
|
+
* This mirrors the host's own `sharedCatalogApi`: a route whose installed
|
|
375
|
+
* entries all speak the same protocol needs no `api` in configuration, because
|
|
376
|
+
* the host resolves every model — including ones the catalog does not describe
|
|
377
|
+
* — to that shared protocol. Reading it here is what lets the panel judge a
|
|
378
|
+
* row's compat switches the way the adapter will. A provider whose entries
|
|
379
|
+
* disagree (an OpenAI-style catalog spanning Responses and Chat Completions)
|
|
380
|
+
* has no such answer, and neither does an index that has not loaded yet.
|
|
381
|
+
* @param index - the fetched index, or undefined while the page still loads.
|
|
382
|
+
* @param provider - the route key to inspect.
|
|
383
|
+
* @returns the shared protocol, or undefined when none settles it.
|
|
384
|
+
*/
|
|
385
|
+
function sharedCatalogApi(index, provider) {
|
|
386
|
+
if (index === void 0 || provider === void 0 || provider.length === 0) return void 0;
|
|
387
|
+
const apis = /* @__PURE__ */ new Set();
|
|
388
|
+
for (const entry of index.piAi) {
|
|
389
|
+
if (entry.provider !== provider || entry.api === void 0) continue;
|
|
390
|
+
apis.add(entry.api);
|
|
391
|
+
}
|
|
392
|
+
return apis.size === 1 ? [...apis][0] : void 0;
|
|
393
|
+
}
|
|
394
|
+
/**
|
|
372
395
|
* Download/refresh the models.dev file through the server half (user-triggered
|
|
373
396
|
* from the title-row button). A success also refreshes the local cache.
|
|
374
397
|
*/
|
|
@@ -447,181 +470,6 @@ if (typeof document !== 'undefined' && document.querySelector('style[data-plugin
|
|
|
447
470
|
};
|
|
448
471
|
}
|
|
449
472
|
//#endregion
|
|
450
|
-
//#region src/client/models-plus/compat.ts
|
|
451
|
-
/**
|
|
452
|
-
* The minimal path ops carrying `after` over `before`, both as the card sees
|
|
453
|
-
* them. Only keys the card observed are named; fields absent from both sides
|
|
454
|
-
* produce no op, which is why edits are path-addressed rather than a rebuilt
|
|
455
|
-
* section.
|
|
456
|
-
* @param base - path of the edited subtree inside the user section.
|
|
457
|
-
* @param before - the subtree as loaded, or undefined when it is new.
|
|
458
|
-
* @param after - the subtree as edited.
|
|
459
|
-
* @returns ordered set/unset ops; empty when nothing changed.
|
|
460
|
-
*/
|
|
461
|
-
function pathOps(base, before, after) {
|
|
462
|
-
const previous = typeof before === "object" && before !== null && !Array.isArray(before) ? before : {};
|
|
463
|
-
const ops = [];
|
|
464
|
-
for (const [key, value] of Object.entries(after)) {
|
|
465
|
-
if (JSON.stringify(previous[key]) === JSON.stringify(value)) continue;
|
|
466
|
-
ops.push({
|
|
467
|
-
op: "set",
|
|
468
|
-
path: [...base, key],
|
|
469
|
-
value
|
|
470
|
-
});
|
|
471
|
-
}
|
|
472
|
-
for (const key of Object.keys(previous)) if (!(key in after)) ops.push({
|
|
473
|
-
op: "unset",
|
|
474
|
-
path: [...base, key]
|
|
475
|
-
});
|
|
476
|
-
return ops;
|
|
477
|
-
}
|
|
478
|
-
/** Accepted capacity spellings: a decimal count with an optional K/M suffix. */
|
|
479
|
-
const CAPACITY_PATTERN = /^(\d+(?:\.\d+)?)([km])?$/i;
|
|
480
|
-
/** Decimal suffix scales — `1M` is 1000K, matching how model capacities are quoted. */
|
|
481
|
-
const CAPACITY_SCALE = {
|
|
482
|
-
k: 1e3,
|
|
483
|
-
m: 1e6
|
|
484
|
-
};
|
|
485
|
-
/**
|
|
486
|
-
* Read a typed capacity, so a user can write `256K` or `1M` instead of counting
|
|
487
|
-
* zeroes. The stored value stays a plain token count.
|
|
488
|
-
* @param text - raw field text.
|
|
489
|
-
* @returns the count; `undefined` when blank (inherit), `NaN` when unreadable
|
|
490
|
-
* (rejected by {@link validateModelRows} before any write).
|
|
491
|
-
*/
|
|
492
|
-
function parseCapacity(text) {
|
|
493
|
-
const trimmed = text.trim();
|
|
494
|
-
if (trimmed.length === 0) return void 0;
|
|
495
|
-
const match = CAPACITY_PATTERN.exec(trimmed);
|
|
496
|
-
if (match === null) return NaN;
|
|
497
|
-
const suffix = match[2]?.toLowerCase();
|
|
498
|
-
const scale = suffix === "k" || suffix === "m" ? CAPACITY_SCALE[suffix] : 1;
|
|
499
|
-
const scaled = Number(match[1]) * scale;
|
|
500
|
-
const rounded = Math.round(scaled);
|
|
501
|
-
return Math.abs(scaled - rounded) < 1e-6 ? rounded : scaled;
|
|
502
|
-
}
|
|
503
|
-
/**
|
|
504
|
-
* Spell a stored count back in the shortest form that survives a round trip
|
|
505
|
-
* through {@link parseCapacity}; a count that is not a whole number of
|
|
506
|
-
* thousands stays written out.
|
|
507
|
-
* @param value - stored capacity.
|
|
508
|
-
* @returns the field text.
|
|
509
|
-
*/
|
|
510
|
-
function formatCapacity(value) {
|
|
511
|
-
if (!Number.isInteger(value) || value <= 0) return String(value);
|
|
512
|
-
if (value % CAPACITY_SCALE.m === 0) return `${String(value / CAPACITY_SCALE.m)}M`;
|
|
513
|
-
if (value % CAPACITY_SCALE.k === 0) return `${String(value / CAPACITY_SCALE.k)}K`;
|
|
514
|
-
return String(value);
|
|
515
|
-
}
|
|
516
|
-
/** Convert a schema-validated catalog value into records without dropping hidden fields. */
|
|
517
|
-
function modelDrafts(value) {
|
|
518
|
-
if (!Array.isArray(value)) return [];
|
|
519
|
-
return value.map((entry) => typeof entry === "object" && entry !== null && !Array.isArray(entry) ? entry : {});
|
|
520
|
-
}
|
|
521
|
-
/** Canonical key order for one models[] row (plugin-known fields first). */
|
|
522
|
-
const ROW_KEY_ORDER = [
|
|
523
|
-
"id",
|
|
524
|
-
"name",
|
|
525
|
-
"contextWindow",
|
|
526
|
-
"maxTokens",
|
|
527
|
-
"input",
|
|
528
|
-
"reasoningEfforts",
|
|
529
|
-
"compat"
|
|
530
|
-
];
|
|
531
|
-
/** Canonical key order for the row's compat sub-object. */
|
|
532
|
-
const COMPAT_KEY_ORDER = [
|
|
533
|
-
"supportsDeveloperRole",
|
|
534
|
-
"supportsReasoningEffort",
|
|
535
|
-
"thinkingFormat"
|
|
536
|
-
];
|
|
537
|
-
/**
|
|
538
|
-
* Re-key one model row into the canonical order (plugin-known fields in
|
|
539
|
-
* order, unknown/future fields kept at the tail so nothing is dropped).
|
|
540
|
-
* YAML emits keys in object insertion order, and interactive edits append
|
|
541
|
-
* keys at the tail — without this, rows saved after quick-load or gated-key
|
|
542
|
-
* removals come out with scrambled key orders (purely cosmetic, but noisy
|
|
543
|
-
* in settings.yaml diffs).
|
|
544
|
-
* @param row - the drafted row.
|
|
545
|
-
* @returns the re-keyed row (shallow copy).
|
|
546
|
-
*/
|
|
547
|
-
function normalizeModelRow(row) {
|
|
548
|
-
const next = {};
|
|
549
|
-
for (const key of ROW_KEY_ORDER) if (key in row) next[key] = row[key];
|
|
550
|
-
for (const key of Object.keys(row)) if (!ROW_KEY_ORDER.includes(key)) next[key] = row[key];
|
|
551
|
-
const compat = next["compat"];
|
|
552
|
-
if (typeof compat === "object" && compat !== null && !Array.isArray(compat)) {
|
|
553
|
-
const source = compat;
|
|
554
|
-
const normalized = {};
|
|
555
|
-
for (const key of COMPAT_KEY_ORDER) if (key in source) normalized[key] = source[key];
|
|
556
|
-
for (const key of Object.keys(source)) if (!COMPAT_KEY_ORDER.includes(key)) normalized[key] = source[key];
|
|
557
|
-
next["compat"] = normalized;
|
|
558
|
-
}
|
|
559
|
-
return next;
|
|
560
|
-
}
|
|
561
|
-
/**
|
|
562
|
-
* Validate adapter constraints that the serialized schema cannot express.
|
|
563
|
-
* @param value - user-owned `models` value, or undefined while inherited.
|
|
564
|
-
* @returns the first invalid row, or undefined when the adapter will accept it.
|
|
565
|
-
*/
|
|
566
|
-
function validateModelRows(value) {
|
|
567
|
-
if (value === void 0) return void 0;
|
|
568
|
-
const models = modelDrafts(value);
|
|
569
|
-
const seen = /* @__PURE__ */ new Set();
|
|
570
|
-
for (const [index, model] of models.entries()) {
|
|
571
|
-
const id = model["id"];
|
|
572
|
-
const trimmed = typeof id === "string" ? id.trim() : void 0;
|
|
573
|
-
if (trimmed === void 0 || trimmed.length === 0) return {
|
|
574
|
-
index,
|
|
575
|
-
key: "modelIdRequired"
|
|
576
|
-
};
|
|
577
|
-
if (seen.has(trimmed)) return {
|
|
578
|
-
index,
|
|
579
|
-
key: "modelIdDuplicate"
|
|
580
|
-
};
|
|
581
|
-
seen.add(trimmed);
|
|
582
|
-
const name = model["name"];
|
|
583
|
-
if (name !== void 0 && (typeof name !== "string" || name.length === 0)) return {
|
|
584
|
-
index,
|
|
585
|
-
key: "modelNameInvalid"
|
|
586
|
-
};
|
|
587
|
-
const contextWindow = model["contextWindow"];
|
|
588
|
-
if (contextWindow !== void 0 && (typeof contextWindow !== "number" || !Number.isInteger(contextWindow) || contextWindow <= 0)) return {
|
|
589
|
-
index,
|
|
590
|
-
key: "modelContextInvalid"
|
|
591
|
-
};
|
|
592
|
-
const maxTokens = model["maxTokens"];
|
|
593
|
-
if (maxTokens !== void 0 && (typeof maxTokens !== "number" || !Number.isInteger(maxTokens) || maxTokens <= 0)) return {
|
|
594
|
-
index,
|
|
595
|
-
key: "modelMaxTokensInvalid"
|
|
596
|
-
};
|
|
597
|
-
}
|
|
598
|
-
}
|
|
599
|
-
//#endregion
|
|
600
|
-
//#region src/client/models-plus/presets.ts
|
|
601
|
-
/** The tri-state `compat.supportsDeveloperRole` seed: absent (reads checked). */
|
|
602
|
-
const DEVELOPER_ROLE_SEED = {};
|
|
603
|
-
/** Draft seed for one new model row. */
|
|
604
|
-
function newModelDraft() {
|
|
605
|
-
return {
|
|
606
|
-
id: "",
|
|
607
|
-
input: ["text", "image"],
|
|
608
|
-
reasoningEfforts: {
|
|
609
|
-
off: null,
|
|
610
|
-
minimal: "minimal",
|
|
611
|
-
low: "low",
|
|
612
|
-
medium: "medium",
|
|
613
|
-
high: "high",
|
|
614
|
-
xhigh: "xhigh",
|
|
615
|
-
max: "max"
|
|
616
|
-
},
|
|
617
|
-
compat: {
|
|
618
|
-
...DEVELOPER_ROLE_SEED,
|
|
619
|
-
supportsReasoningEffort: true,
|
|
620
|
-
thinkingFormat: "openai"
|
|
621
|
-
}
|
|
622
|
-
};
|
|
623
|
-
}
|
|
624
|
-
//#endregion
|
|
625
473
|
//#region src/client/extension-meta.ts
|
|
626
474
|
/** Thinking levels offered by llm-pi-ai (THINKING_LEVEL_GATE @ 0.1.2-alpha.4). Only `off` may carry an empty wire value. */
|
|
627
475
|
const THINKING_LEVELS = [
|
|
@@ -726,6 +574,20 @@ if (typeof document !== 'undefined' && document.querySelector('style[data-plugin
|
|
|
726
574
|
const fields = COMPAT_FIELDS[api];
|
|
727
575
|
return fields === void 0 ? [] : fields;
|
|
728
576
|
}
|
|
577
|
+
/**
|
|
578
|
+
* Whether one protocol takes one compat switch.
|
|
579
|
+
*
|
|
580
|
+
* The adapter *refuses* a switch its protocol does not declare rather than
|
|
581
|
+
* ignoring it, so this is the difference between a control that can be offered
|
|
582
|
+
* and one that would fail the save. An unknown protocol takes nothing: its
|
|
583
|
+
* field set cannot be read, and the adapter resolves it to the same refusal.
|
|
584
|
+
* @param api - the model's wire protocol, when known.
|
|
585
|
+
* @param field - the compat field name.
|
|
586
|
+
* @returns true when the protocol offers the field.
|
|
587
|
+
*/
|
|
588
|
+
function protocolOffers(api, field) {
|
|
589
|
+
return offeredCompatFields(api).includes(field);
|
|
590
|
+
}
|
|
729
591
|
/** Extra copy for the extension, keyed like the official dictionaries (en is authoritative). */
|
|
730
592
|
const en = {
|
|
731
593
|
nav: "Models+",
|
|
@@ -951,6 +813,245 @@ if (typeof document !== 'undefined' && document.querySelector('style[data-plugin
|
|
|
951
813
|
thinkingFormat: "思考格式"
|
|
952
814
|
};
|
|
953
815
|
//#endregion
|
|
816
|
+
//#region src/client/models-plus/compat.ts
|
|
817
|
+
/**
|
|
818
|
+
* The minimal path ops carrying `after` over `before`, both as the card sees
|
|
819
|
+
* them. Only keys the card observed are named; fields absent from both sides
|
|
820
|
+
* produce no op, which is why edits are path-addressed rather than a rebuilt
|
|
821
|
+
* section.
|
|
822
|
+
* @param base - path of the edited subtree inside the user section.
|
|
823
|
+
* @param before - the subtree as loaded, or undefined when it is new.
|
|
824
|
+
* @param after - the subtree as edited.
|
|
825
|
+
* @returns ordered set/unset ops; empty when nothing changed.
|
|
826
|
+
*/
|
|
827
|
+
function pathOps(base, before, after) {
|
|
828
|
+
const previous = typeof before === "object" && before !== null && !Array.isArray(before) ? before : {};
|
|
829
|
+
const ops = [];
|
|
830
|
+
for (const [key, value] of Object.entries(after)) {
|
|
831
|
+
if (JSON.stringify(previous[key]) === JSON.stringify(value)) continue;
|
|
832
|
+
ops.push({
|
|
833
|
+
op: "set",
|
|
834
|
+
path: [...base, key],
|
|
835
|
+
value
|
|
836
|
+
});
|
|
837
|
+
}
|
|
838
|
+
for (const key of Object.keys(previous)) if (!(key in after)) ops.push({
|
|
839
|
+
op: "unset",
|
|
840
|
+
path: [...base, key]
|
|
841
|
+
});
|
|
842
|
+
return ops;
|
|
843
|
+
}
|
|
844
|
+
/** Accepted capacity spellings: a decimal count with an optional K/M suffix. */
|
|
845
|
+
const CAPACITY_PATTERN = /^(\d+(?:\.\d+)?)([km])?$/i;
|
|
846
|
+
/** Decimal suffix scales — `1M` is 1000K, matching how model capacities are quoted. */
|
|
847
|
+
const CAPACITY_SCALE = {
|
|
848
|
+
k: 1e3,
|
|
849
|
+
m: 1e6
|
|
850
|
+
};
|
|
851
|
+
/**
|
|
852
|
+
* Read a typed capacity, so a user can write `256K` or `1M` instead of counting
|
|
853
|
+
* zeroes. The stored value stays a plain token count.
|
|
854
|
+
* @param text - raw field text.
|
|
855
|
+
* @returns the count; `undefined` when blank (inherit), `NaN` when unreadable
|
|
856
|
+
* (rejected by {@link validateModelRows} before any write).
|
|
857
|
+
*/
|
|
858
|
+
function parseCapacity(text) {
|
|
859
|
+
const trimmed = text.trim();
|
|
860
|
+
if (trimmed.length === 0) return void 0;
|
|
861
|
+
const match = CAPACITY_PATTERN.exec(trimmed);
|
|
862
|
+
if (match === null) return NaN;
|
|
863
|
+
const suffix = match[2]?.toLowerCase();
|
|
864
|
+
const scale = suffix === "k" || suffix === "m" ? CAPACITY_SCALE[suffix] : 1;
|
|
865
|
+
const scaled = Number(match[1]) * scale;
|
|
866
|
+
const rounded = Math.round(scaled);
|
|
867
|
+
return Math.abs(scaled - rounded) < 1e-6 ? rounded : scaled;
|
|
868
|
+
}
|
|
869
|
+
/**
|
|
870
|
+
* Spell a stored count back in the shortest form that survives a round trip
|
|
871
|
+
* through {@link parseCapacity}; a count that is not a whole number of
|
|
872
|
+
* thousands stays written out.
|
|
873
|
+
* @param value - stored capacity.
|
|
874
|
+
* @returns the field text.
|
|
875
|
+
*/
|
|
876
|
+
function formatCapacity(value) {
|
|
877
|
+
if (!Number.isInteger(value) || value <= 0) return String(value);
|
|
878
|
+
if (value % CAPACITY_SCALE.m === 0) return `${String(value / CAPACITY_SCALE.m)}M`;
|
|
879
|
+
if (value % CAPACITY_SCALE.k === 0) return `${String(value / CAPACITY_SCALE.k)}K`;
|
|
880
|
+
return String(value);
|
|
881
|
+
}
|
|
882
|
+
/** Convert a schema-validated catalog value into records without dropping hidden fields. */
|
|
883
|
+
function modelDrafts(value) {
|
|
884
|
+
if (!Array.isArray(value)) return [];
|
|
885
|
+
return value.map((entry) => typeof entry === "object" && entry !== null && !Array.isArray(entry) ? entry : {});
|
|
886
|
+
}
|
|
887
|
+
/** Canonical key order for one models[] row (plugin-known fields first). */
|
|
888
|
+
const ROW_KEY_ORDER = [
|
|
889
|
+
"id",
|
|
890
|
+
"name",
|
|
891
|
+
"contextWindow",
|
|
892
|
+
"maxTokens",
|
|
893
|
+
"input",
|
|
894
|
+
"reasoningEfforts",
|
|
895
|
+
"compat"
|
|
896
|
+
];
|
|
897
|
+
/** Canonical key order for the row's compat sub-object. */
|
|
898
|
+
const COMPAT_KEY_ORDER = [
|
|
899
|
+
"supportsDeveloperRole",
|
|
900
|
+
"supportsReasoningEffort",
|
|
901
|
+
"thinkingFormat"
|
|
902
|
+
];
|
|
903
|
+
/**
|
|
904
|
+
* Re-key one model row into the canonical order (plugin-known fields in
|
|
905
|
+
* order, unknown/future fields kept at the tail so nothing is dropped).
|
|
906
|
+
* YAML emits keys in object insertion order, and interactive edits append
|
|
907
|
+
* keys at the tail — without this, rows saved after quick-load or gated-key
|
|
908
|
+
* removals come out with scrambled key orders (purely cosmetic, but noisy
|
|
909
|
+
* in settings.yaml diffs).
|
|
910
|
+
* @param row - the drafted row.
|
|
911
|
+
* @returns the re-keyed row (shallow copy).
|
|
912
|
+
*/
|
|
913
|
+
function normalizeModelRow(row) {
|
|
914
|
+
const next = {};
|
|
915
|
+
for (const key of ROW_KEY_ORDER) if (key in row) next[key] = row[key];
|
|
916
|
+
for (const key of Object.keys(row)) if (!ROW_KEY_ORDER.includes(key)) next[key] = row[key];
|
|
917
|
+
const compat = next["compat"];
|
|
918
|
+
if (typeof compat === "object" && compat !== null && !Array.isArray(compat)) {
|
|
919
|
+
const source = compat;
|
|
920
|
+
const normalized = {};
|
|
921
|
+
for (const key of COMPAT_KEY_ORDER) if (key in source) normalized[key] = source[key];
|
|
922
|
+
for (const key of Object.keys(source)) if (!COMPAT_KEY_ORDER.includes(key)) normalized[key] = source[key];
|
|
923
|
+
next["compat"] = normalized;
|
|
924
|
+
}
|
|
925
|
+
return next;
|
|
926
|
+
}
|
|
927
|
+
/**
|
|
928
|
+
* The message for a refused compat switch, shared by both provider cards so the
|
|
929
|
+
* same failure reads the same way wherever it is hit.
|
|
930
|
+
* @param failure - a `modelCompatNotOffered` failure from {@link validateModelRows}.
|
|
931
|
+
* @returns the localised sentence.
|
|
932
|
+
*/
|
|
933
|
+
function compatFailureMessage(failure) {
|
|
934
|
+
const offered = failure.offered ?? [];
|
|
935
|
+
const available = offered.length === 0 ? ",该协议不接受任何可配置开关" : `,该协议可用:${offered.join("、")}`;
|
|
936
|
+
return `模型 ${String(failure.index + 1)}:compat 开关 ${String(failure.field)} 不适用于当前协议(${String(failure.api)})${available}。请在展开的「其他兼容开关」中清空该项以移除,或回到供应商页把协议改成端点真正使用的协议。`;
|
|
937
|
+
}
|
|
938
|
+
/**
|
|
939
|
+
* Validate adapter constraints that the serialized schema cannot express.
|
|
940
|
+
*
|
|
941
|
+
* The compat half of the check exists because the adapter *refuses* a switch a
|
|
942
|
+
* model's protocol does not declare rather than ignoring it — and the protocol
|
|
943
|
+
* a row resolves to is `route.api` first, the installed catalog entry second.
|
|
944
|
+
* A row can therefore hold switches that were legal when it was written (a
|
|
945
|
+
* protocol change on the route, or a prefill taken from another protocol's
|
|
946
|
+
* catalog entry) and only fail at save time, in English, from the host. This
|
|
947
|
+
* turns that into a positioned, named, localised refusal.
|
|
948
|
+
*
|
|
949
|
+
* An unknown protocol is skipped on purpose: the route's protocol could not be
|
|
950
|
+
* resolved, so the row's real one is unknowable here, and a guess would refuse
|
|
951
|
+
* a configuration the host accepts. The host's own diagnostic still covers it.
|
|
952
|
+
* @param value - user-owned `models` value, or undefined while inherited.
|
|
953
|
+
* @param api - the protocol every row resolves to, when the route settles one.
|
|
954
|
+
* @returns the first invalid row, or undefined when the adapter will accept it.
|
|
955
|
+
*/
|
|
956
|
+
function validateModelRows(value, api) {
|
|
957
|
+
if (value === void 0) return void 0;
|
|
958
|
+
const models = modelDrafts(value);
|
|
959
|
+
const seen = /* @__PURE__ */ new Set();
|
|
960
|
+
for (const [index, model] of models.entries()) {
|
|
961
|
+
const id = model["id"];
|
|
962
|
+
const trimmed = typeof id === "string" ? id.trim() : void 0;
|
|
963
|
+
if (trimmed === void 0 || trimmed.length === 0) return {
|
|
964
|
+
index,
|
|
965
|
+
key: "modelIdRequired"
|
|
966
|
+
};
|
|
967
|
+
if (seen.has(trimmed)) return {
|
|
968
|
+
index,
|
|
969
|
+
key: "modelIdDuplicate"
|
|
970
|
+
};
|
|
971
|
+
seen.add(trimmed);
|
|
972
|
+
const name = model["name"];
|
|
973
|
+
if (name !== void 0 && (typeof name !== "string" || name.length === 0)) return {
|
|
974
|
+
index,
|
|
975
|
+
key: "modelNameInvalid"
|
|
976
|
+
};
|
|
977
|
+
const contextWindow = model["contextWindow"];
|
|
978
|
+
if (contextWindow !== void 0 && (typeof contextWindow !== "number" || !Number.isInteger(contextWindow) || contextWindow <= 0)) return {
|
|
979
|
+
index,
|
|
980
|
+
key: "modelContextInvalid"
|
|
981
|
+
};
|
|
982
|
+
const maxTokens = model["maxTokens"];
|
|
983
|
+
if (maxTokens !== void 0 && (typeof maxTokens !== "number" || !Number.isInteger(maxTokens) || maxTokens <= 0)) return {
|
|
984
|
+
index,
|
|
985
|
+
key: "modelMaxTokensInvalid"
|
|
986
|
+
};
|
|
987
|
+
const compat = model["compat"];
|
|
988
|
+
if (api !== void 0 && typeof compat === "object" && compat !== null && !Array.isArray(compat)) for (const field of Object.keys(compat)) {
|
|
989
|
+
if (protocolOffers(api, field)) continue;
|
|
990
|
+
return {
|
|
991
|
+
index,
|
|
992
|
+
key: "modelCompatNotOffered",
|
|
993
|
+
field,
|
|
994
|
+
api,
|
|
995
|
+
offered: offeredCompatFields(api)
|
|
996
|
+
};
|
|
997
|
+
}
|
|
998
|
+
}
|
|
999
|
+
}
|
|
1000
|
+
//#endregion
|
|
1001
|
+
//#region src/client/models-plus/presets.ts
|
|
1002
|
+
/**
|
|
1003
|
+
* Draft defaults for a NEW model row (added by hand or adopted from a fetch),
|
|
1004
|
+
* per the v1.0.0 plan: reasoning effort ON with every level declared, thinking
|
|
1005
|
+
* format `openai`, both input modalities checked. These are draft seeds that
|
|
1006
|
+
* land in settings.yaml when the row is saved — they are not inherited-state
|
|
1007
|
+
* sentinels, except `supportsDeveloperRole`, which stays UNWRITTEN (its
|
|
1008
|
+
* tri-state reads an absent key as checked, so only an explicit user uncheck
|
|
1009
|
+
* ever writes `false`).
|
|
1010
|
+
*
|
|
1011
|
+
* The compat half of the seed is PROTOCOL-DEPENDENT, and that is load-bearing:
|
|
1012
|
+
* `supportsReasoningEffort` and `thinkingFormat` belong to `openai-completions`
|
|
1013
|
+
* alone, and the adapter refuses a switch its protocol does not declare rather
|
|
1014
|
+
* than ignoring it. Seeding them onto an `anthropic-messages` route — which is
|
|
1015
|
+
* what a fixed vocabulary here did — made every hand-added model on such a
|
|
1016
|
+
* route fail the save over a switch the user never wrote. So the seed asks
|
|
1017
|
+
* {@link protocolOffers} first and writes nothing its protocol would refuse.
|
|
1018
|
+
* `reasoningEfforts` is unaffected: the levels travel through each protocol's
|
|
1019
|
+
* own thinking parameter, so every protocol takes them.
|
|
1020
|
+
*/
|
|
1021
|
+
/** The tri-state `compat.supportsDeveloperRole` seed: absent (reads checked). */
|
|
1022
|
+
const DEVELOPER_ROLE_SEED = {};
|
|
1023
|
+
/**
|
|
1024
|
+
* Draft seed for one new model row.
|
|
1025
|
+
*
|
|
1026
|
+
* An UNKNOWN protocol (no route-level `api`, and the installed catalog does not
|
|
1027
|
+
* describe the route) seeds no compat at all: nothing can say which switches
|
|
1028
|
+
* its endpoint would take, and a guessed `supportsReasoningEffort` on an
|
|
1029
|
+
* Anthropic-shaped route is refused rather than dropped. The levels stay seeded
|
|
1030
|
+
* — they are protocol-independent — so the row still opens with its effort
|
|
1031
|
+
* table populated.
|
|
1032
|
+
* @param api - the wire protocol this row will resolve to, when known.
|
|
1033
|
+
* @returns the draft row.
|
|
1034
|
+
*/
|
|
1035
|
+
function newModelDraft(api) {
|
|
1036
|
+
const compat = { ...DEVELOPER_ROLE_SEED };
|
|
1037
|
+
if (protocolOffers(api, "supportsReasoningEffort")) compat["supportsReasoningEffort"] = true;
|
|
1038
|
+
if (protocolOffers(api, "thinkingFormat")) compat["thinkingFormat"] = "openai";
|
|
1039
|
+
return {
|
|
1040
|
+
id: "",
|
|
1041
|
+
input: ["text", "image"],
|
|
1042
|
+
reasoningEfforts: {
|
|
1043
|
+
off: null,
|
|
1044
|
+
minimal: "minimal",
|
|
1045
|
+
low: "low",
|
|
1046
|
+
medium: "medium",
|
|
1047
|
+
high: "high",
|
|
1048
|
+
xhigh: "xhigh",
|
|
1049
|
+
max: "max"
|
|
1050
|
+
},
|
|
1051
|
+
...Object.keys(compat).length === 0 ? {} : { compat }
|
|
1052
|
+
};
|
|
1053
|
+
}
|
|
1054
|
+
//#endregion
|
|
954
1055
|
//#region src/client/models-plus/prefill.ts
|
|
955
1056
|
/**
|
|
956
1057
|
* Mapping pi-ai catalog values onto a Models+ row.
|
|
@@ -1033,12 +1134,16 @@ if (typeof document !== 'undefined' && document.querySelector('style[data-plugin
|
|
|
1033
1134
|
* Project a catalog `compat` block onto the switches the host offers for one
|
|
1034
1135
|
* protocol.
|
|
1035
1136
|
*
|
|
1036
|
-
* The filter is load-bearing
|
|
1037
|
-
* (routing preferences, session affinity, deferred tools, grammar tools),
|
|
1038
|
-
* the adapter *refuses*
|
|
1039
|
-
*
|
|
1137
|
+
* The filter is load-bearing twice over. It drops pi-ai's withheld switches
|
|
1138
|
+
* (routing preferences, session affinity, deferred tools, grammar tools), which
|
|
1139
|
+
* the adapter *refuses* rather than ignores — a verbatim copy would make the
|
|
1140
|
+
* route fail to resolve. And it filters by the protocol the row will be JUDGED
|
|
1141
|
+
* by, which is not always the catalog entry's own: a hand-declared route states
|
|
1142
|
+
* its `api`, that value overrides the catalog for every model on the route, and
|
|
1143
|
+
* a block taken from another protocol's entry (`supportsStore` on a gateway
|
|
1144
|
+
* that speaks `anthropic-messages`) is refused at save time.
|
|
1040
1145
|
* @param compat - the catalog's compat record, when it carries one.
|
|
1041
|
-
* @param api - the
|
|
1146
|
+
* @param api - the protocol the row resolves to, as the adapter resolves it.
|
|
1042
1147
|
* @returns the writable subset; empty when nothing survives.
|
|
1043
1148
|
*/
|
|
1044
1149
|
function compatFrom(compat, api) {
|
|
@@ -1116,6 +1221,8 @@ if (typeof document !== 'undefined' && document.querySelector('style[data-plugin
|
|
|
1116
1221
|
"primaryButton": "J84-9a_primaryButton",
|
|
1117
1222
|
"quickEmpty": "J84-9a_quickEmpty",
|
|
1118
1223
|
"quickItem": "J84-9a_quickItem",
|
|
1224
|
+
"quickItemApi": "J84-9a_quickItemApi",
|
|
1225
|
+
"quickItemId": "J84-9a_quickItemId",
|
|
1119
1226
|
"quickList": "J84-9a_quickList",
|
|
1120
1227
|
"quickWrap": "J84-9a_quickWrap",
|
|
1121
1228
|
"rowActions": "J84-9a_rowActions",
|
|
@@ -1284,14 +1391,20 @@ if (typeof document !== 'undefined' && document.querySelector('style[data-plugin
|
|
|
1284
1391
|
className: models_plus_module_default["quickEmpty"],
|
|
1285
1392
|
children: "没有匹配的模型"
|
|
1286
1393
|
});
|
|
1287
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [hits.map((entry) => /* @__PURE__ */ (0, react_jsx_runtime.
|
|
1394
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [hits.map((entry) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
1288
1395
|
type: "button",
|
|
1289
1396
|
className: models_plus_module_default["quickItem"],
|
|
1290
1397
|
onMouseDown: (event) => {
|
|
1291
1398
|
event.preventDefault();
|
|
1292
1399
|
pick(entry);
|
|
1293
1400
|
},
|
|
1294
|
-
children:
|
|
1401
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1402
|
+
className: models_plus_module_default["quickItemId"],
|
|
1403
|
+
children: entry.id
|
|
1404
|
+
}), entry.api === void 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1405
|
+
className: models_plus_module_default["quickItemApi"],
|
|
1406
|
+
children: entry.api
|
|
1407
|
+
})]
|
|
1295
1408
|
}, entry.key)), total > hits.length ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
1296
1409
|
className: models_plus_module_default["quickEmpty"],
|
|
1297
1410
|
children: [
|
|
@@ -1406,6 +1519,13 @@ if (typeof document !== 'undefined' && document.querySelector('style[data-plugin
|
|
|
1406
1519
|
* rides the card's existing path-ops save with no extra wire calls. Clearing
|
|
1407
1520
|
* the effort gate drops `reasoningEfforts` AND `compat.thinkingFormat` in ONE
|
|
1408
1521
|
* commit so partial updates never overwrite each other (no orphan settings).
|
|
1522
|
+
*
|
|
1523
|
+
* Which compat switches this panel may write at all is decided by `api` (see
|
|
1524
|
+
* {@link ModelEntryPanelProps.api}): the adapter refuses a switch the model's
|
|
1525
|
+
* protocol does not declare instead of ignoring it, so a control offered on the
|
|
1526
|
+
* wrong protocol is a save that cannot succeed. An UNKNOWN protocol hides
|
|
1527
|
+
* nothing — nothing can be judged — and the host's own diagnostic still covers
|
|
1528
|
+
* that case.
|
|
1409
1529
|
*/
|
|
1410
1530
|
/**
|
|
1411
1531
|
* Whether a draft field is absent or whitespace-only.
|
|
@@ -1438,7 +1558,18 @@ if (typeof document !== 'undefined' && document.querySelector('style[data-plugin
|
|
|
1438
1558
|
* @returns the expanded panel.
|
|
1439
1559
|
*/
|
|
1440
1560
|
function ModelEntryPanel(props) {
|
|
1441
|
-
const { model, onChange, disabled } = props;
|
|
1561
|
+
const { model, onChange, disabled, api } = props;
|
|
1562
|
+
/**
|
|
1563
|
+
* Whether this panel may OFFER a control for one compat switch.
|
|
1564
|
+
*
|
|
1565
|
+
* Not the same question as `protocolOffers`, and deliberately so: an
|
|
1566
|
+
* unresolvable protocol answers `true` throughout, because with no protocol to
|
|
1567
|
+
* read nothing can be judged — hiding a control on a guess would remove a
|
|
1568
|
+
* switch the route may well take, while the host still names anything it
|
|
1569
|
+
* refuses. A resolved protocol that offers nothing (one pi-ai gives no compat
|
|
1570
|
+
* type) answers `false` throughout, which is exactly what the adapter says.
|
|
1571
|
+
*/
|
|
1572
|
+
const mayOffer = (field) => api === void 0 || offeredCompatFields(api).includes(field);
|
|
1442
1573
|
const [capacityText, setCapacityText] = (0, react.useState)(() => /* @__PURE__ */ new Map());
|
|
1443
1574
|
/** Patch one key onto the row; `undefined` clears it. */
|
|
1444
1575
|
const setKey = (key, value) => {
|
|
@@ -1479,6 +1610,7 @@ if (typeof document !== 'undefined' && document.querySelector('style[data-plugin
|
|
|
1479
1610
|
*/
|
|
1480
1611
|
const applyMetadata = (entry) => {
|
|
1481
1612
|
const next = { ...model };
|
|
1613
|
+
const judgedBy = props.api ?? entry.api;
|
|
1482
1614
|
if (entry.context === void 0) Reflect.deleteProperty(next, "contextWindow");
|
|
1483
1615
|
else next["contextWindow"] = entry.context;
|
|
1484
1616
|
if (entry.output === void 0) Reflect.deleteProperty(next, "maxTokens");
|
|
@@ -1489,13 +1621,13 @@ if (typeof document !== 'undefined' && document.querySelector('style[data-plugin
|
|
|
1489
1621
|
if (entry.source === "pi-ai") {
|
|
1490
1622
|
if (isBlank(next["id"])) next["id"] = entry.id;
|
|
1491
1623
|
if (isBlank(next["name"]) && entry.name !== void 0) next["name"] = entry.name;
|
|
1492
|
-
next["reasoningEfforts"] = reasoningEffortsFrom(entry.thinkingLevelMap,
|
|
1493
|
-
const compat = compatFrom(entry.compat,
|
|
1624
|
+
next["reasoningEfforts"] = reasoningEffortsFrom(entry.thinkingLevelMap, judgedBy, entry.reasoning);
|
|
1625
|
+
const compat = compatFrom(entry.compat, judgedBy);
|
|
1494
1626
|
if (Object.keys(compat).length === 0) Reflect.deleteProperty(next, "compat");
|
|
1495
1627
|
else next["compat"] = compat;
|
|
1496
1628
|
} else {
|
|
1497
1629
|
Reflect.deleteProperty(next, "reasoningEfforts");
|
|
1498
|
-
if (entry.reasoning) next["compat"] = { supportsReasoningEffort: true };
|
|
1630
|
+
if (entry.reasoning && mayOffer("supportsReasoningEffort")) next["compat"] = { supportsReasoningEffort: true };
|
|
1499
1631
|
else Reflect.deleteProperty(next, "compat");
|
|
1500
1632
|
}
|
|
1501
1633
|
onChange(next);
|
|
@@ -1538,13 +1670,20 @@ if (typeof document !== 'undefined' && document.querySelector('style[data-plugin
|
|
|
1538
1670
|
const compat = compatOf(model);
|
|
1539
1671
|
const developerRole = compat["supportsDeveloperRole"] !== false;
|
|
1540
1672
|
/**
|
|
1541
|
-
* Switches a prefill wrote that
|
|
1542
|
-
*
|
|
1543
|
-
*
|
|
1544
|
-
*
|
|
1545
|
-
*
|
|
1673
|
+
* Switches a prefill wrote that no control above stands for. Listing them
|
|
1674
|
+
* keeps a prefilled value from becoming invisible state: the pi-ai catalog
|
|
1675
|
+
* records far more of the compat surface than this panel models explicitly,
|
|
1676
|
+
* and that API refuses an unknown switch rather than ignoring it — so a value
|
|
1677
|
+
* the user cannot see is a value the user cannot fix.
|
|
1678
|
+
*
|
|
1679
|
+
* The set is the panel's base list narrowed to what this protocol takes. A
|
|
1680
|
+
* switch the protocol refuses keeps NO control — writing it would fail the
|
|
1681
|
+
* save — so it lands here instead, where it is named as refused and can be
|
|
1682
|
+
* cleared. That is the only way out of a row written before a protocol change
|
|
1683
|
+
* on the route, which no amount of hiding would repair.
|
|
1546
1684
|
*/
|
|
1547
|
-
const
|
|
1685
|
+
const dedicated = COMPAT_BASE_FIELDS.filter((field) => mayOffer(field));
|
|
1686
|
+
const extraCompat = Object.entries(compat).filter(([key]) => !dedicated.includes(key)).sort(([a], [b]) => a.localeCompare(b));
|
|
1548
1687
|
/**
|
|
1549
1688
|
* Read an edited switch back as the type it already had.
|
|
1550
1689
|
* @param previous - the value the switch carried when rendered.
|
|
@@ -1564,8 +1703,14 @@ if (typeof document !== 'undefined' && document.querySelector('style[data-plugin
|
|
|
1564
1703
|
return previous;
|
|
1565
1704
|
}
|
|
1566
1705
|
};
|
|
1567
|
-
/**
|
|
1568
|
-
|
|
1706
|
+
/**
|
|
1707
|
+
* The switch as a wire field: whether the endpoint takes `reasoning_effort`.
|
|
1708
|
+
*
|
|
1709
|
+
* Gated on the protocol as well as on the stored value: on a protocol that
|
|
1710
|
+
* does not take the switch a leftover `true` describes nothing this route can
|
|
1711
|
+
* act on, and the field's real home is the refused-switch list below.
|
|
1712
|
+
*/
|
|
1713
|
+
const gateOn = mayOffer("supportsReasoningEffort") && compat["supportsReasoningEffort"] === true;
|
|
1569
1714
|
const efforts = effortsOf(model);
|
|
1570
1715
|
/**
|
|
1571
1716
|
* Whether the reasoning area is worth showing.
|
|
@@ -1578,7 +1723,7 @@ if (typeof document !== 'undefined' && document.querySelector('style[data-plugin
|
|
|
1578
1723
|
* through the protocol's own thinking parameter either way. So the area keys
|
|
1579
1724
|
* off either signal, not the switch alone.
|
|
1580
1725
|
*/
|
|
1581
|
-
const reasoningAreaShown = gateOn || efforts !== void 0 || compat["thinkingFormat"] !== void 0;
|
|
1726
|
+
const reasoningAreaShown = gateOn || efforts !== void 0 || mayOffer("thinkingFormat") && compat["thinkingFormat"] !== void 0;
|
|
1582
1727
|
const toggleGate = (checked) => {
|
|
1583
1728
|
if (checked) {
|
|
1584
1729
|
setCompatKey("supportsReasoningEffort", true);
|
|
@@ -1657,7 +1802,7 @@ if (typeof document !== 'undefined' && document.querySelector('style[data-plugin
|
|
|
1657
1802
|
}, modality))
|
|
1658
1803
|
})]
|
|
1659
1804
|
}),
|
|
1660
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1805
|
+
mayOffer("supportsDeveloperRole") ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1661
1806
|
className: models_plus_module_default["extGroup"],
|
|
1662
1807
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
|
|
1663
1808
|
className: models_plus_module_default["extCheck"],
|
|
@@ -1685,10 +1830,10 @@ if (typeof document !== 'undefined' && document.querySelector('style[data-plugin
|
|
|
1685
1830
|
})]
|
|
1686
1831
|
})]
|
|
1687
1832
|
})
|
|
1688
|
-
}),
|
|
1833
|
+
}) : null,
|
|
1689
1834
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1690
1835
|
className: models_plus_module_default["extGroup"],
|
|
1691
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
|
|
1836
|
+
children: [mayOffer("supportsReasoningEffort") ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
|
|
1692
1837
|
className: models_plus_module_default["switchRow"],
|
|
1693
1838
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
1694
1839
|
type: "checkbox",
|
|
@@ -1699,7 +1844,14 @@ if (typeof document !== 'undefined' && document.querySelector('style[data-plugin
|
|
|
1699
1844
|
toggleGate(event.target.checked);
|
|
1700
1845
|
}
|
|
1701
1846
|
}), "端点接受推理挡位参数(reasoning_effort)"]
|
|
1702
|
-
})
|
|
1847
|
+
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
|
|
1848
|
+
className: models_plus_module_default["extHint"],
|
|
1849
|
+
children: [
|
|
1850
|
+
"当前协议(",
|
|
1851
|
+
String(api),
|
|
1852
|
+
")不接受 reasoning_effort 开关,故此处不提供;下面的挡位仍通过该协议自身的 thinking 参数生效。"
|
|
1853
|
+
]
|
|
1854
|
+
}), mayOffer("supportsReasoningEffort") && !gateOn && reasoningAreaShown ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1703
1855
|
className: models_plus_module_default["extHint"],
|
|
1704
1856
|
style: { marginTop: 6 },
|
|
1705
1857
|
children: "此项未设置:由 llm-pi-ai 按其 baseURL 检测结果决定是否发送 reasoning_effort; 下面的挡位不受影响,仍通过各协议自己的 thinking 参数生效。"
|
|
@@ -1708,7 +1860,7 @@ if (typeof document !== 'undefined' && document.querySelector('style[data-plugin
|
|
|
1708
1860
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1709
1861
|
className: models_plus_module_default["extGated"],
|
|
1710
1862
|
hidden: !reasoningAreaShown,
|
|
1711
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1863
|
+
children: [mayOffer("thinkingFormat") ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1712
1864
|
className: models_plus_module_default["extField"],
|
|
1713
1865
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1714
1866
|
className: models_plus_module_default["extLabel"],
|
|
@@ -1728,7 +1880,7 @@ if (typeof document !== 'undefined' && document.querySelector('style[data-plugin
|
|
|
1728
1880
|
children: format
|
|
1729
1881
|
}, format))]
|
|
1730
1882
|
})]
|
|
1731
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1883
|
+
}) : null, /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1732
1884
|
className: models_plus_module_default["extField"],
|
|
1733
1885
|
children: [
|
|
1734
1886
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
@@ -1816,27 +1968,30 @@ if (typeof document !== 'undefined' && document.querySelector('style[data-plugin
|
|
|
1816
1968
|
flexDirection: "column",
|
|
1817
1969
|
gap: 6
|
|
1818
1970
|
},
|
|
1819
|
-
children: extraCompat.map(([key, value]) =>
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
children:
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1971
|
+
children: extraCompat.map(([key, value]) => {
|
|
1972
|
+
const refused = !mayOffer(key);
|
|
1973
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
|
|
1974
|
+
style: {
|
|
1975
|
+
display: "flex",
|
|
1976
|
+
flexDirection: "column",
|
|
1977
|
+
gap: 2
|
|
1978
|
+
},
|
|
1979
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1980
|
+
className: refused ? models_plus_module_default["error"] : models_plus_module_default["extHint"],
|
|
1981
|
+
children: refused ? `${key} —— 当前协议(${String(api)})不接受此开关,请清空输入框以移除` : key
|
|
1982
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
1983
|
+
className: models_plus_module_default["input"],
|
|
1984
|
+
type: "text",
|
|
1985
|
+
defaultValue: typeof value === "string" ? value : JSON.stringify(value) ?? "",
|
|
1986
|
+
"aria-label": key,
|
|
1987
|
+
disabled,
|
|
1988
|
+
onBlur: (event) => {
|
|
1989
|
+
const raw = event.target.value.trim();
|
|
1990
|
+
setCompatKey(key, raw.length === 0 ? void 0 : readCompatValue(value, raw));
|
|
1991
|
+
}
|
|
1992
|
+
})]
|
|
1993
|
+
}, key);
|
|
1994
|
+
})
|
|
1840
1995
|
}),
|
|
1841
1996
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1842
1997
|
className: models_plus_module_default["extHint"],
|
|
@@ -1862,8 +2017,8 @@ if (typeof document !== 'undefined' && document.querySelector('style[data-plugin
|
|
|
1862
2017
|
return typeof value === "string" ? value : "";
|
|
1863
2018
|
}
|
|
1864
2019
|
/** Adopt one candidate, v1.0.0 defaults + the endpoint's disclosed capacities. */
|
|
1865
|
-
function adopt(candidate) {
|
|
1866
|
-
const row = newModelDraft();
|
|
2020
|
+
function adopt(candidate, routeApi) {
|
|
2021
|
+
const row = newModelDraft(routeApi);
|
|
1867
2022
|
row["id"] = candidate.id;
|
|
1868
2023
|
row["name"] = candidate.name ?? candidate.id;
|
|
1869
2024
|
if (candidate.contextWindow !== void 0) row["contextWindow"] = candidate.contextWindow;
|
|
@@ -1946,7 +2101,7 @@ if (typeof document !== 'undefined' && document.querySelector('style[data-plugin
|
|
|
1946
2101
|
const byId = new Map(models.map((model) => [textOf(model, "id"), model]));
|
|
1947
2102
|
for (const candidate of candidates) {
|
|
1948
2103
|
if (!picked.has(candidate.id)) continue;
|
|
1949
|
-
byId.set(candidate.id, byId.get(candidate.id) ?? adopt(candidate));
|
|
2104
|
+
byId.set(candidate.id, byId.get(candidate.id) ?? adopt(candidate, props.routeApi));
|
|
1950
2105
|
}
|
|
1951
2106
|
onChange([...byId.values()]);
|
|
1952
2107
|
closePicker();
|
|
@@ -2089,6 +2244,7 @@ if (typeof document !== 'undefined' && document.querySelector('style[data-plugin
|
|
|
2089
2244
|
]
|
|
2090
2245
|
}), expanded.has(index) ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ModelEntryPanel, {
|
|
2091
2246
|
model,
|
|
2247
|
+
api: props.routeApi,
|
|
2092
2248
|
disabled,
|
|
2093
2249
|
onChange: (next) => {
|
|
2094
2250
|
onChange(models.map((row, at) => at === index ? next : row));
|
|
@@ -2101,7 +2257,7 @@ if (typeof document !== 'undefined' && document.querySelector('style[data-plugin
|
|
|
2101
2257
|
className: models_plus_module_default["addModelButton"],
|
|
2102
2258
|
disabled,
|
|
2103
2259
|
onClick: () => {
|
|
2104
|
-
onChange([...models, newModelDraft()]);
|
|
2260
|
+
onChange([...models, newModelDraft(props.routeApi)]);
|
|
2105
2261
|
},
|
|
2106
2262
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("svg", {
|
|
2107
2263
|
width: "14",
|
|
@@ -2251,6 +2407,22 @@ if (typeof document !== 'undefined' && document.querySelector('style[data-plugin
|
|
|
2251
2407
|
namespace,
|
|
2252
2408
|
schema
|
|
2253
2409
|
]);
|
|
2410
|
+
/**
|
|
2411
|
+
* The pi-ai catalog, loaded only on the family that needs it: it answers the
|
|
2412
|
+
* protocol of a route that states none (a catalog route), which is what the
|
|
2413
|
+
* model panel judges compat switches by.
|
|
2414
|
+
*/
|
|
2415
|
+
const [prefillIndex, setPrefillIndex] = (0, react.useState)(void 0);
|
|
2416
|
+
(0, react.useEffect)(() => {
|
|
2417
|
+
if (layout !== "pi-ai") return;
|
|
2418
|
+
let stale = false;
|
|
2419
|
+
getPrefillIndex().then((loaded) => {
|
|
2420
|
+
if (!stale) setPrefillIndex(loaded);
|
|
2421
|
+
});
|
|
2422
|
+
return () => {
|
|
2423
|
+
stale = true;
|
|
2424
|
+
};
|
|
2425
|
+
}, [layout]);
|
|
2254
2426
|
(0, react.useEffect)(() => {
|
|
2255
2427
|
let stale = false;
|
|
2256
2428
|
setKeyState(void 0);
|
|
@@ -2270,7 +2442,18 @@ if (typeof document !== 'undefined' && document.querySelector('style[data-plugin
|
|
|
2270
2442
|
const value = next === void 0 || next.trim().length === 0 ? void 0 : next;
|
|
2271
2443
|
setDraft((current) => value === void 0 ? schema.deletePath(current, [key]) : schema.setPath(current, [key], value));
|
|
2272
2444
|
};
|
|
2273
|
-
|
|
2445
|
+
/**
|
|
2446
|
+
* The protocol every row of this route resolves to, resolved the way the
|
|
2447
|
+
* adapter resolves it: a hand-declared route's own `api` first — it overrides
|
|
2448
|
+
* the catalog for every model on the route — then the protocol the installed
|
|
2449
|
+
* catalog's entries for this route agree on, then nothing.
|
|
2450
|
+
*
|
|
2451
|
+
* The model panel needs it because the adapter judges each row's compat
|
|
2452
|
+
* switches by THIS protocol, not by the catalog entry the row was prefilled
|
|
2453
|
+
* from; without it a row can carry switches the route will refuse.
|
|
2454
|
+
*/
|
|
2455
|
+
const routeApi = layout === "pi-ai" ? (props.declared === true ? stringAt(draft, "api") ?? stringAt(fallback, "api") : void 0) ?? sharedCatalogApi(prefillIndex, props.provider) : void 0;
|
|
2456
|
+
const modelFailure = validateModelRows(schema.getPath(draft, ["models"]), routeApi);
|
|
2274
2457
|
const keyFailure = (() => {
|
|
2275
2458
|
if (keyDraft.length === 0) return void 0;
|
|
2276
2459
|
const value = keyDraft.trim();
|
|
@@ -2298,8 +2481,8 @@ if (typeof document !== 'undefined' && document.querySelector('style[data-plugin
|
|
|
2298
2481
|
const applyOnce = async () => {
|
|
2299
2482
|
const ns = namespace.ns;
|
|
2300
2483
|
let next = layout === "pi-ai" && stringAt(draft, "apiKeyEnv") === void 0 && stringAt(fallback, "apiKeyEnv") === void 0 && keyValue.length > 0 ? schema.setPath(draft, ["apiKeyEnv"], keyRef) : draft;
|
|
2301
|
-
const rowFailure = validateModelRows(schema.getPath(next, ["models"]));
|
|
2302
|
-
if (rowFailure !== void 0) return `模型 ${String(rowFailure.index + 1)}:${{
|
|
2484
|
+
const rowFailure = validateModelRows(schema.getPath(next, ["models"]), routeApi);
|
|
2485
|
+
if (rowFailure !== void 0) return rowFailure.key === "modelCompatNotOffered" ? compatFailureMessage(rowFailure) : `模型 ${String(rowFailure.index + 1)}:${{
|
|
2303
2486
|
modelIdRequired: "模型 ID 不能为空。",
|
|
2304
2487
|
modelIdDuplicate: "模型 ID 不能重复。",
|
|
2305
2488
|
modelNameInvalid: "显示名称不能为空。",
|
|
@@ -2494,6 +2677,7 @@ if (typeof document !== 'undefined' && document.querySelector('style[data-plugin
|
|
|
2494
2677
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ModelCatalog, {
|
|
2495
2678
|
models,
|
|
2496
2679
|
overridden: modelsOverridden,
|
|
2680
|
+
routeApi,
|
|
2497
2681
|
defaultContextWindow: typeof defaultContextWindow === "number" ? defaultContextWindow : void 0,
|
|
2498
2682
|
defaultMaxTokens: typeof defaultMaxTokens === "number" ? defaultMaxTokens : void 0,
|
|
2499
2683
|
probe,
|
|
@@ -2516,7 +2700,7 @@ if (typeof document !== 'undefined' && document.querySelector('style[data-plugin
|
|
|
2516
2700
|
}) : null,
|
|
2517
2701
|
modelFailure === void 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
2518
2702
|
className: models_plus_module_default["advancedHint"],
|
|
2519
|
-
children: `模型 ${String(modelFailure.index + 1)}:${modelFailure.key}`
|
|
2703
|
+
children: modelFailure.key === "modelCompatNotOffered" ? compatFailureMessage(modelFailure) : `模型 ${String(modelFailure.index + 1)}:${modelFailure.key}`
|
|
2520
2704
|
}),
|
|
2521
2705
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2522
2706
|
className: models_plus_module_default["editorActions"],
|
|
@@ -2580,7 +2764,7 @@ if (typeof document !== 'undefined' && document.querySelector('style[data-plugin
|
|
|
2580
2764
|
const profileDisabled = disabled || committed;
|
|
2581
2765
|
const routeInvalid = route.length > 0 && !ROUTE_PATTERN.test(route);
|
|
2582
2766
|
const routeTaken = taken.includes(route);
|
|
2583
|
-
const modelFailure = validateModelRows(models);
|
|
2767
|
+
const modelFailure = validateModelRows(models, protocol);
|
|
2584
2768
|
const keyFailure = (() => {
|
|
2585
2769
|
if (keyDraft.length === 0) return void 0;
|
|
2586
2770
|
const value = keyDraft.trim();
|
|
@@ -2592,7 +2776,7 @@ if (typeof document !== 'undefined' && document.querySelector('style[data-plugin
|
|
|
2592
2776
|
})();
|
|
2593
2777
|
const keyValue = keyDraft.trim();
|
|
2594
2778
|
const ready = route.length > 0 && !routeInvalid && !routeTaken && baseURL.length > 0 && models.length > 0 && modelFailure === void 0 && keyFailure === void 0;
|
|
2595
|
-
const hint = failure !== void 0 || ready || keyFailure !== void 0 || route.length === 0 || routeInvalid || routeTaken ? void 0 : baseURL.length === 0 ? "自定义提供方需要填写 API 地址。" : modelFailure !== void 0 ? `模型 ${String(modelFailure.index + 1)}:${modelFailure.key}` : "自定义提供方至少需要一个模型。";
|
|
2779
|
+
const hint = failure !== void 0 || ready || keyFailure !== void 0 || route.length === 0 || routeInvalid || routeTaken ? void 0 : baseURL.length === 0 ? "自定义提供方需要填写 API 地址。" : modelFailure !== void 0 ? modelFailure.key === "modelCompatNotOffered" ? compatFailureMessage(modelFailure) : `模型 ${String(modelFailure.index + 1)}:${modelFailure.key}` : "自定义提供方至少需要一个模型。";
|
|
2596
2780
|
/** Perform the create, returning a failure message or undefined. */
|
|
2597
2781
|
const createOnce = async () => {
|
|
2598
2782
|
const keyRef = deriveKeyRef(route);
|
|
@@ -2784,6 +2968,7 @@ if (typeof document !== 'undefined' && document.querySelector('style[data-plugin
|
|
|
2784
2968
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ModelCatalog, {
|
|
2785
2969
|
models,
|
|
2786
2970
|
overridden: true,
|
|
2971
|
+
routeApi: protocol,
|
|
2787
2972
|
defaultContextWindow: void 0,
|
|
2788
2973
|
defaultMaxTokens: void 0,
|
|
2789
2974
|
probe: {
|