@leterhong/multichat 1.7.0 → 1.8.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.
- package/backend/package.json +1 -1
- package/frontend/dist/assets/{agentPicker-DIOlVr1C.js → agentPicker-Jan8fWb3.js} +9 -9
- package/frontend/dist/assets/{assets-D2_TVEqD.js → assets-ChkvQqhp.js} +1 -1
- package/frontend/dist/assets/{compare-BYqbOF36.js → compare-CkyqXEbN.js} +1 -1
- package/frontend/dist/assets/conversations-DoyXfY4T.js +1 -0
- package/frontend/dist/assets/data-BN7t_AoO.js +1 -0
- package/frontend/dist/assets/{extensionImport-C2cHyfeC.js → extensionImport-DPZhdnxE.js} +10 -10
- package/frontend/dist/assets/{importExport-BWpKt1dW.js → importExport-Bb6-L-4y.js} +18 -18
- package/frontend/dist/assets/index-CeU_ksnE.js +49 -0
- package/frontend/dist/assets/index-DDdMiim6.css +1 -0
- package/frontend/dist/assets/init-yIIG9GSH.js +1 -0
- package/frontend/dist/assets/{modal-CO4he94s.js → modal-BYrNUOVj.js} +1 -1
- package/frontend/dist/assets/modelPicker-B612Gojw.js +14 -0
- package/frontend/dist/assets/pluginsUI-KCpFagXv.js +16 -0
- package/frontend/dist/assets/react-sySUN5R7.js +1 -0
- package/frontend/dist/assets/{render-BVmIwN3C.js → render-BBfAbC8M.js} +1 -1
- package/frontend/dist/assets/send-BAyqvnlM.js +14 -0
- package/frontend/dist/assets/settings-DkUaMAOG.js +2 -0
- package/frontend/dist/assets/{shell-BLqMMR-L.js → shell-Cny595HR.js} +1 -1
- package/frontend/dist/assets/{workbench-ChZGUESv.js → workbench-cTwE7423.js} +12 -12
- package/frontend/dist/boot-fallback.js +2 -0
- package/frontend/dist/icon-maskable.svg +18 -6
- package/frontend/dist/icon.svg +13 -6
- package/frontend/dist/index.html +6 -6
- package/frontend/dist/manifest.webmanifest +2 -2
- package/frontend/dist/theme-seed.js +10 -0
- package/package.json +1 -1
- package/frontend/dist/assets/conversations-DSJtvviE.js +0 -1
- package/frontend/dist/assets/data-D6TAf2h9.js +0 -1
- package/frontend/dist/assets/index-BaUGyQ3C.js +0 -46
- package/frontend/dist/assets/index-DXwClNo-.css +0 -1
- package/frontend/dist/assets/init-DUZJcBWS.js +0 -1
- package/frontend/dist/assets/modelPicker-Ddloc_nz.js +0 -14
- package/frontend/dist/assets/pluginsUI-28Rxtlgo.js +0 -16
- package/frontend/dist/assets/react-CDEwA66Z.js +0 -1
- package/frontend/dist/assets/send-yu3ud0kM.js +0 -14
- package/frontend/dist/assets/settings-IUzleKUb.js +0 -2
package/backend/package.json
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{E as e,O as t,T as n,b as r,y as i}from"./index-CeU_ksnE.js";import{importProjectFolder as a}from"./assets-ChkvQqhp.js";e(`#workspacePicker`).onclick=()=>{let e=r.projects.map(e=>({id:e.id,name:e.name,description:e.description}));showModal({title:`选择项目`,body:`<div class="picker-dialog-intro"><span>每个项目保存自己的文件、记忆和对话上下文</span><span>${e.length} 个项目</span></div>
|
|
2
2
|
<button type="button" class="picker-import-project" data-import-project>
|
|
3
3
|
<span class="picker-provider-mark folder" aria-hidden="true">+</span>
|
|
4
4
|
<span class="picker-option-copy"><strong>打开本地项目文件夹</strong><small>自动创建项目并导入可读取的源码与文档</small></span>
|
|
5
5
|
<span class="picker-option-state" aria-hidden="true">›</span>
|
|
6
6
|
</button>
|
|
7
|
-
<div class="model-picker-list">${e.map(e=>{let n=
|
|
8
|
-
<span class="picker-provider-mark" aria-hidden="true">${i?`—`:
|
|
9
|
-
<span class="picker-option-copy"><strong>${
|
|
7
|
+
<div class="model-picker-list">${e.map(e=>{let n=r.selectedProject?.id===e.id,i=e.id===`pr_inbox`||e.name===`收件箱`,a=i?`临时对话`:e.name,o=i?`不载入项目文件,只进行普通对话`:e.description||`本地项目`;return`<button type="button" class="picker-option${n?` active`:``}" data-pid="${t(e.id)}" aria-pressed="${n}">
|
|
8
|
+
<span class="picker-provider-mark" aria-hidden="true">${i?`—`:t(a.trim().slice(0,1).toUpperCase()||`P`)}</span>
|
|
9
|
+
<span class="picker-option-copy"><strong>${t(a)}</strong><small>${t(o)}</small></span>
|
|
10
10
|
<span class="picker-option-state" aria-hidden="true">${n?`✓`:`›`}</span>
|
|
11
|
-
</button>`}).join(``)}</div>`,onMount:e=>{let
|
|
11
|
+
</button>`}).join(``)}</div>`,onMount:e=>{let t=e.querySelector(`[data-import-project]`);t&&(t.onclick=()=>{closeModal(),a()}),e.querySelectorAll(`[data-pid]`).forEach(e=>e.onclick=async()=>{let t=r.projects.find(t=>t.id===e.dataset.pid)||null;t&&(r.selectedProject=t,localStorage.setItem(`multichat_project`,t.id),await loadProjects(),await newConversation(),renderTopbar(),renderFileContext(),closeModal())})}})},e(`#agentPicker`).onclick=()=>{if(!r.agents.length){openSettings(`agents`),n(`请先创建运行配置`);return}let e=[{id:``,name:`直接对话`,description:`不注入系统提示词,也不启用工具`}].concat(r.agents.map(e=>({id:e.id,name:e.name,description:e.description})));showModal({title:`选择运行配置`,body:`<div class="picker-dialog-intro"><span>选择本轮使用的提示词与能力组合</span><span>${r.agents.length} 个配置</span></div>
|
|
12
12
|
<div class="model-picker-list">
|
|
13
|
-
${e.map(e=>{let n=(
|
|
14
|
-
<span class="picker-provider-mark agent" aria-hidden="true">${e.id?
|
|
15
|
-
<span class="picker-option-copy"><strong>${
|
|
13
|
+
${e.map(e=>{let n=(r.selectedAgent?.id||``)===e.id;return`<button type="button" class="picker-option${n?` active`:``}" data-aid="${t(e.id)}" aria-pressed="${n}">
|
|
14
|
+
<span class="picker-provider-mark agent" aria-hidden="true">${e.id?t(e.name.trim().slice(0,1).toUpperCase()||`A`):`—`}</span>
|
|
15
|
+
<span class="picker-option-copy"><strong>${t(e.name)}</strong><small>${t(e.description||`自定义运行配置`)}</small></span>
|
|
16
16
|
<span class="picker-option-state" aria-hidden="true">${n?`✓`:`›`}</span>
|
|
17
17
|
</button>`}).join(``)}
|
|
18
|
-
</div>`,onMount:e=>{e.querySelectorAll(`[data-aid]`).forEach(e=>{e.onclick=()=>{let
|
|
18
|
+
</div>`,onMount:e=>{e.querySelectorAll(`[data-aid]`).forEach(e=>{e.onclick=()=>{let t=e.dataset.aid;r.selectedAgent=t?r.agents.find(e=>e.id===t):null,i(),renderTopbar(),closeModal(),r.messages.length||renderContent()}})}})};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{T as e,b as t,f as n}from"./index-CeU_ksnE.js";var r=18e5,i=16e6,a=240,o=new Set([`.git`,`.hg`,`.svn`,`.idea`,`.vscode`,`node_modules`,`dist`,`build`,`coverage`,`.next`,`.nuxt`,`.cache`,`target`,`vendor`,`__pycache__`]),s=new Set(`txt.md.mdx.json.jsonc.csv.tsv.js.jsx.mjs.cjs.ts.tsx.py.go.rs.java.kt.kts.c.h.cpp.hpp.cs.php.rb.swift.vue.svelte.html.htm.css.scss.sass.less.yaml.yml.toml.ini.conf.env.sql.graphql.gql.sh.bash.zsh.fish.ps1.bat.cmd.xml.svg.lock`.split(`.`)),c=new Set([`readme`,`license`,`changelog`,`makefile`,`procfile`,`dockerfile`,`.gitignore`,`.gitattributes`,`.editorconfig`,`.npmrc`,`.nvmrc`]);function l(e){return String(e.webkitRelativePath||e.name).replaceAll(`\\`,`/`).replace(/^\/+/,``)}function u(e){let t=Array.from(e,e=>{let t=l(e);return t.includes(`/`)?t.split(`/`).filter(Boolean)[0]:``}).filter(Boolean);return t.length&&t.every(e=>e===t[0])?t[0].slice(0,120):`本地项目`}function d(e,t){let n=l(e),r=`${t}/`;return n.startsWith(r)?n.slice(r.length):n}function f(e){let t=l(e).split(`/`).filter(Boolean);if(!t.length||t.some(e=>o.has(e.toLowerCase()))||!e.size||e.size>r)return!1;let n=t.at(-1)?.toLowerCase()||``,i=n.includes(`.`)&&n.split(`.`).pop()||``;return e.type.startsWith(`text/`)||s.has(i)||c.has(n)}function p(e){let t=Array.from(e),n=u(t),r=[],o=0,s=0;for(let e of t)r.length>=a||!f(e)||o+e.size>i?s+=1:(r.push({file:e,name:d(e,n)}),o+=e.size);return{selected:r,skipped:s,bytes:o}}async function m(e){if(!t.selectedWorkspace)throw Error(`项目存储尚未初始化,请刷新页面后重试`);let r=t.projects.find(t=>t.id!==`pr_inbox`&&String(t.name).toLowerCase()===e.toLowerCase());r||(r=await n(`/api/projects`,{method:`POST`,body:JSON.stringify({workspaceId:t.selectedWorkspace.id,name:e,description:`从本地项目文件夹导入`})}),t.projects=[r,...t.projects]);let i=t.selectedProject?.id!==r.id;return t.selectedProject=r,localStorage.setItem(`multichat_project`,r.id),t.assets=await n(`/api/assets?projectId=`+encodeURIComponent(r.id)),t.selectedAssetIds=new Set(t.assets.map(e=>e.id)),await loadProjectControlData(),i&&(document.querySelector(`#settings.open`)&&closeSettings(),await newConversation()),renderTopbar(),renderFileContext(),r}async function h(r){let{selected:i,skipped:a}=p(r);if(!i.length){e(`文件夹中没有可导入的文本或源代码文件`,`error`);return}let o=u(r),s;try{s=await m(o)}catch(t){e(t.message||`无法创建项目`,`error`);return}let c=s.id,l=new Set((t.assets||[]).map(e=>String(e.name).toLowerCase())),d=i.filter(e=>!l.has(e.name.toLowerCase())),f=i.length-d.length;if(!d.length){e(`该文件夹中的可用文件已经在当前项目中`);return}e(`正在打开「${o}」并导入 ${d.length} 个文件…`);let h=[],g=[],_=0,v=async()=>{for(;_<d.length;){let e=d[_++];try{let t=await n(`/api/assets`,{method:`POST`,body:JSON.stringify({projectId:c,name:e.name,mimeType:e.file.type||`text/plain`,content:await e.file.text()})});h.push(t)}catch{g.push(e.name)}}};await Promise.all(Array.from({length:Math.min(4,d.length)},()=>v())),h.length&&(t.assets=[...h,...t.assets],t.selectedAssetIds=new Set([...t.selectedAssetIds,...h.map(e=>e.id)]));let y=[a?`跳过 ${a} 个构建产物、二进制或超限文件`:``,f?`忽略 ${f} 个重复文件`:``,g.length?`${g.length} 个文件导入失败`:``].filter(Boolean);renderTopbar(),renderFileContext(),e(`项目「${o}」已打开,新增 ${h.length} 个文件${y.length?`;${y.join(`,`)}`:``}`,g.length?`error`:void 0)}function g(){return new Promise(e=>{let t=document.createElement(`input`);t.type=`file`,t.multiple=!0,t.setAttribute(`webkitdirectory`,``),t.setAttribute(`directory`,``),t.className=`project-folder-input`,t.setAttribute(`aria-hidden`,`true`),document.body.appendChild(t);let n=()=>{t.remove(),e()};t.addEventListener(`change`,()=>{h(Array.from(t.files||[])).finally(n)},{once:!0}),t.addEventListener(`cancel`,n,{once:!0}),t.click()})}export{g as importProjectFolder,f as isProjectTextFile,u as projectFolderName,p as selectProjectFiles};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{D as e,T as t,b as n,m as r}from"./index-CeU_ksnE.js";function i(){return(n.providers||[]).flatMap(e=>(e.models||[]).map(t=>({id:`${e.id}:${t}`,providerId:e.id,providerName:e.name||e.id,model:t})))}async function a(e,t,i){let a=performance.now();try{let o=await fetch(n.apiBase+`/v1/chat/completions`,{method:`POST`,headers:{"Content-Type":`application/json`,...r()},signal:i,body:JSON.stringify({providerId:e.providerId,model:e.model,messages:[{role:`user`,content:t}],stream:!1,temperature:n.params.temperature,max_tokens:n.params.max_tokens,top_p:n.params.top_p,workspaceId:n.selectedWorkspace?.id||null,projectId:n.selectedProject?.id||null,assetIds:[...n.selectedAssetIds],interactionId:`compare_${crypto.randomUUID()}`})}),s=await o.json();if(!o.ok){let e=typeof s?.error==`string`?s.error:s?.error?.message;throw Error(e||`HTTP ${o.status}`)}return{...e,status:`success`,text:s?.choices?.[0]?.message?.content||``,usage:s?.usage||{},elapsedMs:Math.round(performance.now()-a)}}catch(t){return t instanceof Error&&t.name===`AbortError`?{...e,status:`cancelled`,elapsedMs:Math.round(performance.now()-a)}:{...e,status:`error`,error:t instanceof Error?t.message:String(t),elapsedMs:Math.round(performance.now()-a)}}}async function o(e,r){if(!e.text)return;let i=(n.providers||[]).find(t=>t.id===e.providerId);i&&(n.selectedProvider=i,n.selectedModel=e.model),n.messages=[...n.messages,{role:`user`,content:r},{role:`assistant`,content:e.text,model:e.model,providerName:e.providerName,usage:e.usage,elapsedMs:e.elapsedMs,importedFromCompare:!0}];try{await ensureConversation(),await saveCurrentMessages()}catch{}renderTopbar(),renderContent(),renderConvList(),t(`已采用 ${e.model} 的结果`)}function s(){openSettings(`experiment`)}function c(){e(`[data-open-compare]`).forEach(e=>e.onclick=s)}export{o as adoptResult,i as compareTargets,a as executeTarget,s as openCompare,c as setupCompare};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{C as e,E as t,T as n,b as r,f as i,i as a,w as o,y as s}from"./index-CeU_ksnE.js";function c(t=r.currentConvId,n=r.selectedProject?.id){let i=o(t,n);r.workflowScope=i,r.workflow=e(i)}async function l(){try{r.conversations=await i(`/api/conversations`),r.conversationsLoadFailed=!1}catch{r.conversations=[],r.conversationsLoadFailed=!0}}function u(){}async function d(e){let o=r.conversations.find(t=>t.id===e);if(o&&await showConfirm({title:`删除对话`,message:`删除「${o.title||`新对话`}」?`,confirmLabel:`删除`,danger:!0}))try{await i(`/api/conversations/`+encodeURIComponent(e),{method:`DELETE`}),r.conversations=r.conversations.filter(t=>t.id!==e),r.currentConvId===e&&(r.currentConvId=null,r.messages=[],c(null,r.selectedProject?.id),t(`#topbarTitle`).textContent=`新对话`,a(`chat`),location.hash!==`#/new`&&history.replaceState(null,``,`#/new`)),n(`对话已删除`)}catch(e){n(`删除对话失败:`+e.message,`error`)}}async function f(e){let a=r.conversations.find(t=>t.id===e);if(!a)return;let o=await showPrompt({title:`重命名任务`,label:`任务名称`,value:a.title||`新任务`,placeholder:`输入新的任务名称`,maxLength:120});if(o?.trim())try{let a=await i(`/api/conversations/`+encodeURIComponent(e),{method:`PUT`,body:JSON.stringify({title:o.trim()})});r.conversations=r.conversations.map(t=>t.id===e?{...t,...a}:t),r.currentConvId===e&&(t(`#topbarTitle`).textContent=a.title||o.trim()),n(`任务已重命名`)}catch(e){n(`重命名失败:`+e.message,`error`)}}async function p(){a(`home`),r.currentConvId=null,r.messages=[],c(null,r.selectedProject?.id),t(`#topbarTitle`).textContent=`新对话`,renderContent(),renderInspector(),requestAnimationFrame(()=>t(`#heroInput`)?.focus()),location.hash!==`#/home`&&history.pushState(null,``,`#/home`)}async function m(e){try{a(`chat`);let n=await i(`/api/conversations/`+encodeURIComponent(e));(n.workspaceId&&(!r.selectedWorkspace||r.selectedWorkspace.id!==n.workspaceId)||n.projectId&&(!r.selectedProject||r.selectedProject.id!==n.projectId))&&(r.selectedWorkspace=r.workspaces.find(e=>e.id===n.workspaceId)||r.selectedWorkspace,r.selectedWorkspace&&await loadProjects(),n.projectId&&(r.selectedProject=r.projects.find(e=>e.id===n.projectId)||r.selectedProject,r.selectedProject&&(localStorage.setItem(`multichat_project`,r.selectedProject.id),r.assets=await i(`/api/assets?projectId=`+encodeURIComponent(r.selectedProject.id)),r.selectedAssetIds=new Set(r.assets.map(e=>e.id))))),r.currentConvId=n.id,r.messages=(n.messages||[]).map(e=>({role:e.role,content:e.content,model:e.model})),c(n.id,n.projectId||r.selectedProject?.id),t(`#topbarTitle`).textContent=n.title||`对话`,renderTopbar(),renderContent(),g();let o=`#/chat/${encodeURIComponent(n.id)}`;location.hash!==o&&history.pushState(null,``,o)}catch(t){if(t?.status===404){r.conversations=r.conversations.filter(t=>t.id!==e),r.currentConvId===e&&(r.currentConvId=null,r.messages=[],c(null,r.selectedProject?.id)),a(`home`),history.replaceState(null,``,`#/home`),renderTopbar(),renderContent(),n(`该任务不存在或已被删除,已返回新任务页`,`error`);return}n(`打开对话失败:`+t.message,`error`)}}function h(e){try{return e<1024?e+` B`:e<1048576?(e/1024).toFixed(1)+` KB`:(e/1024/1024).toFixed(1)+` MB`}catch{return``}}function g(){renderContent(),renderInspector()}function _(){let e=r.selectedProject;if(e){if(e.defaultAgentId){let t=r.agents.find(t=>t.id===e.defaultAgentId);t&&(r.selectedAgent=t,s())}if(e.defaultProviderId&&e.defaultModel){let t=r.providers.find(t=>t.id===e.defaultProviderId);t&&(r.selectedProvider=t,r.selectedModel=e.defaultModel,localStorage.setItem(`multichat_lastModel`,t.id+`:`+e.defaultModel))}renderTopbar()}}export{c as activateWorkflow,_ as applyProjectDefaults,d as deleteConversation,h as fmtSize,l as loadConversations,p as newConversation,m as openConversation,f as renameConversation,u as renderConvList,g as renderFileContext};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{b as e,f as t}from"./index-CeU_ksnE.js";async function n(){try{e.providers=await t(`/api/providers`)}catch{e.providers=[]}}async function r(){try{e.runtime=await t(`/api/runtime`)}catch{e.runtime=null}}async function i(){try{e.runs=await t(`/api/runs?limit=40`)}catch{e.runs=[]}}async function a(n=e.usageRange){e.usageRange=String(n||`30`),e.usageLoading=!0;try{let n=new Date().getTimezoneOffset();e.usage=await t(`/api/usage?range=${encodeURIComponent(e.usageRange)}&offset=${n}`)}catch{e.usage=null}finally{e.usageLoading=!1}}async function o(){try{e.capabilities=await t(`/api/capabilities`)}catch{e.capabilities=null}}async function s(){if(!e.selectedProject)e.memories=[],e.snapshots=[];else try{[e.memories,e.snapshots]=await Promise.all([t(`/api/memories?projectId=`+encodeURIComponent(e.selectedProject.id)),t(`/api/snapshots?projectId=`+encodeURIComponent(e.selectedProject.id))])}catch{e.memories=[],e.snapshots=[]}}async function c(){try{e.workspaces=await t(`/api/workspaces`);let n=localStorage.getItem(`multichat_workspace`);e.selectedWorkspace=e.workspaces.find(e=>e.id===n)||e.workspaces[0]||null,await l()}catch{e.workspaces=[],e.projects=[]}}async function l(){if(!e.selectedWorkspace)e.projects=[],e.selectedProject=null;else try{e.projects=await t(`/api/projects?workspaceId=`+encodeURIComponent(e.selectedWorkspace.id));let n=localStorage.getItem(`multichat_project`);e.selectedProject=e.projects.find(e=>e.id===n)||e.projects.find(t=>t.id===e.selectedWorkspace.defaultProjectId)||e.projects[0]||null,localStorage.setItem(`multichat_workspace`,e.selectedWorkspace.id),e.selectedProject&&localStorage.setItem(`multichat_project`,e.selectedProject.id),e.selectedProject&&(e.assets=await t(`/api/assets?projectId=`+encodeURIComponent(e.selectedProject.id)),e.selectedAssetIds=new Set(e.assets.map(e=>e.id)),applyProjectDefaults(),await s())}catch{e.projects=[],e.selectedProject=null,e.assets=[],e.selectedAssetIds=new Set}}async function u(){try{e.skills=await t(`/api/skills`)}catch{e.skills=[]}}async function d(){try{e.tools=await t(`/api/tools`)}catch{e.tools=[]}}async function f(){try{e.mcpServers=await t(`/api/mcp-servers`)}catch{e.mcpServers=[]}}async function p(){let n=e.selectedAgent?.id;try{e.agents=await t(`/api/agents`),n&&(e.selectedAgent=e.agents.find(e=>e.id===n)||null)}catch{e.agents=[],n&&(e.selectedAgent=null)}}async function m(){try{e.plugins=await t(`/api/plugins`)}catch{e.plugins=[]}}export{p as loadAgents,o as loadCapabilities,f as loadMcpServers,m as loadPlugins,s as loadProjectControlData,l as loadProjects,n as loadProviders,i as loadRuns,r as loadRuntime,u as loadSkills,d as loadTools,a as loadUsage,c as loadWorkspaces};
|
|
@@ -1,28 +1,28 @@
|
|
|
1
|
-
import{
|
|
2
|
-
<div class="extension-import-row"><div><strong>${
|
|
3
|
-
${(
|
|
1
|
+
import{E as e,O as t,T as n,f as r}from"./index-CeU_ksnE.js";var i=`<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 15V4M7.5 8.5 12 4l4.5 4.5"/><path d="M4 15v3.5A1.5 1.5 0 0 0 5.5 20h13a1.5 1.5 0 0 0 1.5-1.5V15"/></svg>`,a=null,o={skill:{title:`导入 Agent Skill`,tab:`skills`,accept:`.zip,.md`,fileLabel:`选择 ZIP / SKILL.md`,directory:!0,help:`支持以 SKILL.md 为入口的 Skill ZIP、单个 SKILL.md,或直接选择完整目录。目录中的 scripts、references、assets 和 templates 会原样保留。`},mcp:{title:`导入 MCP 配置`,tab:`mcp`,accept:`.json,.mcp.json`,fileLabel:`选择 MCP JSON`,directory:!1,help:`支持 mcpServers、mcp_servers、servers 和直接 server map。导入项默认停用且未信任,不会在导入时启动命令或连接网络。`},plugin:{title:`安装插件包`,tab:`plugins`,accept:`.zip`,fileLabel:`选择插件 ZIP`,directory:!0,help:`插件以 .codex-plugin/plugin.json 为入口,整包注册到当前项目市场,Skill、MCP 与资源目录不会被扁平化。安装与启用分离。`}};function s(e){return new Promise((t,n)=>{let r=new FileReader;r.onerror=()=>n(Error(`无法读取 ${e.name}`)),r.onload=()=>{let i=String(r.result||``),a=i.indexOf(`,`);a<0?n(Error(`无法编码 ${e.name}`)):t(i.slice(a+1))},r.readAsDataURL(e)})}async function c(e){let t=Array.from(e||[]);if(!t.length)throw Error(`请先选择文件`);if(t.length>600)throw Error(`一次最多导入 600 个文件`);if(t.reduce((e,t)=>e+t.size,0)>20971520)throw Error(`导入文件总大小不能超过 20 MB`);if(!(t.length>1||t.some(e=>!!e.webkitRelativePath))){let e=t[0];return{fileName:e.name,contentBase64:await s(e)}}return{files:await Promise.all(t.map(async e=>({path:e.webkitRelativePath||e.name,contentBase64:await s(e)})))}}function l(e){return Number.isFinite(e)?e<1024?`${e} B`:e<1048576?`${(e/1024).toFixed(1)} KB`:`${(e/1024/1024).toFixed(1)} MB`:``}function u(e,n){if(e===`mcp`)return`<div class="extension-import-list">${(n.servers||[]).map(e=>`
|
|
2
|
+
<div class="extension-import-row"><div><strong>${t(e.name)}</strong><span>${t(e.id)}</span></div><div class="mc-tags"><span class="mc-tag">${t(String(e.transport||``).toUpperCase())}</span>${(e.targets||[]).map(e=>`<span class="mc-tag">${t(e)}</span>`).join(``)}</div></div>`).join(``)}</div>`;let r=n.components||{};return`<div class="mc-tags extension-import-tags">${[n.fileCount===void 0?``:`${n.fileCount} 个文件`,n.totalBytes===void 0?``:l(n.totalBytes),...n.resources||[],r.skills===void 0?``:`${r.skills} Skills`,r.mcpServers===void 0?``:`${r.mcpServers} MCP`].filter(Boolean).map(e=>`<span class="mc-tag">${t(e)}</span>`).join(``)}</div>
|
|
3
|
+
${(n.fileTree||[]).length?`<details class="extension-file-tree"><summary>查看包内文件</summary><pre>${t(n.fileTree.join(`
|
|
4
4
|
`))}</pre></details>`:``}`}async function d(e){e===`skill`&&await Promise.all([loadSkills(),loadAgents(),loadRuntime()]),e===`mcp`&&await Promise.all([loadMcpServers(),loadAgents(),loadRuntime()]),e===`plugin`&&await Promise.all([loadPlugins(),loadSkills(),loadMcpServers(),loadAgents(),loadRuntime()])}function f(i,a,s){let c=o[i],l=s.conflicts||[],f=l.some(e=>e.replaceable===!1),p=s.warnings||[];showModal({title:`预检通过 · ${s.name}`,body:`<div class="extension-import-summary">
|
|
5
5
|
<div class="extension-import-kind">${i===`skill`?`SKILL`:i===`mcp`?`MCP`:`PLUGIN`}</div>
|
|
6
|
-
<div><div class="extension-import-name">${
|
|
6
|
+
<div><div class="extension-import-name">${t(s.name)}</div><div class="pmeta">${t(s.description||``)}${s.version?` · v${t(s.version)}`:``}</div></div>
|
|
7
7
|
</div>
|
|
8
8
|
<div class="field"><label>安装范围</label><div class="extension-import-scope">当前项目 · ${i===`mcp`?`.codex/config.toml(启用且选择 Codex 后同步)`:i===`skill`?`.agents/skills`:`.agents/plugins/marketplace.json`}</div></div>
|
|
9
9
|
${u(i,s)}
|
|
10
|
-
${p.length?`<div class="extension-import-warnings"><strong>启用前请确认</strong>${p.map(e=>`<div>• ${
|
|
11
|
-
${l.length?`<div class="extension-import-conflicts"><strong>发现同名项</strong>${l.map(e=>`<div>${
|
|
10
|
+
${p.length?`<div class="extension-import-warnings"><strong>启用前请确认</strong>${p.map(e=>`<div>• ${t(e)}</div>`).join(``)}</div>`:``}
|
|
11
|
+
${l.length?`<div class="extension-import-conflicts"><strong>发现同名项</strong>${l.map(e=>`<div>${t(e.id)}${e.path?` · ${t(e.path)}`:``}${e.replaceable===!1?` · 其他来源,不可覆盖`:``}</div>`).join(``)}</div>`:``}
|
|
12
12
|
${i===`plugin`?`<div class="extension-import-note">插件以完整资源包安装并独立启停,包契约使用 Codex plugin。MultiChat 当前会加载其中的 Skills 与 MCP;其他资源会保留,但不会把上传的 JS、hooks 直接注入网站主进程。</div>`:``}
|
|
13
13
|
${l.length&&!f?`<label class="extension-import-confirm"><input type="checkbox" id="replaceExtension" /> 我已确认,用这个包覆盖当前项目中的同名项</label>`:``}
|
|
14
14
|
<div id="extensionImportErr" class="auth-error">${f?`同名项来自插件或其他受保护来源,本次导入不能覆盖。`:``}</div>
|
|
15
|
-
<div class="row"><button type="button" class="btn-ghost" id="importBack">重新选择</button><button type="button" class="btn-primary btn-auto" id="importCommit" ${f?`disabled`:``}>确认导入</button></div>`,onMount:
|
|
15
|
+
<div class="row"><button type="button" class="btn-ghost" id="importBack">重新选择</button><button type="button" class="btn-primary btn-auto" id="importCommit" ${f?`disabled`:``}>确认导入</button></div>`,onMount:t=>{e(`#importBack`,t).onclick=()=>m(i),e(`#importCommit`,t).onclick=async()=>{let o=l.length>0&&!!e(`#replaceExtension`,t)?.checked;if(l.length&&!o){e(`#extensionImportErr`,t).textContent=`请先确认覆盖同名项。`;return}let u=e(`#importCommit`,t);u.disabled=!0,u.textContent=`正在导入…`;try{await r(`/api/extensions/import/${i}/install`,{method:`POST`,body:JSON.stringify({...a,expectedFingerprint:s.fingerprint,conflictPolicy:o?`replace`:`reject`})}),await d(i),renderSettings(c.tab,!0),closeModal(),n(i===`plugin`?`插件包已导入,当前保持停用`:i===`mcp`?`MCP 配置已导入,当前保持停用`:`Skill 已导入当前项目`)}catch(n){e(`#extensionImportErr`,t).textContent=n.message,u.disabled=!1,u.textContent=`确认导入`}}}})}async function p(t,n,i){let o=e(`#extensionPickStatus`,i);o.classList.remove(`error`),o.textContent=`正在读取并预检…`;let s=e(`#extensionPickRetry`,i);s&&(s.hidden=!0,s.disabled=!0);try{let e=await c(n);f(t,e,await r(`/api/extensions/import/${t}/inspect`,{method:`POST`,body:JSON.stringify(e)}))}catch(e){a={kind:t,files:n},o.textContent=e.message,o.classList.add(`error`),s&&(s.hidden=!1,s.disabled=!1,s.onclick=()=>a&&p(a.kind,a.files,i))}}function m(n){let r=o[n];showModal({title:r.title,body:`<p class="lead lead-tight">${t(r.help)}</p>
|
|
16
16
|
<div class="extension-dropzone" id="extensionDropzone" tabindex="0">
|
|
17
17
|
<div class="extension-drop-icon">${i}</div><strong>拖入文件进行预检</strong><span>不会在预检阶段执行任何脚本或 MCP 命令</span>
|
|
18
18
|
</div>
|
|
19
19
|
<div class="extension-picker-actions">
|
|
20
|
-
<button type="button" class="btn-primary btn-auto" id="pickExtensionFile">${
|
|
20
|
+
<button type="button" class="btn-primary btn-auto" id="pickExtensionFile">${t(r.fileLabel)}</button>
|
|
21
21
|
${r.directory?`<button type="button" class="btn-ghost" id="pickExtensionDirectory">选择完整目录</button>`:``}
|
|
22
22
|
</div>
|
|
23
|
-
<input type="file" id="extensionFileInput" accept="${
|
|
23
|
+
<input type="file" id="extensionFileInput" accept="${t(r.accept)}" hidden />
|
|
24
24
|
${r.directory?`<input type="file" id="extensionDirectoryInput" hidden multiple />`:``}
|
|
25
25
|
<div id="extensionPickStatus" class="extension-pick-status" role="status"></div>
|
|
26
26
|
<button type="button" class="btn-ghost" id="extensionPickRetry" hidden>用刚才的文件重新预检</button>
|
|
27
27
|
<div class="extension-import-note">默认冲突策略是拒绝覆盖;只有预检发现冲突且你再次勾选确认后,才会替换旧版本。</div>
|
|
28
|
-
<div class="row"><button type="button" class="btn-ghost" id="extensionImportCancel">取消</button></div>`,onMount:
|
|
28
|
+
<div class="row"><button type="button" class="btn-ghost" id="extensionImportCancel">取消</button></div>`,onMount:t=>{let r=e(`#extensionFileInput`,t),i=e(`#extensionDirectoryInput`,t);i&&i.setAttribute(`webkitdirectory`,``),e(`#pickExtensionFile`,t).onclick=()=>r.click(),i&&(e(`#pickExtensionDirectory`,t).onclick=()=>i.click()),e(`#extensionImportCancel`,t).onclick=closeModal,r.onchange=()=>r.files?.length&&p(n,r.files,t),i&&(i.onchange=()=>i.files?.length&&p(n,i.files,t));let a=e(`#extensionDropzone`,t);a.ondragover=e=>{e.preventDefault(),a.classList.add(`dragging`)},a.ondragleave=()=>a.classList.remove(`dragging`),a.ondrop=e=>{e.preventDefault(),a.classList.remove(`dragging`),e.dataTransfer?.files?.length&&p(n,e.dataTransfer.files,t)}}})}export{m as showExtensionImport};
|
|
@@ -1,30 +1,30 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{E as e,O as t,T as n,b as r,f as i}from"./index-CeU_ksnE.js";function a(){return`
|
|
2
2
|
<div class="import-bar">
|
|
3
3
|
<span class="import-bar-label">运行配置备份</span>
|
|
4
4
|
<button class="mini-btn" id="importFile">导入配置 JSON</button>
|
|
5
5
|
<input type="file" id="importFileInput" accept=".json,application/json" style="display:none" />
|
|
6
|
-
</div>`}async function o(e,
|
|
7
|
-
<div class="field"><label>名称</label><input name="name" value="${s?
|
|
8
|
-
<div class="field"><label>描述</label><input name="description" value="${s?
|
|
6
|
+
</div>`}async function o(e,t){try{let a=await i(`/api/import`,{method:`POST`,body:JSON.stringify(e)});return await loadAgents(),renderSettings(r.currentTab||`agents`,!0),renderTopbar(),n(`已导入 ${a.agents} 个运行配置(来源:${t})`),a}catch(e){throw n(e.message,`error`),e}}function s(e){if(Array.isArray(e))return{agents:e};if(e&&e.agents)return{agents:e.agents};if(e&&typeof e==`object`&&e.id)return{agents:[e]};throw Error(`文件不是 Agent JSON 备份`)}function c(){let t=e(`#settingsBody`),r=t.querySelector(`#importFile`),i=t.querySelector(`#importFileInput`);r&&i&&(r.onclick=()=>i.click(),i.onchange=async()=>{let e=i.files&&i.files[0];if(e){try{let t=await e.text();await o(s(JSON.parse(t)),`文件 `+e.name)}catch(e){n(`解析失败:`+e.message,`error`)}i.value=``}})}function l(e,t){let r=new Blob([JSON.stringify(e,null,2)],{type:`application/json`}),i=document.createElement(`a`);i.href=URL.createObjectURL(r),i.download=(e.id||t)+`.json`,document.body.appendChild(i),i.click(),i.remove(),setTimeout(()=>URL.revokeObjectURL(i.href),1e3),n(`已导出:`+(e.name||e.id))}function u(a){let o=!!a,s=o?r.agents.find(e=>e.id===a):null;showModal({title:o?`编辑运行配置`:`新建运行配置`,body:`<form id="agentForm">
|
|
7
|
+
<div class="field"><label>名称</label><input name="name" value="${s?t(s.name):``}" placeholder="中英翻译" required /></div>
|
|
8
|
+
<div class="field"><label>描述</label><input name="description" value="${s?t(s.description||``):``}" placeholder="一句话说明这套配置适合什么任务" /></div>
|
|
9
9
|
<div class="field"><label>系统提示词 <button type="button" class="btn-ghost tpl-save" id="savePromptTpl" style="float:right;font-size:11px;">存为模板</button></label>
|
|
10
10
|
<select id="promptTplPick" class="form-control" style="margin-bottom:6px;"><option value="">从模板填充…</option></select>
|
|
11
|
-
<textarea name="systemPrompt" rows="4" placeholder="你是一个...">${s?
|
|
12
|
-
<div class="field"><label>单次最大执行轮数</label><input name="maxIterations" type="number" min="1" max="30" step="1" value="${
|
|
11
|
+
<textarea name="systemPrompt" rows="4" placeholder="你是一个...">${s?t(s.systemPrompt||``):``}</textarea></div>
|
|
12
|
+
<div class="field"><label>单次最大执行轮数</label><input name="maxIterations" type="number" min="1" max="30" step="1" value="${t(s?.maxIterations||12)}" /><div class="pmeta">达到上限后保存检查点,可在对话中继续运行。</div></div>
|
|
13
13
|
<div class="field"><label>Agent Skills(先提供描述,匹配任务时再加载完整工作流)</label>
|
|
14
14
|
<div class="extension-checks">
|
|
15
|
-
${
|
|
16
|
-
<input type="checkbox" name="skill" value="${
|
|
15
|
+
${r.skills.map(e=>{let n=e.key||e.id,r=s&&(s.skillRefs||s.skillIds)||[],i=r.includes(n)||r.includes(e.id)?`checked`:``;return`<label>
|
|
16
|
+
<input type="checkbox" name="skill" value="${t(n)}" ${i} /> ${t(e.name)} <span class="pmeta">${t(sourceLabel(e.source))}${e.enabled?``:` · 已停用`}</span>
|
|
17
17
|
</label>`}).join(``)||`<span class="pmeta">没有已启用的 Skill</span>`}
|
|
18
18
|
</div>
|
|
19
19
|
</div>
|
|
20
20
|
<div class="field"><label>内置工具(函数调用)</label>
|
|
21
21
|
<div class="extension-checks">
|
|
22
|
-
${(
|
|
22
|
+
${(r.tools||[]).map(e=>{let n=s&&(s.toolIds||[]).includes(e.id)?`checked`:``;return`<label><input type="checkbox" name="tool" value="${t(e.id)}" ${n} /> ${t(e.name)}${e.enabled?``:`(已停用)`}</label>`}).join(``)||`<span class="pmeta">没有已启用的内置工具</span>`}
|
|
23
23
|
</div>
|
|
24
24
|
</div>
|
|
25
25
|
<div class="field"><label>MCP servers(工具由 tools/list 实时发现)</label>
|
|
26
26
|
<div class="extension-checks">
|
|
27
|
-
${(
|
|
27
|
+
${(r.mcpServers||[]).filter(e=>(e.targets||[`multichat`]).includes(`multichat`)).map(e=>{let n=s&&(s.mcpServerIds||[]).includes(e.id)?`checked`:``;return`<label><input type="checkbox" name="mcpServer" value="${t(e.id)}" ${n} /> ${t(e.name)} <span class="pmeta">${(e.tools||[]).length} tools${e.enabled?``:` · 已停用`}</span></label>`}).join(``)||`<span class="pmeta">没有已启用的 MCP server</span>`}
|
|
28
28
|
</div>
|
|
29
29
|
</div>
|
|
30
30
|
<div id="agentErr" class="auth-error"></div>
|
|
@@ -32,21 +32,21 @@ import{S as e,c as t,g as n,w as r,x as i}from"./index-BaUGyQ3C.js";function a()
|
|
|
32
32
|
<button type="button" class="btn-ghost" id="agentCancel">取消</button>
|
|
33
33
|
<button type="submit" class="btn-primary btn-auto">${o?`保存`:`创建`}</button>
|
|
34
34
|
</div>
|
|
35
|
-
</form>`,onMount:
|
|
36
|
-
<div class="field"><label>Skill ID</label><input name="id" value="${s?
|
|
35
|
+
</form>`,onMount:t=>{e(`#agentCancel`,t).onclick=closeModal;let c=e(`#promptTplPick`,t),l=t.querySelector(`[name="systemPrompt"]`);(async()=>{try{let e=await i(`/api/prompt-templates`);for(let t of e){let e=document.createElement(`option`);e.value=t.id,e.textContent=t.name,c.appendChild(e)}}catch{}})(),c.onchange=async()=>{if(!c.value)return;let e=(await i(`/api/prompt-templates`)).find(e=>e.id===c.value);e&&(l.value=e.content)},e(`#savePromptTpl`,t).onclick=async()=>{let e=l.value.trim();if(!e){n(`提示词为空,无法存为模板`,`error`);return}let t=await showPrompt({title:`保存为提示词模板`,label:`模板名称`,placeholder:`例如:代码审查员`,maxLength:80});if(t)try{await i(`/api/prompt-templates`,{method:`POST`,body:JSON.stringify({name:t,content:e})});let r=document.createElement(`option`);r.value=(await i(`/api/prompt-templates`)).find(e=>e.name===t)?.id||``,r.textContent=t,r.selected=!0,c.appendChild(r),n(`已保存模板:`+t)}catch(e){n(e.message,`error`)}},e(`#agentForm`,t).onsubmit=async c=>{c.preventDefault();let l=new FormData(c.target),u=Object.fromEntries(l.entries());u.name&&=u.name.trim(),u.description&&=u.description.trim(),u.maxIterations=Math.max(1,Math.min(30,Number.parseInt(u.maxIterations||`12`,10)||12));let d=new Set(r.skills.flatMap(e=>[e.key||e.id,e.id])),f=new Set((r.tools||[]).map(e=>e.id)),p=new Set((r.mcpServers||[]).filter(e=>(e.targets||[`multichat`]).includes(`multichat`)).map(e=>e.id)),m=o?(s?.skillRefs||s?.skillIds||[]).filter(e=>!d.has(e)):[],h=o?(s?.toolIds||[]).filter(e=>!f.has(e)):[],g=o?(s?.mcpServerIds||[]).filter(e=>!p.has(e)):[];u.skillRefs=[...Array.from(c.target.querySelectorAll(`input[name="skill"]:checked`)).map(e=>e.value),...m],u.toolIds=[...Array.from(c.target.querySelectorAll(`input[name="tool"]:checked`)).map(e=>e.value),...h],u.mcpServerIds=[...Array.from(c.target.querySelectorAll(`input[name="mcpServer"]:checked`)).map(e=>e.value),...g];try{o?(await i(`/api/agents/`+a,{method:`PUT`,body:JSON.stringify(u)}),n(`已保存`)):(await i(`/api/agents`,{method:`POST`,body:JSON.stringify(u)}),n(`已创建`)),await loadAgents(),renderSettings(r.currentTab||`agents`,!0),renderTopbar(),closeModal()}catch(n){e(`#agentErr`,t).textContent=n.message}}}})}function d(a){let o=!!a,s=o?r.skills.find(e=>(e.key||e.id)===a):null;showModal({title:o?`编辑 Agent Skill`:`新建 Agent Skill`,body:`<form id="skillForm">
|
|
36
|
+
<div class="field"><label>Skill ID</label><input name="id" value="${s?t(s.id):``}" placeholder="release-notes" required pattern="[a-z0-9-]+" ${o?`readonly`:``} />
|
|
37
37
|
<div class="pmeta">1–64 位小写字母、数字或连字符;写入 SKILL.md frontmatter。</div></div>
|
|
38
|
-
<div class="field"><label>Skill name</label><input name="name" value="${s?
|
|
39
|
-
<div class="field"><label>Description</label><textarea name="description" rows="3" placeholder="说明何时应使用此 Skill,以及它能完成什么。" required>${s?
|
|
40
|
-
<div class="field"><label>Instructions(SKILL.md 正文)</label><textarea name="instructions" rows="9" placeholder="# Workflow 1. ..." required>${s?
|
|
38
|
+
<div class="field"><label>Skill name</label><input name="name" value="${s?t(s.name):``}" placeholder="release-notes" required pattern="[a-z0-9-]+" ${o?`readonly`:``} /></div>
|
|
39
|
+
<div class="field"><label>Description</label><textarea name="description" rows="3" placeholder="说明何时应使用此 Skill,以及它能完成什么。" required>${s?t(s.description||``):``}</textarea></div>
|
|
40
|
+
<div class="field"><label>Instructions(SKILL.md 正文)</label><textarea name="instructions" rows="9" placeholder="# Workflow 1. ..." required>${s?t(s.instructions||``):``}</textarea>
|
|
41
41
|
<div class="pmeta">需要脚本、参考资料或模板时,可在对应 Skill 目录添加 scripts、references、assets。</div></div>
|
|
42
42
|
<div id="skillErr" class="auth-error"></div>
|
|
43
43
|
<div class="row">
|
|
44
44
|
<button type="button" class="btn-ghost" id="skillCancel">取消</button>
|
|
45
45
|
<button type="submit" class="btn-primary btn-auto">${o?`保存`:`创建`}</button>
|
|
46
46
|
</div>
|
|
47
|
-
</form>`,onMount:
|
|
47
|
+
</form>`,onMount:t=>{e(`#skillCancel`,t).onclick=closeModal,e(`#skillForm`,t).onsubmit=async s=>{s.preventDefault();let c=new FormData(s.target),l=Object.fromEntries(c.entries());l.id&&=l.id.trim(),l.name&&=l.name.trim(),l.description&&=l.description.trim(),l.instructions&&=l.instructions.trim();try{if(o){let e={...l};delete e.id,await i(`/api/skills/`+encodeURIComponent(a),{method:`PUT`,body:JSON.stringify(e)}),n(`已保存`)}else await i(`/api/skills`,{method:`POST`,body:JSON.stringify(l)}),n(`已创建`);await loadSkills(),renderSettings(r.currentTab||`skills`,!0),closeModal()}catch(n){e(`#skillErr`,t).textContent=n.message}}}})}var f=[{id:`mock`,name:`本地体验(无需密钥)`,apiType:`openai`,baseUrl:`http://127.0.0.1:3099`,models:[`echo`],allowPrivate:!0},{id:`openai`,name:`OpenAI`,apiType:`openai`,baseUrl:`https://api.openai.com/v1`,models:[`gpt-4o`,`gpt-4o-mini`,`gpt-4-turbo`]},{id:`deepseek`,name:`DeepSeek`,apiType:`openai`,baseUrl:`https://api.deepseek.com/v1`,models:[`deepseek-chat`,`deepseek-reasoner`]},{id:`anthropic`,name:`Anthropic`,apiType:`anthropic`,baseUrl:`https://api.anthropic.com/v1`,models:[`claude-3-5-sonnet-latest`,`claude-3-opus-latest`,`claude-3-haiku-latest`]},{id:`gemini`,name:`Google Gemini`,apiType:`openai`,baseUrl:`https://generativelanguage.googleapis.com/v1beta/openai`,models:[`gemini-1.5-pro`,`gemini-1.5-flash`,`gemini-2.0-flash`]},{id:`moonshot`,name:`月之暗面 Kimi`,apiType:`openai`,baseUrl:`https://api.moonshot.cn/v1`,models:[`moonshot-v1-8k`,`moonshot-v1-32k`,`moonshot-v1-128k`]},{id:`zhipu`,name:`智谱 GLM`,apiType:`zhipu`,baseUrl:`https://open.bigmodel.cn/api/paas/v4`,models:[`glm-4-plus`,`glm-4`,`glm-4-air`]},{id:`dashscope`,name:`阿里云 DashScope`,apiType:`openai`,baseUrl:`https://dashscope.aliyuncs.com/compatible-mode/v1`,models:[`qwen-max`,`qwen-plus`,`qwen-turbo`]},{id:`ollama`,name:`Ollama (本地)`,apiType:`ollama`,baseUrl:`http://localhost:11434/v1`,models:[]},{id:`lmstudio`,name:`LM Studio (本地)`,apiType:`lmstudio`,baseUrl:`http://localhost:1234/v1`,models:[]},{id:`siliconflow`,name:`硅基流动 SiliconFlow (注册送额度)`,apiType:`openai`,baseUrl:`https://api.siliconflow.cn/v1`,models:[`Qwen/Qwen2.5-72B-Instruct`,`deepseek-ai/DeepSeek-V3`,`Qwen/Qwen2.5-7B-Instruct`]}];function p(){showModal({title:`添加提供方`,body:`<div class="provider-template-grid">
|
|
48
48
|
${f.map(e=>`<button class="add-tile" data-id="${e.id}"><div class="tpl-name">${e.name}</div><div class="tpl-meta">${e.apiType} · ${e.baseUrl}</div></button>`).join(``)}
|
|
49
|
-
</div>`,onMount:e=>{e.querySelectorAll(`[data-id]`).forEach(e=>e.onclick=async()=>{let
|
|
49
|
+
</div>`,onMount:e=>{e.querySelectorAll(`[data-id]`).forEach(e=>e.onclick=async()=>{let t=f.find(t=>t.id===e.dataset.id);try{await i(`/api/providers`,{method:`POST`,body:JSON.stringify(t)}),await loadProviders(),renderSettings(`providers`,!0),closeModal(),n(`已添加:`+t.name)}catch(e){n(e.message,`error`)}})}})}function m(){showModal({title:`自定义提供方`,body:`<form id="customForm">
|
|
50
50
|
<div class="field"><label>Provider ID(留空自动生成)</label><input name="id" placeholder="留空自动生成,例如 acme-gateway" />
|
|
51
51
|
<div class="field-hint">小写字母、数字、下划线或连字符,唯一标识该提供方;不确定就留空。</div></div>
|
|
52
52
|
<div class="field"><label>模型列表</label><textarea name="models" rows="2" placeholder="deepseek-chat, deepseek-reasoner"></textarea>
|
|
@@ -66,4 +66,4 @@ import{S as e,c as t,g as n,w as r,x as i}from"./index-BaUGyQ3C.js";function a()
|
|
|
66
66
|
<button type="button" class="btn-ghost" id="customCancel">取消</button>
|
|
67
67
|
<button type="submit" class="btn-primary btn-auto">保存</button>
|
|
68
68
|
</div>
|
|
69
|
-
</form>`,onMount:
|
|
69
|
+
</form>`,onMount:t=>{e(`#customCancel`,t).onclick=closeModal,e(`#customForm`,t).onsubmit=async r=>{r.preventDefault();let a=new FormData(r.target),o=Object.fromEntries(a.entries());o.models=(o.models||``).toString().split(/[,\n]/).map(e=>e.trim()).filter(Boolean),o.allowPrivate=a.get(`allowPrivate`)===`on`,o.id&&=o.id.trim(),o.name&&=o.name.trim();try{await i(`/api/providers`,{method:`POST`,body:JSON.stringify(o)}),await loadProviders(),renderSettings(`providers`,!0),closeModal(),n(`已添加`)}catch(n){e(`#customErr`,t).textContent=n.message}}}})}export{f as BUILTIN_PROVIDERS,o as doImport,l as exportEntity,a as importBarHTML,s as normalizeImport,p as showAddBuiltin,m as showAddCustom,u as showAgentModal,d as showSkillModal,c as wireImportBar};
|