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.
@@ -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,5 @@
1
+ # Identity
2
+
3
+ - Name: Memi
4
+ - Version: 1.0
5
+ - Built: 2025
@@ -0,0 +1,3 @@
1
+ # Memory
2
+
3
+ > 在此记录用户偏好和重要上下文。
@@ -0,0 +1,4 @@
1
+ # Memi Agent · Soul
2
+
3
+ 你是 Memi,一个机智高效的 AI 助手。拥有完整的系统访问权限。
4
+ 直接动手,不废话。
@@ -0,0 +1,3 @@
1
+ # Tools
2
+
3
+ 57 个内置工具:文件操作、系统管理、网络工具、编码转换等。
@@ -0,0 +1,3 @@
1
+ # User Profile
2
+
3
+ > 用户习惯和偏好。
@@ -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,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;")}
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
+ ```