memi-agent 1.0.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/README.md +90 -0
- package/memi-agent.js +1364 -0
- package/memi-client/README.md +43 -0
- package/memi-client/dist/assets/index-CmQIBT8Z.js +210 -0
- package/memi-client/dist/assets/index-Djh6rbJ-.css +1 -0
- package/memi-client/dist/index.html +13 -0
- package/memi-config/workspace/IDENTITY.md +5 -0
- package/memi-config/workspace/MEMORY.md +3 -0
- package/memi-config/workspace/SOUL.md +4 -0
- package/memi-config/workspace/TOOLS.md +3 -0
- package/memi-config/workspace/USER.md +3 -0
- package/memi-dashboard.html +359 -0
- package/memi-server/README.md +56 -0
- package/memi-server/gateway.js +532 -0
- package/memi-server/index.js +152 -0
- package/memi-server/package-lock.json +1658 -0
- package/memi-server/package.json +16 -0
- package/memi-server/routes/api.js +744 -0
- package/memi-server/utils/agent.js +1068 -0
- package/memi-server/utils/aiProxy.js +871 -0
- package/memi-server/utils/importSkill.js +74 -0
- package/package.json +27 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
*,:before,:after{--tw-border-spacing-x: 0;--tw-border-spacing-y: 0;--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(59 130 246 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }::backdrop{--tw-border-spacing-x: 0;--tw-border-spacing-y: 0;--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(59 130 246 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }*,:before,:after{box-sizing:border-box;border-width:0;border-style:solid;border-color:#e5e7eb}:before,:after{--tw-content: ""}html,:host{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji",Segoe UI Symbol,"Noto Color Emoji";font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-feature-settings:normal;font-variation-settings:normal;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-feature-settings:inherit;font-variation-settings:inherit;font-size:100%;font-weight:inherit;line-height:inherit;letter-spacing:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button,input:where([type=button]),input:where([type=reset]),input:where([type=submit]){-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dl,dd,h1,h2,h3,h4,h5,h6,hr,figure,p,pre{margin:0}fieldset{margin:0;padding:0}legend{padding:0}ol,ul,menu{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}button,[role=button]{cursor:pointer}:disabled{cursor:default}img,svg,video,canvas,audio,iframe,embed,object{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]:where(:not([hidden=until-found])){display:none}.pointer-events-none{pointer-events:none}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.inset-0{top:0;right:0;bottom:0;left:0}.left-3{left:.75rem}.right-4{right:1rem}.top-1\/2{top:50%}.top-4{top:1rem}.z-50{z-index:50}.z-\[60\]{z-index:60}.mx-4{margin-left:1rem;margin-right:1rem}.mx-auto{margin-left:auto;margin-right:auto}.mb-1{margin-bottom:.25rem}.mb-1\.5{margin-bottom:.375rem}.mb-2{margin-bottom:.5rem}.mb-3{margin-bottom:.75rem}.mb-4{margin-bottom:1rem}.mb-5{margin-bottom:1.25rem}.mb-6{margin-bottom:1.5rem}.ml-2{margin-left:.5rem}.mr-1\.5{margin-right:.375rem}.mr-2{margin-right:.5rem}.mt-0\.5{margin-top:.125rem}.mt-1{margin-top:.25rem}.mt-1\.5{margin-top:.375rem}.mt-2{margin-top:.5rem}.mt-3{margin-top:.75rem}.mt-4{margin-top:1rem}.mt-5{margin-top:1.25rem}.mt-6{margin-top:1.5rem}.line-clamp-2{overflow:hidden;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2}.line-clamp-3{overflow:hidden;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:3}.block{display:block}.inline-block{display:inline-block}.inline{display:inline}.flex{display:flex}.inline-flex{display:inline-flex}.grid{display:grid}.hidden{display:none}.aspect-square{aspect-ratio:1 / 1}.h-1{height:.25rem}.h-10{height:2.5rem}.h-11{height:2.75rem}.h-14{height:3.5rem}.h-2{height:.5rem}.h-3{height:.75rem}.h-3\.5{height:.875rem}.h-4{height:1rem}.h-48{height:12rem}.h-5{height:1.25rem}.h-64{height:16rem}.h-8{height:2rem}.h-\[80vh\]{height:80vh}.h-full{height:100%}.h-screen{height:100vh}.max-h-24{max-height:6rem}.max-h-32{max-height:8rem}.max-h-48{max-height:12rem}.max-h-56{max-height:14rem}.max-h-\[680px\]{max-height:680px}.max-h-\[90vh\]{max-height:90vh}.min-h-44{min-height:11rem}.min-h-\[120px\]{min-height:120px}.min-h-\[300px\]{min-height:300px}.min-h-\[420px\]{min-height:420px}.min-h-\[44px\]{min-height:44px}.w-11{width:2.75rem}.w-12{width:3rem}.w-14{width:3.5rem}.w-2{width:.5rem}.w-2\/3{width:66.666667%}.w-20{width:5rem}.w-3{width:.75rem}.w-3\.5{width:.875rem}.w-52{width:13rem}.w-64{width:16rem}.w-7{width:1.75rem}.w-8{width:2rem}.w-9{width:2.25rem}.w-full{width:100%}.min-w-0{min-width:0px}.min-w-\[140px\]{min-width:140px}.max-w-2xl{max-width:42rem}.max-w-3xl{max-width:48rem}.max-w-4xl{max-width:56rem}.max-w-\[75\%\]{max-width:75%}.max-w-\[90vw\]{max-width:90vw}.max-w-full{max-width:100%}.max-w-lg{max-width:32rem}.max-w-md{max-width:28rem}.max-w-sm{max-width:24rem}.max-w-xl{max-width:36rem}.flex-1{flex:1 1 0%}.flex-shrink-0,.shrink-0{flex-shrink:0}.-translate-y-1\/2{--tw-translate-y: -50%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.translate-x-\[14px\]{--tw-translate-x: 14px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.translate-x-\[18px\]{--tw-translate-x: 18px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.translate-x-\[2px\]{--tw-translate-x: 2px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.translate-x-\[3px\]{--tw-translate-x: 3px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.transform{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}@keyframes bounce{0%,to{transform:translateY(-25%);animation-timing-function:cubic-bezier(.8,0,1,1)}50%{transform:none;animation-timing-function:cubic-bezier(0,0,.2,1)}}.animate-bounce{animation:bounce 1s infinite}@keyframes spin{to{transform:rotate(360deg)}}.animate-spin{animation:spin 1s linear infinite}.cursor-default{cursor:default}.cursor-pointer{cursor:pointer}.cursor-zoom-out{cursor:zoom-out}.resize-none{resize:none}.resize-y{resize:vertical}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.items-start{align-items:flex-start}.items-end{align-items:flex-end}.items-center{align-items:center}.justify-start{justify-content:flex-start}.justify-end{justify-content:flex-end}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.justify-around{justify-content:space-around}.gap-1{gap:.25rem}.gap-1\.5{gap:.375rem}.gap-2{gap:.5rem}.gap-3{gap:.75rem}.gap-4{gap:1rem}.gap-5{gap:1.25rem}.gap-6{gap:1.5rem}.space-y-0\.5>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.125rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.125rem * var(--tw-space-y-reverse))}.space-y-1\.5>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.375rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.375rem * var(--tw-space-y-reverse))}.space-y-2>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.5rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.5rem * var(--tw-space-y-reverse))}.space-y-3>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.75rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.75rem * var(--tw-space-y-reverse))}.space-y-4>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(1rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1rem * var(--tw-space-y-reverse))}.space-y-5>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(1.25rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1.25rem * var(--tw-space-y-reverse))}.space-y-6>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(1.5rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1.5rem * var(--tw-space-y-reverse))}.space-y-8>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(2rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(2rem * var(--tw-space-y-reverse))}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.overflow-x-auto{overflow-x:auto}.overflow-y-auto{overflow-y:auto}.truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.whitespace-nowrap{white-space:nowrap}.whitespace-pre{white-space:pre}.whitespace-pre-wrap{white-space:pre-wrap}.break-all{word-break:break-all}.rounded{border-radius:.25rem}.rounded-2xl{border-radius:1rem}.rounded-full{border-radius:9999px}.rounded-lg{border-radius:.5rem}.rounded-md{border-radius:.375rem}.rounded-xl{border-radius:.75rem}.border{border-width:1px}.border-2{border-width:2px}.border-b{border-bottom-width:1px}.border-r{border-right-width:1px}.border-t{border-top-width:1px}.border-gray-100{--tw-border-opacity: 1;border-color:rgb(243 244 246 / var(--tw-border-opacity, 1))}.border-gray-200{--tw-border-opacity: 1;border-color:rgb(229 231 235 / var(--tw-border-opacity, 1))}.border-gray-300{--tw-border-opacity: 1;border-color:rgb(209 213 219 / var(--tw-border-opacity, 1))}.border-gray-50{--tw-border-opacity: 1;border-color:rgb(249 250 251 / var(--tw-border-opacity, 1))}.border-gray-950{--tw-border-opacity: 1;border-color:rgb(3 7 18 / var(--tw-border-opacity, 1))}.border-green-100{--tw-border-opacity: 1;border-color:rgb(220 252 231 / var(--tw-border-opacity, 1))}.border-green-200{--tw-border-opacity: 1;border-color:rgb(187 247 208 / var(--tw-border-opacity, 1))}.border-red-100{--tw-border-opacity: 1;border-color:rgb(254 226 226 / var(--tw-border-opacity, 1))}.border-red-200{--tw-border-opacity: 1;border-color:rgb(254 202 202 / var(--tw-border-opacity, 1))}.bg-black\/20{background-color:#0003}.bg-black\/30{background-color:#0000004d}.bg-black\/60{background-color:#0009}.bg-gray-100{--tw-bg-opacity: 1;background-color:rgb(243 244 246 / var(--tw-bg-opacity, 1))}.bg-gray-200{--tw-bg-opacity: 1;background-color:rgb(229 231 235 / var(--tw-bg-opacity, 1))}.bg-gray-300{--tw-bg-opacity: 1;background-color:rgb(209 213 219 / var(--tw-bg-opacity, 1))}.bg-gray-50{--tw-bg-opacity: 1;background-color:rgb(249 250 251 / var(--tw-bg-opacity, 1))}.bg-gray-800{--tw-bg-opacity: 1;background-color:rgb(31 41 55 / var(--tw-bg-opacity, 1))}.bg-green-100{--tw-bg-opacity: 1;background-color:rgb(220 252 231 / var(--tw-bg-opacity, 1))}.bg-green-50{--tw-bg-opacity: 1;background-color:rgb(240 253 244 / var(--tw-bg-opacity, 1))}.bg-red-50{--tw-bg-opacity: 1;background-color:rgb(254 242 242 / var(--tw-bg-opacity, 1))}.bg-transparent{background-color:transparent}.bg-white{--tw-bg-opacity: 1;background-color:rgb(255 255 255 / var(--tw-bg-opacity, 1))}.bg-white\/10{background-color:#ffffff1a}.bg-white\/80{background-color:#fffc}.object-contain{-o-object-fit:contain;object-fit:contain}.object-cover{-o-object-fit:cover;object-fit:cover}.p-1{padding:.25rem}.p-10{padding:2.5rem}.p-2{padding:.5rem}.p-3{padding:.75rem}.p-4{padding:1rem}.p-5{padding:1.25rem}.p-6{padding:1.5rem}.p-8{padding:2rem}.px-2{padding-left:.5rem;padding-right:.5rem}.px-2\.5{padding-left:.625rem;padding-right:.625rem}.px-3{padding-left:.75rem;padding-right:.75rem}.px-4{padding-left:1rem;padding-right:1rem}.px-5{padding-left:1.25rem;padding-right:1.25rem}.px-6{padding-left:1.5rem;padding-right:1.5rem}.py-0\.5{padding-top:.125rem;padding-bottom:.125rem}.py-1{padding-top:.25rem;padding-bottom:.25rem}.py-1\.5{padding-top:.375rem;padding-bottom:.375rem}.py-2{padding-top:.5rem;padding-bottom:.5rem}.py-2\.5{padding-top:.625rem;padding-bottom:.625rem}.py-3{padding-top:.75rem;padding-bottom:.75rem}.py-4{padding-top:1rem;padding-bottom:1rem}.py-6{padding-top:1.5rem;padding-bottom:1.5rem}.pb-1{padding-bottom:.25rem}.pb-2{padding-bottom:.5rem}.pb-3{padding-bottom:.75rem}.pl-9{padding-left:2.25rem}.pr-4{padding-right:1rem}.pt-2{padding-top:.5rem}.pt-3{padding-top:.75rem}.pt-5{padding-top:1.25rem}.pt-8{padding-top:2rem}.text-left{text-align:left}.text-center{text-align:center}.align-middle{vertical-align:middle}.font-mono{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace}.text-2xl{font-size:1.5rem;line-height:2rem}.text-3xl{font-size:1.875rem;line-height:2.25rem}.text-\[11px\]{font-size:11px}.text-base{font-size:1rem;line-height:1.5rem}.text-lg{font-size:1.125rem;line-height:1.75rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xs{font-size:.75rem;line-height:1rem}.font-medium{font-weight:500}.font-normal{font-weight:400}.font-semibold{font-weight:600}.uppercase{text-transform:uppercase}.italic{font-style:italic}.leading-5{line-height:1.25rem}.leading-6{line-height:1.5rem}.leading-relaxed{line-height:1.625}.tracking-tight{letter-spacing:-.025em}.tracking-wide{letter-spacing:.025em}.text-gray-200{--tw-text-opacity: 1;color:rgb(229 231 235 / var(--tw-text-opacity, 1))}.text-gray-300{--tw-text-opacity: 1;color:rgb(209 213 219 / var(--tw-text-opacity, 1))}.text-gray-400{--tw-text-opacity: 1;color:rgb(156 163 175 / var(--tw-text-opacity, 1))}.text-gray-500{--tw-text-opacity: 1;color:rgb(107 114 128 / var(--tw-text-opacity, 1))}.text-gray-600{--tw-text-opacity: 1;color:rgb(75 85 99 / var(--tw-text-opacity, 1))}.text-gray-700{--tw-text-opacity: 1;color:rgb(55 65 81 / var(--tw-text-opacity, 1))}.text-gray-800{--tw-text-opacity: 1;color:rgb(31 41 55 / var(--tw-text-opacity, 1))}.text-gray-900{--tw-text-opacity: 1;color:rgb(17 24 39 / var(--tw-text-opacity, 1))}.text-gray-950{--tw-text-opacity: 1;color:rgb(3 7 18 / var(--tw-text-opacity, 1))}.text-green-500{--tw-text-opacity: 1;color:rgb(34 197 94 / var(--tw-text-opacity, 1))}.text-green-600{--tw-text-opacity: 1;color:rgb(22 163 74 / var(--tw-text-opacity, 1))}.text-green-700{--tw-text-opacity: 1;color:rgb(21 128 61 / var(--tw-text-opacity, 1))}.text-green-800{--tw-text-opacity: 1;color:rgb(22 101 52 / var(--tw-text-opacity, 1))}.text-red-600{--tw-text-opacity: 1;color:rgb(220 38 38 / var(--tw-text-opacity, 1))}.text-red-700{--tw-text-opacity: 1;color:rgb(185 28 28 / var(--tw-text-opacity, 1))}.text-white{--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity, 1))}.text-white\/70{color:#ffffffb3}.underline{text-decoration-line:underline}.opacity-0{opacity:0}.shadow-2xl{--tw-shadow: 0 25px 50px -12px rgb(0 0 0 / .25);--tw-shadow-colored: 0 25px 50px -12px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-lg{--tw-shadow: 0 10px 15px -3px rgb(0 0 0 / .1), 0 4px 6px -4px rgb(0 0 0 / .1);--tw-shadow-colored: 0 10px 15px -3px var(--tw-shadow-color), 0 4px 6px -4px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-sm{--tw-shadow: 0 1px 2px 0 rgb(0 0 0 / .05);--tw-shadow-colored: 0 1px 2px 0 var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-xl{--tw-shadow: 0 20px 25px -5px rgb(0 0 0 / .1), 0 8px 10px -6px rgb(0 0 0 / .1);--tw-shadow-colored: 0 20px 25px -5px var(--tw-shadow-color), 0 8px 10px -6px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.outline-none{outline:2px solid transparent;outline-offset:2px}.filter{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.backdrop-blur-sm{--tw-backdrop-blur: blur(4px);-webkit-backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia);backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia)}.transition{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-all{transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-colors{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-opacity{transition-property:opacity;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-transform{transition-property:transform;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.duration-500{transition-duration:.5s}:root{--theme-color: #111827;--theme-hover: #374151}body{margin:0;background:#fff;color:#1f2937;font-family:Inter,ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,sans-serif}[data-theme=dark] body,[data-theme=dark]{background:#111827;color:#f3f4f6}.theme-bg{background:var(--theme-color);color:#fff}.theme-bg:hover{background:var(--theme-hover)}.theme-bg:disabled{background:#9ca3af}.theme-border{border-color:var(--theme-color)}.theme-text{color:var(--theme-color)}.theme-progress{background:var(--theme-color)}.placeholder\:text-gray-300::-moz-placeholder{--tw-text-opacity: 1;color:rgb(209 213 219 / var(--tw-text-opacity, 1))}.placeholder\:text-gray-300::placeholder{--tw-text-opacity: 1;color:rgb(209 213 219 / var(--tw-text-opacity, 1))}.placeholder\:text-gray-400::-moz-placeholder{--tw-text-opacity: 1;color:rgb(156 163 175 / var(--tw-text-opacity, 1))}.placeholder\:text-gray-400::placeholder{--tw-text-opacity: 1;color:rgb(156 163 175 / var(--tw-text-opacity, 1))}.last\:mb-0:last-child{margin-bottom:0}.focus-within\:border-gray-400:focus-within{--tw-border-opacity: 1;border-color:rgb(156 163 175 / var(--tw-border-opacity, 1))}.hover\:border-gray-200:hover{--tw-border-opacity: 1;border-color:rgb(229 231 235 / var(--tw-border-opacity, 1))}.hover\:border-gray-300:hover{--tw-border-opacity: 1;border-color:rgb(209 213 219 / var(--tw-border-opacity, 1))}.hover\:border-gray-500:hover{--tw-border-opacity: 1;border-color:rgb(107 114 128 / var(--tw-border-opacity, 1))}.hover\:border-gray-700:hover{--tw-border-opacity: 1;border-color:rgb(55 65 81 / var(--tw-border-opacity, 1))}.hover\:border-gray-900:hover{--tw-border-opacity: 1;border-color:rgb(17 24 39 / var(--tw-border-opacity, 1))}.hover\:bg-gray-100:hover{--tw-bg-opacity: 1;background-color:rgb(243 244 246 / var(--tw-bg-opacity, 1))}.hover\:bg-gray-50:hover{--tw-bg-opacity: 1;background-color:rgb(249 250 251 / var(--tw-bg-opacity, 1))}.hover\:bg-gray-700:hover{--tw-bg-opacity: 1;background-color:rgb(55 65 81 / var(--tw-bg-opacity, 1))}.hover\:bg-white:hover{--tw-bg-opacity: 1;background-color:rgb(255 255 255 / var(--tw-bg-opacity, 1))}.hover\:bg-white\/20:hover{background-color:#fff3}.hover\:text-gray-500:hover{--tw-text-opacity: 1;color:rgb(107 114 128 / var(--tw-text-opacity, 1))}.hover\:text-gray-600:hover{--tw-text-opacity: 1;color:rgb(75 85 99 / var(--tw-text-opacity, 1))}.hover\:text-gray-700:hover{--tw-text-opacity: 1;color:rgb(55 65 81 / var(--tw-text-opacity, 1))}.hover\:text-gray-800:hover{--tw-text-opacity: 1;color:rgb(31 41 55 / var(--tw-text-opacity, 1))}.hover\:text-gray-900:hover{--tw-text-opacity: 1;color:rgb(17 24 39 / var(--tw-text-opacity, 1))}.hover\:text-red-400:hover{--tw-text-opacity: 1;color:rgb(248 113 113 / var(--tw-text-opacity, 1))}.hover\:text-white:hover{--tw-text-opacity: 1;color:rgb(255 255 255 / var(--tw-text-opacity, 1))}.hover\:opacity-90:hover{opacity:.9}.hover\:opacity-95:hover{opacity:.95}.hover\:shadow-sm:hover{--tw-shadow: 0 1px 2px 0 rgb(0 0 0 / .05);--tw-shadow-colored: 0 1px 2px 0 var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.focus\:border-gray-300:focus{--tw-border-opacity: 1;border-color:rgb(209 213 219 / var(--tw-border-opacity, 1))}.focus\:border-gray-400:focus{--tw-border-opacity: 1;border-color:rgb(156 163 175 / var(--tw-border-opacity, 1))}.focus\:border-gray-900:focus{--tw-border-opacity: 1;border-color:rgb(17 24 39 / var(--tw-border-opacity, 1))}.focus\:bg-white:focus{--tw-bg-opacity: 1;background-color:rgb(255 255 255 / var(--tw-bg-opacity, 1))}.disabled\:cursor-not-allowed:disabled{cursor:not-allowed}.disabled\:bg-gray-400:disabled{--tw-bg-opacity: 1;background-color:rgb(156 163 175 / var(--tw-bg-opacity, 1))}.disabled\:opacity-30:disabled{opacity:.3}.disabled\:opacity-40:disabled{opacity:.4}.disabled\:opacity-50:disabled{opacity:.5}.group:hover .group-hover\:opacity-100{opacity:1}@media (min-width: 640px){.sm\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.sm\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.sm\:grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}.sm\:flex-row{flex-direction:row}.sm\:items-end{align-items:flex-end}.sm\:items-center{align-items:center}.sm\:justify-between{justify-content:space-between}.sm\:text-4xl{font-size:2.25rem;line-height:2.5rem}}@media (min-width: 768px){.md\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}}@media (min-width: 1024px){.lg\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.lg\:grid-cols-\[minmax\(0\,1\.2fr\)_420px\]{grid-template-columns:minmax(0,1.2fr) 420px}}@media (min-width: 1280px){.xl\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}}@media (min-width: 1536px){.\32xl\:grid-cols-\[360px_minmax\(0\,1fr\)_340px\]{grid-template-columns:360px minmax(0,1fr) 340px}}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
|
+
<title>memi</title>
|
|
7
|
+
<script type="module" crossorigin src="/assets/index-CmQIBT8Z.js"></script>
|
|
8
|
+
<link rel="stylesheet" crossorigin href="/assets/index-Djh6rbJ-.css">
|
|
9
|
+
</head>
|
|
10
|
+
<body>
|
|
11
|
+
<div id="root"></div>
|
|
12
|
+
</body>
|
|
13
|
+
</html>
|
|
@@ -0,0 +1,359 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="zh">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1">
|
|
5
|
+
<title>Memi Agent</title>
|
|
6
|
+
<style>
|
|
7
|
+
:root{--bg:#f5f5f5;--panel:#fff;--border:#e5e7eb;--text:#1a1a1a;--dim:#9ca3af;--accent:#111827;--green:#059669;--red:#dc2626;--yellow:#d97706}
|
|
8
|
+
*{margin:0;padding:0;box-sizing:border-box}
|
|
9
|
+
body{font-family:system-ui,sans-serif;background:var(--bg);color:var(--text);height:100vh;display:flex}
|
|
10
|
+
/* sidebar */
|
|
11
|
+
.sidebar{width:260px;background:var(--panel);border-right:1px solid var(--border);display:flex;flex-direction:column;overflow:hidden;transition:width .2s;flex-shrink:0}
|
|
12
|
+
.sidebar.closed{width:0;border:none;overflow:hidden}
|
|
13
|
+
.sidebar-closed .sidebar{width:0;border:none}
|
|
14
|
+
body.clean .sidebar,body.clean .monitor{display:none}
|
|
15
|
+
body.clean #cleanBtn{border-color:var(--accent);color:var(--accent)}
|
|
16
|
+
.sidebar .head{padding:12px 16px;border-bottom:1px solid var(--border);display:flex;align-items:center;gap:8px}
|
|
17
|
+
.sidebar .head h1{font-size:14px;font-weight:600;flex:1}
|
|
18
|
+
.sidebar .head button{background:none;border:none;cursor:pointer;color:var(--dim);font-size:18px}
|
|
19
|
+
.sidebar .new-btn{margin:12px}
|
|
20
|
+
.sidebar .new-btn button{width:100%;padding:8px;border:1px solid var(--border);border-radius:8px;background:var(--panel);color:var(--text);font-size:13px;cursor:pointer;display:flex;align-items:center;gap:6px}
|
|
21
|
+
.sidebar .new-btn button:hover{background:var(--bg)}
|
|
22
|
+
.sidebar .sessions{flex:1;overflow-y:auto;padding:0 12px}
|
|
23
|
+
.sidebar .sessions .item{padding:8px 12px;border-radius:8px;cursor:pointer;font-size:13px;color:var(--text);margin-bottom:2px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
|
|
24
|
+
.sidebar .sessions .item:hover,.sidebar .sessions .item.active{background:var(--bg)}
|
|
25
|
+
.sidebar .sessions .item .del{float:right;color:var(--dim);font-size:10px;line-height:20px;display:none}
|
|
26
|
+
.sidebar .sessions .item:hover .del{display:inline}
|
|
27
|
+
.sidebar .footer{padding:12px 16px;border-top:1px solid var(--border);font-size:11px;color:var(--dim)}
|
|
28
|
+
/* main */
|
|
29
|
+
.main{flex:1;display:flex;flex-direction:column;overflow:hidden;min-width:0}
|
|
30
|
+
.header{background:var(--panel);padding:8px 16px;border-bottom:1px solid var(--border);display:flex;align-items:center;gap:8px;font-size:13px}
|
|
31
|
+
.header .toggle{background:none;border:none;cursor:pointer;color:var(--dim);font-size:18px;padding:4px}
|
|
32
|
+
.header .dot{width:6px;height:6px;border-radius:50%;background:var(--green);flex-shrink:0}
|
|
33
|
+
.header .dot.off{background:var(--red)}
|
|
34
|
+
.header select{margin-left:8px;border:1px solid var(--border);border-radius:4px;padding:2px 6px;font-size:11px;color:var(--text);background:var(--panel)}
|
|
35
|
+
.msgs{flex:1;overflow-y:auto;padding:16px 20px;display:flex;flex-direction:column;gap:12px}
|
|
36
|
+
.msg{max-width:80%;font-size:13px;line-height:1.6;animation:fade .2s}
|
|
37
|
+
.msg.user{align-self:flex-end;background:var(--accent);color:#fff;padding:8px 14px;border-radius:14px 4px 14px 14px}
|
|
38
|
+
.msg.agent{align-self:flex-start;background:var(--panel);border:1px solid var(--border);padding:10px 14px;border-radius:4px 14px 14px 14px}
|
|
39
|
+
.msg.agent pre{background:var(--bg);padding:8px;border-radius:6px;overflow-x:auto;font-size:11px;margin:6px 0}
|
|
40
|
+
.msg.agent table{border-collapse:collapse;margin:6px 0;font-size:12px}
|
|
41
|
+
.msg.agent td,.msg.agent th{border:1px solid var(--border);padding:4px 8px}
|
|
42
|
+
.msg.agent th{background:var(--bg);font-weight:600}
|
|
43
|
+
.msg.agent code{background:var(--bg);padding:1px 4px;border-radius:3px;font-size:11px}
|
|
44
|
+
.msg.tool,.msg.tool *{align-self:flex-start;background:#dbeafe;color:#1e40af;padding:6px 10px;border-radius:6px;font-size:11px;cursor:pointer;user-select:none;border:1px solid #93c5fd;margin:0;max-width:100%}
|
|
45
|
+
.msg.tool b{background:transparent;color:#1e40af;padding:0;border:none}
|
|
46
|
+
.msg.tool .res{display:none;margin-top:4px;padding:6px 8px;background:#fff;border-radius:4px;color:var(--text);font-size:11px;max-height:120px;overflow-y:auto;white-space:pre-wrap;word-break:break-all}
|
|
47
|
+
.msg.tool.open .res{display:block}
|
|
48
|
+
.msg.think{align-self:flex-start;color:var(--dim);font-size:11px;font-style:italic;padding:4px 8px;border-left:3px solid var(--dim);margin-left:8px}
|
|
49
|
+
.input-area{padding:12px 20px;border-top:1px solid var(--border);display:flex;gap:8px}
|
|
50
|
+
.input-area textarea{flex:1;border:1px solid var(--border);border-radius:10px;padding:10px 14px;font-size:13px;resize:none;outline:none;min-height:42px;max-height:120px;font-family:inherit;background:var(--panel)}
|
|
51
|
+
.input-area textarea:focus{border-color:var(--accent)}
|
|
52
|
+
.input-area button{background:var(--accent);border:none;border-radius:10px;padding:10px 18px;color:#fff;font-weight:600;cursor:pointer;font-size:13px}
|
|
53
|
+
.input-area button:disabled{opacity:.5}
|
|
54
|
+
/* monitor */
|
|
55
|
+
.monitor{width:240px;background:var(--panel);border-left:1px solid var(--border);overflow-y:auto;padding:12px;font-size:11px;flex-shrink:0}
|
|
56
|
+
.monitor h3{font-size:10px;text-transform:uppercase;letter-spacing:1px;color:var(--dim);margin:12px 0 6px}
|
|
57
|
+
.monitor .row{display:flex;justify-content:space-between;padding:4px 0}
|
|
58
|
+
.monitor .v{font-family:monospace;font-size:11px}
|
|
59
|
+
.tlog{padding:2px 0;border-bottom:1px solid var(--border);font-size:10px}
|
|
60
|
+
.tlog .tn{color:#1e40af;font-weight:600}
|
|
61
|
+
.tlog .tr{color:var(--dim);margin-top:1px}
|
|
62
|
+
@keyframes fade{from{opacity:0;transform:translateY(4px)}to{opacity:1;transform:translateY(0)}}
|
|
63
|
+
::-webkit-scrollbar{width:3px}::-webkit-scrollbar-thumb{background:var(--border);border-radius:2px}
|
|
64
|
+
</style>
|
|
65
|
+
</head>
|
|
66
|
+
<body>
|
|
67
|
+
<div class="sidebar" id="sidebar">
|
|
68
|
+
<div class="head">
|
|
69
|
+
<h1>Memi</h1>
|
|
70
|
+
<button onclick="toggleSidebar()" title="关闭侧边栏">«</button>
|
|
71
|
+
</div>
|
|
72
|
+
<div class="new-btn">
|
|
73
|
+
<button onclick="newChat()">+ 新对话</button>
|
|
74
|
+
</div>
|
|
75
|
+
<div class="sessions" id="sessions"></div>
|
|
76
|
+
<div class="footer"><span id="model">—</span></div>
|
|
77
|
+
</div>
|
|
78
|
+
|
|
79
|
+
<div class="main">
|
|
80
|
+
<div class="header">
|
|
81
|
+
<button class="toggle" onclick="toggleSidebar()" title="侧边栏">☰</button>
|
|
82
|
+
<span class="dot" id="dot"></span>
|
|
83
|
+
<span id="st" style="font-size:12px;color:var(--dim)">就绪</span>
|
|
84
|
+
<button onclick="toggleClean()" id="cleanBtn" style="margin-left:4px;background:none;border:1px solid var(--border);border-radius:4px;padding:2px 6px;cursor:pointer" title="纯净模式">
|
|
85
|
+
<svg id="cleanIconExpand" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="15 3 21 3 21 9"/><polyline points="9 21 3 21 3 15"/><line x1="21" y1="3" x2="14" y2="10"/><line x1="3" y1="21" x2="10" y2="14"/></svg>
|
|
86
|
+
<svg id="cleanIconCollapse" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" style="display:none"><polyline points="4 8 10 8 10 2"/><polyline points="20 16 14 16 14 22"/><line x1="10" y1="8" x2="4" y2="14"/><line x1="14" y1="16" x2="20" y2="10"/></svg>
|
|
87
|
+
</button>
|
|
88
|
+
<select id="thinkLevel" onchange="saveThink()">
|
|
89
|
+
<option value="high">🧠 高</option><option value="medium">中</option><option value="low">低</option><option value="off">关</option>
|
|
90
|
+
</select>
|
|
91
|
+
<span id="msgCount" style="margin-left:auto;font-size:11px;color:var(--dim)">0</span>
|
|
92
|
+
</div>
|
|
93
|
+
<div class="msgs" id="msgs"></div>
|
|
94
|
+
<div class="input-area">
|
|
95
|
+
<textarea id="inp" placeholder="发送消息..." rows="1"></textarea>
|
|
96
|
+
<button id="sendBtn" onclick="send()">发送</button>
|
|
97
|
+
</div>
|
|
98
|
+
</div>
|
|
99
|
+
|
|
100
|
+
<div class="monitor">
|
|
101
|
+
<h3>Monitor</h3>
|
|
102
|
+
<div class="row"><span>迭代</span><span class="v" id="mIter">0</span></div>
|
|
103
|
+
<div class="row"><span>工具</span><span class="v" id="mTools">0</span></div>
|
|
104
|
+
<div class="row"><span>耗时</span><span class="v" id="mTime">0s</span></div>
|
|
105
|
+
<div class="row"><span>Tokens</span><span class="v" id="mTokens">0</span></div>
|
|
106
|
+
<div class="row"><span>花费</span><span class="v" id="mCost">$0</span></div>
|
|
107
|
+
<div class="row"><span>余额</span><span class="v" id="mBalance">$10.00</span></div>
|
|
108
|
+
<h3>Tools</h3>
|
|
109
|
+
<div id="toolLogs"><div class="row"><span style="color:var(--dim)">—</span></div></div>
|
|
110
|
+
</div>
|
|
111
|
+
|
|
112
|
+
<script>
|
|
113
|
+
const API="/api/v1/chat/completions";
|
|
114
|
+
let messages=[],currentSession="default",lastAgentEl=null;
|
|
115
|
+
let stats={totalTokens:0,totalCost:0,totalTools:0,totalMsgs:0};
|
|
116
|
+
|
|
117
|
+
// load stats from localStorage
|
|
118
|
+
try{stats=JSON.parse(localStorage.getItem("memi-stats")||"{}")}catch{}
|
|
119
|
+
function saveStats(){localStorage.setItem("memi-stats",JSON.stringify(stats))}
|
|
120
|
+
|
|
121
|
+
function toggleSidebar(){document.getElementById("sidebar").classList.toggle("closed")}
|
|
122
|
+
function toggleClean(){
|
|
123
|
+
const on = document.body.classList.toggle("clean");
|
|
124
|
+
localStorage.setItem("memi-clean", on);
|
|
125
|
+
document.getElementById("cleanIconExpand").style.display = on ? "none" : "inline";
|
|
126
|
+
document.getElementById("cleanIconCollapse").style.display = on ? "inline" : "none";
|
|
127
|
+
}
|
|
128
|
+
if(localStorage.getItem("memi-clean")==="true"){
|
|
129
|
+
document.body.classList.add("clean");
|
|
130
|
+
setTimeout(()=>{
|
|
131
|
+
document.getElementById("cleanIconExpand").style.display="none";
|
|
132
|
+
document.getElementById("cleanIconCollapse").style.display="inline";
|
|
133
|
+
},0);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// sessions
|
|
137
|
+
async function loadSessions(){
|
|
138
|
+
try{const r=await fetch("/api/sessions");const d=await r.json();renderSessions(d.sessions||[])}catch{}
|
|
139
|
+
}
|
|
140
|
+
function renderSessions(list){
|
|
141
|
+
const el=document.getElementById("sessions");
|
|
142
|
+
el.innerHTML=list.map(s=>`<div class="item${s===currentSession?' active':''}" onclick="switchSession('${s}')">${s}<span class="del" onclick="event.stopPropagation();deleteSession('${s}')">✕</span></div>`).join("");
|
|
143
|
+
}
|
|
144
|
+
async function switchSession(name){
|
|
145
|
+
saveCurrentSession();
|
|
146
|
+
currentSession=name;localStorage.setItem("memi-last-session",name);
|
|
147
|
+
try{const r=await fetch("/api/sessions/"+name);const d=await r.json();messages=(d.messages||[]).filter(m=>m.role)}catch{messages=[]}
|
|
148
|
+
fullRender();loadSessions();updateMonitor();
|
|
149
|
+
// 重建工具日志
|
|
150
|
+
rebuildToolLogs();
|
|
151
|
+
}
|
|
152
|
+
function rebuildToolLogs(){
|
|
153
|
+
const el=document.getElementById("toolLogs");
|
|
154
|
+
const tools=messages.filter(m=>m.type==="tool" || (m.content&&/^[🔍📂📖✏️🕐📍🧮📦🗑📁⚡🔧]/.test(m.content)));
|
|
155
|
+
if(tools.length===0){el.innerHTML='<div class="row"><span style="color:var(--dim)">—</span></div>';return}
|
|
156
|
+
el.innerHTML=tools.map(m=>{
|
|
157
|
+
const icon=m.content||"";
|
|
158
|
+
const args=m.args||"";
|
|
159
|
+
const result=m.result||"";
|
|
160
|
+
return `<div class="tlog"><span class="tn">${icon}</span> <span class="tr">${args}</span>${result?`<div style="color:#666;margin-top:2px;font-size:10px">${escapeHtml(result).slice(0,100)}</div>`:""}</div>`;
|
|
161
|
+
}).join("");
|
|
162
|
+
}
|
|
163
|
+
async function deleteSession(name){
|
|
164
|
+
if(!confirm("删除会话 '"+name+"'?"))return;
|
|
165
|
+
try{await fetch("/api/sessions/"+name,{method:"DELETE"})}catch{}
|
|
166
|
+
if(currentSession===name){messages=[];currentSession="default";fullRender()}
|
|
167
|
+
loadSessions();
|
|
168
|
+
}
|
|
169
|
+
function newChat(){
|
|
170
|
+
saveCurrentSession();
|
|
171
|
+
currentSession="s"+Date.now().toString(36).slice(-4);localStorage.setItem("memi-last-session",currentSession);
|
|
172
|
+
messages=[];fullRender();
|
|
173
|
+
saveCurrentSession();loadSessions();
|
|
174
|
+
}
|
|
175
|
+
function saveCurrentSession(){
|
|
176
|
+
const clean=messages.map(m=>({role:m.role,content:m.content||"",type:m.type||"",args:m.args||"",result:m.result||""}));
|
|
177
|
+
if(clean.length===0)return;
|
|
178
|
+
fetch("/api/sessions/"+currentSession,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({messages:clean})}).catch(()=>{});
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// 定期保存(5秒间隔,避免过于频繁)
|
|
182
|
+
let _saveTimer = setInterval(()=>{if(messages.length>0)saveCurrentSession()},5000);
|
|
183
|
+
|
|
184
|
+
// render
|
|
185
|
+
function escapeHtml(t){return (t||"").replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">")}
|
|
186
|
+
function md(t){
|
|
187
|
+
let text=escapeHtml(t).replace(/```(\w*)\n([\s\S]*?)```/g,'<pre><code>$2</code></pre>').replace(/`([^`]+)`/g,'<code>$1</code>').replace(/\*\*(.+?)\*\*/g,'<b>$1</b>');
|
|
188
|
+
const lines=text.split("\n");let out=[],inT=false;
|
|
189
|
+
for(const l of lines){
|
|
190
|
+
if(l.trim().startsWith("|")&&l.trim().endsWith("|")){
|
|
191
|
+
if(!inT){out.push('<table>');inT=true}
|
|
192
|
+
const cells=l.split("|").slice(1,-1);const tag=l.match(/^\|[-:\s|]+\|$/)?'th':'td';
|
|
193
|
+
out.push(`<tr>${cells.map(c=>`<${tag}>${c.trim()}</${tag}>`).join('')}</tr>`);
|
|
194
|
+
}else{if(inT){out.push('</table>');inT=false}out.push(l+'<br>')}
|
|
195
|
+
}
|
|
196
|
+
if(inT)out.push('</table>');
|
|
197
|
+
return out.join('\n');
|
|
198
|
+
}
|
|
199
|
+
function fullRender(){
|
|
200
|
+
const el=document.getElementById("msgs");el.innerHTML="";lastAgentEl=null;
|
|
201
|
+
messages.forEach(m=>{
|
|
202
|
+
const isTool=m.type==="tool"||(m.content&&/^[🔍📂📖✏️🕐📍🧮📦🗑📁⚡🔧]/.test(m.content));
|
|
203
|
+
if(isTool){
|
|
204
|
+
const d=document.createElement("div");
|
|
205
|
+
d.setAttribute("style","align-self:flex-start;background:#dbeafe;color:#1e40af;padding:6px 10px;border-radius:6px;font-size:11px;cursor:pointer;border:1px solid #93c5fd;margin-bottom:4px;max-width:80%");
|
|
206
|
+
const res=m.result?`<div style="margin-top:4px;padding:6px 8px;background:#fff;border-radius:4px;color:#333;font-size:11px;max-height:120px;overflow-y:auto;display:none">${escapeHtml(String(m.result||""))}</div>`:"";
|
|
207
|
+
d.innerHTML=`<b style="background:transparent;color:#1e40af">${m.content||""}</b>${res}`;
|
|
208
|
+
d.onclick=function(){var r=this.querySelector('div');if(r)r.style.display=r.style.display==='none'?'block':'none';};
|
|
209
|
+
el.appendChild(d);
|
|
210
|
+
}
|
|
211
|
+
else{const d=document.createElement("div");d.className="msg "+(m.role==="user"?"user":"agent");d.innerHTML=md(m.content||"");el.appendChild(d)}
|
|
212
|
+
});
|
|
213
|
+
el.scrollTop=el.scrollHeight;document.getElementById("msgCount").textContent=messages.length;
|
|
214
|
+
}
|
|
215
|
+
function renderNew(){
|
|
216
|
+
const el=document.getElementById("msgs");
|
|
217
|
+
for(let i=el.children.length;i<messages.length;i++){
|
|
218
|
+
const m=messages[i];
|
|
219
|
+
const isTool2=m.type==="tool"||(m.content&&/^[🔍📂📖✏️🕐📍🧮📦🗑📁⚡🔧]/.test(m.content));
|
|
220
|
+
if(isTool2){
|
|
221
|
+
const d=document.createElement("div");
|
|
222
|
+
d.setAttribute("style","align-self:flex-start;background:#dbeafe;color:#1e40af;padding:6px 10px;border-radius:6px;font-size:11px;cursor:pointer;border:1px solid #93c5fd;margin-bottom:4px;max-width:80%");
|
|
223
|
+
const res=m.result?`<div style="margin-top:4px;padding:6px 8px;background:#fff;border-radius:4px;color:#333;font-size:11px;max-height:120px;overflow-y:auto;display:none">${escapeHtml(String(m.result||""))}</div>`:"";
|
|
224
|
+
d.innerHTML=`<b style="background:transparent;color:#1e40af">${m.content||""}</b>${res}`;
|
|
225
|
+
d.onclick=function(){var r=this.querySelector('div');if(r)r.style.display=r.style.display==='none'?'block':'none';};
|
|
226
|
+
el.appendChild(d);lastAgentEl=null;
|
|
227
|
+
}
|
|
228
|
+
else{const d=document.createElement("div");d.className="msg "+(m.role==="user"?"user":"agent");d.innerHTML=md(m.content||"");el.appendChild(d);lastAgentEl=m.role==="assistant"?d:null}
|
|
229
|
+
}
|
|
230
|
+
if(lastAgentEl&&messages.length>0){const last=messages[messages.length-1];if(last.role==="assistant")lastAgentEl.innerHTML=md(last.content||"")}
|
|
231
|
+
el.scrollTop=el.scrollHeight;document.getElementById("msgCount").textContent=messages.length;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
// monitor
|
|
235
|
+
async function fetchBalance(){
|
|
236
|
+
try{const r=await fetch("/api/balance");const d=await r.json();document.getElementById("mBalance").textContent=(d.balance!=null?d.balance:"—")}catch{}
|
|
237
|
+
}
|
|
238
|
+
function updateMonitor(){
|
|
239
|
+
document.getElementById("mIter").textContent="0";document.getElementById("mTools").textContent=stats.totalTools||0;
|
|
240
|
+
document.getElementById("mTokens").textContent=stats.totalTokens||0;
|
|
241
|
+
const cost=stats.totalCost||0;document.getElementById("mCost").textContent="$"+cost.toFixed(5);
|
|
242
|
+
}
|
|
243
|
+
document.getElementById("mBalance").onclick=fetchBalance;
|
|
244
|
+
document.getElementById("mBalance").style.cursor="pointer";
|
|
245
|
+
document.getElementById("mBalance").title="点击刷新余额";
|
|
246
|
+
fetchBalance();
|
|
247
|
+
|
|
248
|
+
// send
|
|
249
|
+
async function send(){
|
|
250
|
+
const inp=document.getElementById("inp");const text=inp.value.trim();if(!text)return;
|
|
251
|
+
inp.value="";inp.style.height="42px";document.getElementById("sendBtn").disabled=true;
|
|
252
|
+
messages.push({role:"user",content:text});renderNew();
|
|
253
|
+
|
|
254
|
+
const start=Date.now();let toolCount=0,full="",msgDiv=null;
|
|
255
|
+
document.getElementById("st").textContent="思考中...";document.getElementById("dot").className="dot";
|
|
256
|
+
rebuildToolLogs(); // 先重建,确保只显示当前会话的工具
|
|
257
|
+
try{
|
|
258
|
+
const r=await fetch(API,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({model:"memi-agent",messages,stream:true,thinking:getThink(),systemPrompt:""})});
|
|
259
|
+
const reader=r.body.getReader();const dec=new TextDecoder();let buf="";
|
|
260
|
+
while(true){
|
|
261
|
+
const{done,value}=await reader.read();if(done)break;
|
|
262
|
+
buf+=dec.decode(value,{stream:true});const lines=buf.split("\n");buf=lines.pop()||"";
|
|
263
|
+
for(const line of lines){
|
|
264
|
+
if(!line.startsWith("data: "))continue;if(line.slice(6).trim()==="[DONE]")continue;
|
|
265
|
+
try{const d=JSON.parse(line.slice(6));
|
|
266
|
+
// 工具调用检测
|
|
267
|
+
const isTool = d.type==="tool_call" || d.tool;
|
|
268
|
+
if(isTool){
|
|
269
|
+
const tname = d.tool || d.type;
|
|
270
|
+
toolCount++;document.getElementById("mTools").textContent=++stats.totalTools;saveStats();updateMonitor();
|
|
271
|
+
const icons={web_search:"🔍",list_files:"📂",read_file:"📖",write_file:"✏️",get_time:"🕐",get_location:"📍",calculate:"🧮",move_file:"📦",delete_file:"🗑",create_dir:"📁",run_command:"⚡",find_files:"🔎",search_in_files:"📋",http_request:"🌐",system_info:"🖥",clipboard_read:"📋",clipboard_write:"📝",open_url:"🔗",download_file:"⬇",zip_files:"📦",unzip:"📂",process_list:"📊",notify:"🔔",encode_decode:"🔣",git_status:"📋",git_log:"📜",random:"🎲",hash_text:"🔐",uuid:"🆔",count_text:"🔢",diff_files:"↔",disk_usage:"💾",network_info:"🌐",ping_host:"📡",dns_lookup:"🔍",sort_file:"📑",get_env:"🔧",take_screenshot:"📸",get_weather:"🌤",timer:"⏱",qr_generate:"📱",set_reminder:"📝"};
|
|
272
|
+
const icon=icons[tname]||"🔧";document.getElementById("st").textContent=icon+" "+tname;
|
|
273
|
+
let args=String(d.args||"");try{const a=typeof d.args==="string"?JSON.parse(d.args):d.args;args=Object.values(a||{}).join(", ")}catch{}
|
|
274
|
+
document.getElementById("toolLogs").innerHTML+=`<div class="tlog"><span class="tn">${icon} ${tname}</span><span class="tr">${args.slice(0,60)}</span></div>`;
|
|
275
|
+
// 内联蓝色气泡
|
|
276
|
+
const td=document.createElement("div");
|
|
277
|
+
td.setAttribute("style","align-self:flex-start;background:#dbeafe;color:#1e40af;padding:6px 10px;border-radius:6px;font-size:11px;cursor:pointer;border:1px solid #93c5fd;margin-bottom:4px;max-width:80%");
|
|
278
|
+
const res = d.result ? `<div style="margin-top:4px;padding:6px 8px;background:#fff;border-radius:4px;color:#333;font-size:11px;max-height:120px;overflow-y:auto;display:none">${escapeHtml(String(d.result||"").slice(0,500))}</div>` : "";
|
|
279
|
+
td.innerHTML=`<b style="background:transparent;color:#1e40af">${icon} ${tname}</b>${res}`;
|
|
280
|
+
td.onclick=function(){var r=this.querySelector('div');if(r)r.style.display=r.style.display==='none'?'block':'none';};
|
|
281
|
+
document.getElementById("msgs").appendChild(td);
|
|
282
|
+
document.getElementById("msgs").scrollTop=document.getElementById("msgs").scrollHeight;
|
|
283
|
+
messages.push({role:"assistant",type:"tool",content:icon+" "+tname,args:args.slice(0,60),result:String(d.result||"").slice(0,500)});
|
|
284
|
+
lastAgentEl=null;continue;
|
|
285
|
+
}
|
|
286
|
+
const t=d.choices?.[0]?.delta?.content||"";if(t){full+=t;
|
|
287
|
+
if(!msgDiv){messages.push({role:"assistant",content:""});msgDiv=messages[messages.length-1];document.getElementById("st").textContent="回复中"}
|
|
288
|
+
msgDiv.content=full;
|
|
289
|
+
}
|
|
290
|
+
}catch{}
|
|
291
|
+
}renderNew();
|
|
292
|
+
}
|
|
293
|
+
}catch(e){messages.push({role:"assistant",content:"连接失败: "+e.message});renderNew()}
|
|
294
|
+
|
|
295
|
+
const elapsed=((Date.now()-start)/1000).toFixed(1);document.getElementById("mTime").textContent=elapsed+"s";
|
|
296
|
+
const tks=Math.round(text.length/3.5+full.length/3.5);stats.totalTokens+=tks;stats.totalCost+=tks*0.000002;saveStats();
|
|
297
|
+
updateMonitor();document.getElementById("st").textContent="就绪";document.getElementById("dot").className="dot";
|
|
298
|
+
document.getElementById("sendBtn").disabled=false;saveCurrentSession();
|
|
299
|
+
rebuildToolLogs();
|
|
300
|
+
// 首次对话自动命名
|
|
301
|
+
if (messages.length >= 2 && currentSession.startsWith("s")) autoName();
|
|
302
|
+
loadSessions();
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
async function autoName(){
|
|
306
|
+
const userMsgs=messages.filter(m=>m.role==="user").map(m=>m.content).join("; ").slice(0,200);
|
|
307
|
+
let name="";
|
|
308
|
+
try{
|
|
309
|
+
const r=await fetch(API,{method:"POST",headers:{"Content-Type":"application/json"},
|
|
310
|
+
body:JSON.stringify({model:"memi-agent",thinking:"off",messages:[
|
|
311
|
+
{role:"user",content:"给这段对话起一个简短名称(3-6个汉字),直接描述对话主题,不要修饰、不要诗意、不要标点。\n\n对话:\n"+userMsgs}
|
|
312
|
+
],max_tokens:30,temperature:0.3})
|
|
313
|
+
});
|
|
314
|
+
const d=await r.json();name=(d.choices?.[0]?.message?.content||"").replace(/["\n\r]/g,"").trim();
|
|
315
|
+
}catch{}
|
|
316
|
+
// 过滤垃圾名称
|
|
317
|
+
if(!name||name.length<1||name.length>20||!/[\u4e00-\u9fff]/.test(name)){
|
|
318
|
+
name=userMsgs.replace(/[,。!?,\.!\?]/g," ").split(" ").filter(w=>w.length>1).slice(0,3).join("")||userMsgs.slice(0,10);
|
|
319
|
+
}
|
|
320
|
+
if(name&&name!==currentSession){
|
|
321
|
+
const old=currentSession;
|
|
322
|
+
currentSession=name;
|
|
323
|
+
try{await fetch("/api/sessions/"+old,{method:"DELETE"})}catch{}
|
|
324
|
+
const clean=messages.map(m=>({role:m.role,content:m.content||"",type:m.type||"",args:m.args||"",result:m.result||""}));
|
|
325
|
+
await fetch("/api/sessions/"+name,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({messages:clean})});
|
|
326
|
+
loadSessions();
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
// think
|
|
331
|
+
function saveThink(){localStorage.setItem("memi-think",document.getElementById("thinkLevel").value)}
|
|
332
|
+
let dashModel="";
|
|
333
|
+
async function getThink(){
|
|
334
|
+
const v=localStorage.getItem("memi-think")||"high";const sel=document.getElementById("thinkLevel");sel.value=v;
|
|
335
|
+
try{const r=await fetch("/api/config");const c=await r.json();dashModel=(c.api1&&c.api1.model)||"";document.getElementById("model").textContent=dashModel||"—"}catch{}
|
|
336
|
+
if(!/reasoner|r1|think|v4-pro|v4-flash/i.test(dashModel)){sel.disabled=true;sel.title="不支持";return"off"}
|
|
337
|
+
sel.disabled=false;sel.title="";return v;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
// input
|
|
341
|
+
const inp=document.getElementById("inp");
|
|
342
|
+
inp.addEventListener("input",function(){this.style.height="42px";this.style.height=Math.min(this.scrollHeight,120)+"px"});
|
|
343
|
+
inp.addEventListener("keydown",function(e){if(e.key==="Enter"&&!e.shiftKey){e.preventDefault();send()}});
|
|
344
|
+
document.addEventListener("keydown",function(e){if(e.ctrlKey&&e.key==="n"){e.preventDefault();newChat()}});
|
|
345
|
+
window.addEventListener("beforeunload",()=>{if(messages.length>0)saveCurrentSession()});
|
|
346
|
+
|
|
347
|
+
// init
|
|
348
|
+
(async()=>{
|
|
349
|
+
await getThink();
|
|
350
|
+
try{const r=await fetch("/health");document.getElementById("dot").className=r.ok?"dot":"dot off"}catch(e){document.getElementById("dot").className="dot off"}
|
|
351
|
+
// 加载上次会话或默认
|
|
352
|
+
const lastSession = localStorage.getItem("memi-last-session") || "default";
|
|
353
|
+
await switchSession(lastSession);
|
|
354
|
+
// 加载列表
|
|
355
|
+
try{const r=await fetch("/api/sessions");const d=await r.json();renderSessions(d.sessions||[])}catch{}
|
|
356
|
+
})();
|
|
357
|
+
</script>
|
|
358
|
+
</body>
|
|
359
|
+
</html>
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# memi-server
|
|
2
|
+
|
|
3
|
+
Memi 的 Express 后端服务。
|
|
4
|
+
|
|
5
|
+
## 功能
|
|
6
|
+
|
|
7
|
+
- 服务端口默认 `3001`
|
|
8
|
+
- 开启 CORS,仅允许 `http://localhost:5173`
|
|
9
|
+
- 支持 JSON 请求体解析
|
|
10
|
+
- 提供 `/health` 健康检查接口
|
|
11
|
+
- 提供图片和视频流水线占位接口
|
|
12
|
+
|
|
13
|
+
## 安装
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npm install
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## 启动
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
npm start
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## 接口
|
|
26
|
+
|
|
27
|
+
### GET /health
|
|
28
|
+
|
|
29
|
+
返回:
|
|
30
|
+
|
|
31
|
+
```json
|
|
32
|
+
{
|
|
33
|
+
"status": "ok",
|
|
34
|
+
"name": "memi"
|
|
35
|
+
}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### POST /api/pipeline/image
|
|
39
|
+
|
|
40
|
+
返回:
|
|
41
|
+
|
|
42
|
+
```json
|
|
43
|
+
{
|
|
44
|
+
"status": "image pipeline placeholder"
|
|
45
|
+
}
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### POST /api/pipeline/video
|
|
49
|
+
|
|
50
|
+
返回:
|
|
51
|
+
|
|
52
|
+
```json
|
|
53
|
+
{
|
|
54
|
+
"status": "video pipeline placeholder"
|
|
55
|
+
}
|
|
56
|
+
```
|