Compare commits
26 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| ebc82245a5 | |||
| d772f9a961 | |||
| 7c841a2bce | |||
| 6a6dfb4935 | |||
| 8b370def80 | |||
| d46464282c | |||
| bb4a239cb1 | |||
| e30f0d91fe | |||
| 9f34e858c7 | |||
| 94bbc13de0 | |||
| a2f01a8fcc | |||
| 30d172e826 | |||
| bb69b036b5 | |||
| b55c51e004 | |||
| 4492e75d04 | |||
| 4d949022f2 | |||
| 3ef034a9e4 | |||
| b90e3c0b76 | |||
| a8eeddde64 | |||
| 09a9e34382 | |||
| 66c4394b40 | |||
| 32575a65fc | |||
| 66901d7393 | |||
| a1eefc31bc | |||
| de471799d1 | |||
| 3951ad4705 |
@@ -44,5 +44,15 @@
|
||||
"vitest": "^4.1.0",
|
||||
"@biomejs/biome": "^1.7.0",
|
||||
"@types/node": "^20.0.0"
|
||||
},
|
||||
"pnpm": {
|
||||
"overrides": {
|
||||
"jws@4.0.0": "4.0.1",
|
||||
"langsmith@<0.6.0": "^0.6.0",
|
||||
"tar-fs@>=2.0.0 <2.1.4": "^2.1.4",
|
||||
"picomatch@<2.3.2": "^2.3.2",
|
||||
"postcss@<8.5.10": ">=8.5.10",
|
||||
"esbuild": ">=0.28.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Generated
+115
-399
@@ -10,6 +10,7 @@ overrides:
|
||||
tar-fs@>=2.0.0 <2.1.4: ^2.1.4
|
||||
picomatch@<2.3.2: ^2.3.2
|
||||
postcss@<8.5.10: '>=8.5.10'
|
||||
esbuild: '>=0.28.1'
|
||||
|
||||
importers:
|
||||
|
||||
@@ -77,28 +78,24 @@ packages:
|
||||
engines: {node: '>=14.21.3'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@biomejs/cli-linux-arm64@1.9.4':
|
||||
resolution: {integrity: sha512-fJIW0+LYujdjUgJJuwesP4EjIBl/N/TcOX3IvIHJQNsAqvV2CHIogsmA94BPG6jZATS4Hi+xv4SkBBQSt1N4/g==}
|
||||
engines: {node: '>=14.21.3'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@biomejs/cli-linux-x64-musl@1.9.4':
|
||||
resolution: {integrity: sha512-gEhi/jSBhZ2m6wjV530Yy8+fNqG8PAinM3oV7CyO+6c3CEh16Eizm21uHVsyVBEB6RIM8JHIl6AGYCv6Q6Q9Tg==}
|
||||
engines: {node: '>=14.21.3'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@biomejs/cli-linux-x64@1.9.4':
|
||||
resolution: {integrity: sha512-lRCJv/Vi3Vlwmbd6K+oQ0KhLHMAysN8lXoCI7XeHlxaajk06u7G+UsFSO01NAs5iYuWKmVZjmiOzJ0OJmGsMwg==}
|
||||
engines: {node: '>=14.21.3'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@biomejs/cli-win32-arm64@1.9.4':
|
||||
resolution: {integrity: sha512-tlbhLk+WXZmgwoIKwHIHEBZUwxml7bRJgk0X2sPyNR3S93cdRq6XulAZRQJ17FYGGzWne0fgrXBKpl7l4M87Hg==}
|
||||
@@ -116,314 +113,158 @@ packages:
|
||||
resolution: {integrity: sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==}
|
||||
engines: {node: '>=0.1.90'}
|
||||
|
||||
'@esbuild/aix-ppc64@0.25.12':
|
||||
resolution: {integrity: sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==}
|
||||
'@esbuild/aix-ppc64@0.28.1':
|
||||
resolution: {integrity: sha512-Svl7tq8k/08+p6CXPpRjQ1fKX+1odH/BQbb48fV6fj3CWHhsoIOoY87w1oHXm0qEpkIK3ZfVgp0hed3XBXzXMQ==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [ppc64]
|
||||
os: [aix]
|
||||
|
||||
'@esbuild/aix-ppc64@0.27.4':
|
||||
resolution: {integrity: sha512-cQPwL2mp2nSmHHJlCyoXgHGhbEPMrEEU5xhkcy3Hs/O7nGZqEpZ2sUtLaL9MORLtDfRvVl2/3PAuEkYZH0Ty8Q==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [ppc64]
|
||||
os: [aix]
|
||||
|
||||
'@esbuild/android-arm64@0.25.12':
|
||||
resolution: {integrity: sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==}
|
||||
'@esbuild/android-arm64@0.28.1':
|
||||
resolution: {integrity: sha512-34EGEbCIAgosYz6goLcopX6Mo7NyGv9tfwEM2/7Ce2VcVRk568iSvniGWcUXIy7wEDR1wzolcxcriFVrWYcwBg==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm64]
|
||||
os: [android]
|
||||
|
||||
'@esbuild/android-arm64@0.27.4':
|
||||
resolution: {integrity: sha512-gdLscB7v75wRfu7QSm/zg6Rx29VLdy9eTr2t44sfTW7CxwAtQghZ4ZnqHk3/ogz7xao0QAgrkradbBzcqFPasw==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm64]
|
||||
os: [android]
|
||||
|
||||
'@esbuild/android-arm@0.25.12':
|
||||
resolution: {integrity: sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==}
|
||||
'@esbuild/android-arm@0.28.1':
|
||||
resolution: {integrity: sha512-0k2F129Xdio1TdJfzJ8sy1Q47vUD2NnwdhiAf7drUN1EBTfPf4hsFCtmMgu/6m8JSzsBrlmVjudMBQqOfG8usQ==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm]
|
||||
os: [android]
|
||||
|
||||
'@esbuild/android-arm@0.27.4':
|
||||
resolution: {integrity: sha512-X9bUgvxiC8CHAGKYufLIHGXPJWnr0OCdR0anD2e21vdvgCI8lIfqFbnoeOz7lBjdrAGUhqLZLcQo6MLhTO2DKQ==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm]
|
||||
os: [android]
|
||||
|
||||
'@esbuild/android-x64@0.25.12':
|
||||
resolution: {integrity: sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==}
|
||||
'@esbuild/android-x64@0.28.1':
|
||||
resolution: {integrity: sha512-dbwY7ltSMDWsRatcRpCnES4F+im88OCUgGZjy52shC7GqHRE/cYlxNbB4Z4UpJswpcc4Qxd2oE/ufM0p61IKng==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [x64]
|
||||
os: [android]
|
||||
|
||||
'@esbuild/android-x64@0.27.4':
|
||||
resolution: {integrity: sha512-PzPFnBNVF292sfpfhiyiXCGSn9HZg5BcAz+ivBuSsl6Rk4ga1oEXAamhOXRFyMcjwr2DVtm40G65N3GLeH1Lvw==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [x64]
|
||||
os: [android]
|
||||
|
||||
'@esbuild/darwin-arm64@0.25.12':
|
||||
resolution: {integrity: sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==}
|
||||
'@esbuild/darwin-arm64@0.28.1':
|
||||
resolution: {integrity: sha512-TZbWkQY7kvTAXbXUT7uVACR5cMHsDiSz9z7ZKAX/RTq/WJEk3QyRr0wZpNhBDX+/0CtdqUIJlOiodQcta6tY3Q==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm64]
|
||||
os: [darwin]
|
||||
|
||||
'@esbuild/darwin-arm64@0.27.4':
|
||||
resolution: {integrity: sha512-b7xaGIwdJlht8ZFCvMkpDN6uiSmnxxK56N2GDTMYPr2/gzvfdQN8rTfBsvVKmIVY/X7EM+/hJKEIbbHs9oA4tQ==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm64]
|
||||
os: [darwin]
|
||||
|
||||
'@esbuild/darwin-x64@0.25.12':
|
||||
resolution: {integrity: sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==}
|
||||
'@esbuild/darwin-x64@0.28.1':
|
||||
resolution: {integrity: sha512-zfdzgK9ACBNZLI/CyHTOx81SyNbM6YXn7rxSgX97VjyiPl9W1i4Ka4fgKECEoFCKGpvBj5qArWIGgQjOwkgskQ==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [x64]
|
||||
os: [darwin]
|
||||
|
||||
'@esbuild/darwin-x64@0.27.4':
|
||||
resolution: {integrity: sha512-sR+OiKLwd15nmCdqpXMnuJ9W2kpy0KigzqScqHI3Hqwr7IXxBp3Yva+yJwoqh7rE8V77tdoheRYataNKL4QrPw==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [x64]
|
||||
os: [darwin]
|
||||
|
||||
'@esbuild/freebsd-arm64@0.25.12':
|
||||
resolution: {integrity: sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==}
|
||||
'@esbuild/freebsd-arm64@0.28.1':
|
||||
resolution: {integrity: sha512-wG2EA8ENdEI0qhkSZMjfqrdY+ziCYCPMmtZjjIwOmXFjmyzEHn+UUxk5of+SYsjtfs3VpnlC7QLzSI5hY/rOAw==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm64]
|
||||
os: [freebsd]
|
||||
|
||||
'@esbuild/freebsd-arm64@0.27.4':
|
||||
resolution: {integrity: sha512-jnfpKe+p79tCnm4GVav68A7tUFeKQwQyLgESwEAUzyxk/TJr4QdGog9sqWNcUbr/bZt/O/HXouspuQDd9JxFSw==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm64]
|
||||
os: [freebsd]
|
||||
|
||||
'@esbuild/freebsd-x64@0.25.12':
|
||||
resolution: {integrity: sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==}
|
||||
'@esbuild/freebsd-x64@0.28.1':
|
||||
resolution: {integrity: sha512-i7dZ9vQgnvSCzi/rYCXNgtF/U+eKZNJBzu3eTQbRgHnM7tNSizLOkRFAl3qzVc/Op/u5YkHHa4pf/3DOYHthLQ==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [x64]
|
||||
os: [freebsd]
|
||||
|
||||
'@esbuild/freebsd-x64@0.27.4':
|
||||
resolution: {integrity: sha512-2kb4ceA/CpfUrIcTUl1wrP/9ad9Atrp5J94Lq69w7UwOMolPIGrfLSvAKJp0RTvkPPyn6CIWrNy13kyLikZRZQ==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [x64]
|
||||
os: [freebsd]
|
||||
|
||||
'@esbuild/linux-arm64@0.25.12':
|
||||
resolution: {integrity: sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==}
|
||||
'@esbuild/linux-arm64@0.28.1':
|
||||
resolution: {integrity: sha512-yHs+0uc8+nvEAfAfxrWQKK5peSNzBc4PegcMO0EJ2hT71uA7vB8Ihg2e77R2P7SG5uYjPbHlLLmve4LLLRCf0g==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-arm64@0.27.4':
|
||||
resolution: {integrity: sha512-7nQOttdzVGth1iz57kxg9uCz57dxQLHWxopL6mYuYthohPKEK0vU0C3O21CcBK6KDlkYVcnDXY099HcCDXd9dA==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-arm@0.25.12':
|
||||
resolution: {integrity: sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==}
|
||||
'@esbuild/linux-arm@0.28.1':
|
||||
resolution: {integrity: sha512-qVXBOHQS+d5Y722GwJzJUtOLlX7km3CraOaGormF1pDtPd2C/l1SHRPgjLunLGe51Sh5YYWKMFDyV4SxgMQYTQ==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-arm@0.27.4':
|
||||
resolution: {integrity: sha512-aBYgcIxX/wd5n2ys0yESGeYMGF+pv6g0DhZr3G1ZG4jMfruU9Tl1i2Z+Wnj9/KjGz1lTLCcorqE2viePZqj4Eg==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-ia32@0.25.12':
|
||||
resolution: {integrity: sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==}
|
||||
'@esbuild/linux-ia32@0.28.1':
|
||||
resolution: {integrity: sha512-d1z4ZuP0ajrfz/FhGT4vv278rX8KnPPJx8i5+AtK7TYbx9Le9F1hyzurZpkEyjkGa9dUGhQow4C1NmeGvqxN2w==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [ia32]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-ia32@0.27.4':
|
||||
resolution: {integrity: sha512-oPtixtAIzgvzYcKBQM/qZ3R+9TEUd1aNJQu0HhGyqtx6oS7qTpvjheIWBbes4+qu1bNlo2V4cbkISr8q6gRBFA==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [ia32]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-loong64@0.25.12':
|
||||
resolution: {integrity: sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==}
|
||||
'@esbuild/linux-loong64@0.28.1':
|
||||
resolution: {integrity: sha512-M5sRjUVZrkm1OAPR3dlOYzNmN+loZKGVi1VUQGrwuqLcbR6qeAz+famMhjASeH3YVKvZz+zT1jlh/keC3Rj/lg==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [loong64]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-loong64@0.27.4':
|
||||
resolution: {integrity: sha512-8mL/vh8qeCoRcFH2nM8wm5uJP+ZcVYGGayMavi8GmRJjuI3g1v6Z7Ni0JJKAJW+m0EtUuARb6Lmp4hMjzCBWzA==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [loong64]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-mips64el@0.25.12':
|
||||
resolution: {integrity: sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==}
|
||||
'@esbuild/linux-mips64el@0.28.1':
|
||||
resolution: {integrity: sha512-mRObBZeHh2OxcBFPWE/FjylkRgZdYuiTR3vaTozquCGOH14iP9oN4x4Ge81CoIDYQrXmIxpFumJBu5MtZpnQJQ==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [mips64el]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-mips64el@0.27.4':
|
||||
resolution: {integrity: sha512-1RdrWFFiiLIW7LQq9Q2NES+HiD4NyT8Itj9AUeCl0IVCA459WnPhREKgwrpaIfTOe+/2rdntisegiPWn/r/aAw==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [mips64el]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-ppc64@0.25.12':
|
||||
resolution: {integrity: sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==}
|
||||
'@esbuild/linux-ppc64@0.28.1':
|
||||
resolution: {integrity: sha512-slScBsMAb3GFDcdrCgLwZtPYRoH2H/youv10QiZyRjmsP48fznoveWytSgCI/R0ZcUgpc0ZhIUEx6LHts8yrfQ==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [ppc64]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-ppc64@0.27.4':
|
||||
resolution: {integrity: sha512-tLCwNG47l3sd9lpfyx9LAGEGItCUeRCWeAx6x2Jmbav65nAwoPXfewtAdtbtit/pJFLUWOhpv0FpS6GQAmPrHA==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [ppc64]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-riscv64@0.25.12':
|
||||
resolution: {integrity: sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==}
|
||||
'@esbuild/linux-riscv64@0.28.1':
|
||||
resolution: {integrity: sha512-kw0owk1o0GFETUJyW0jc0G4Yzs0BHZn0JDZ8JRT088vjJYX777BAs1fDGxAC+q831qOs2DTC96mNsG2opdfyyQ==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [riscv64]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-riscv64@0.27.4':
|
||||
resolution: {integrity: sha512-BnASypppbUWyqjd1KIpU4AUBiIhVr6YlHx/cnPgqEkNoVOhHg+YiSVxM1RLfiy4t9cAulbRGTNCKOcqHrEQLIw==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [riscv64]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-s390x@0.25.12':
|
||||
resolution: {integrity: sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==}
|
||||
'@esbuild/linux-s390x@0.28.1':
|
||||
resolution: {integrity: sha512-/lAIjX8aYFRByhh6L5rYtPEDRqa9de/4V/juOXcta5frjvzXO4/sqEtyytse0g3zZFuWu5cDN0MkLz2qRDD2Ag==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [s390x]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-s390x@0.27.4':
|
||||
resolution: {integrity: sha512-+eUqgb/Z7vxVLezG8bVB9SfBie89gMueS+I0xYh2tJdw3vqA/0ImZJ2ROeWwVJN59ihBeZ7Tu92dF/5dy5FttA==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [s390x]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-x64@0.25.12':
|
||||
resolution: {integrity: sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==}
|
||||
'@esbuild/linux-x64@0.28.1':
|
||||
resolution: {integrity: sha512-u/anNYF2mmVOEDwLtnQ1wOr3EZ9sTNGLWrsYGYwHWzGA3Si84IOkHXlbWTD1NB+9/1lcnweYKO54uhxZydNzfA==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-x64@0.27.4':
|
||||
resolution: {integrity: sha512-S5qOXrKV8BQEzJPVxAwnryi2+Iq5pB40gTEIT69BQONqR7JH1EPIcQ/Uiv9mCnn05jff9umq/5nqzxlqTOg9NA==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/netbsd-arm64@0.25.12':
|
||||
resolution: {integrity: sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==}
|
||||
'@esbuild/netbsd-arm64@0.28.1':
|
||||
resolution: {integrity: sha512-oks0DYbLwWMmaakTsCb+zL4E+aHRVLom9IJZOAthMQEPiQmydXHkziYEsGYRx0uNV/IjEKGAV941JzH02pflqw==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm64]
|
||||
os: [netbsd]
|
||||
|
||||
'@esbuild/netbsd-arm64@0.27.4':
|
||||
resolution: {integrity: sha512-xHT8X4sb0GS8qTqiwzHqpY00C95DPAq7nAwX35Ie/s+LO9830hrMd3oX0ZMKLvy7vsonee73x0lmcdOVXFzd6Q==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm64]
|
||||
os: [netbsd]
|
||||
|
||||
'@esbuild/netbsd-x64@0.25.12':
|
||||
resolution: {integrity: sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==}
|
||||
'@esbuild/netbsd-x64@0.28.1':
|
||||
resolution: {integrity: sha512-aeL6lAnN89Hz43Mlh1G8ARasbuoYvSITDEx0tHh5b7jJnHcssqgjy9Yx430GDpmCa6OyrKoS0aNRjKundRizGg==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [x64]
|
||||
os: [netbsd]
|
||||
|
||||
'@esbuild/netbsd-x64@0.27.4':
|
||||
resolution: {integrity: sha512-RugOvOdXfdyi5Tyv40kgQnI0byv66BFgAqjdgtAKqHoZTbTF2QqfQrFwa7cHEORJf6X2ht+l9ABLMP0dnKYsgg==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [x64]
|
||||
os: [netbsd]
|
||||
|
||||
'@esbuild/openbsd-arm64@0.25.12':
|
||||
resolution: {integrity: sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==}
|
||||
'@esbuild/openbsd-arm64@0.28.1':
|
||||
resolution: {integrity: sha512-MEFJe5C3R8pwXdZ5Y21oo6m7ePiS0d9pWucn99O/wvyJZChoIQKrQDxKrGeW8F5+T0okTHesAmDeiHDTIq0V/Q==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm64]
|
||||
os: [openbsd]
|
||||
|
||||
'@esbuild/openbsd-arm64@0.27.4':
|
||||
resolution: {integrity: sha512-2MyL3IAaTX+1/qP0O1SwskwcwCoOI4kV2IBX1xYnDDqthmq5ArrW94qSIKCAuRraMgPOmG0RDTA74mzYNQA9ow==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm64]
|
||||
os: [openbsd]
|
||||
|
||||
'@esbuild/openbsd-x64@0.25.12':
|
||||
resolution: {integrity: sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==}
|
||||
'@esbuild/openbsd-x64@0.28.1':
|
||||
resolution: {integrity: sha512-i/ZLIOafE0Z8cI/XANJAixoJL/uRAoS2xOA3rb0xN+KK0K177cMAsQYkzHtBrtMXAKuAc7HGgcWiZ/sRC1Nxgw==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [x64]
|
||||
os: [openbsd]
|
||||
|
||||
'@esbuild/openbsd-x64@0.27.4':
|
||||
resolution: {integrity: sha512-u8fg/jQ5aQDfsnIV6+KwLOf1CmJnfu1ShpwqdwC0uA7ZPwFws55Ngc12vBdeUdnuWoQYx/SOQLGDcdlfXhYmXQ==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [x64]
|
||||
os: [openbsd]
|
||||
|
||||
'@esbuild/openharmony-arm64@0.25.12':
|
||||
resolution: {integrity: sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==}
|
||||
'@esbuild/openharmony-arm64@0.28.1':
|
||||
resolution: {integrity: sha512-ge+Z7EXFNt2BO1oAMsVpiQ8EwndV9i1xXerAeTIK7AtPs3bKFXQM7nlRxDSIUIMeueR1CNXxqztLzdNeReKBJg==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm64]
|
||||
os: [openharmony]
|
||||
|
||||
'@esbuild/openharmony-arm64@0.27.4':
|
||||
resolution: {integrity: sha512-JkTZrl6VbyO8lDQO3yv26nNr2RM2yZzNrNHEsj9bm6dOwwu9OYN28CjzZkH57bh4w0I2F7IodpQvUAEd1mbWXg==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm64]
|
||||
os: [openharmony]
|
||||
|
||||
'@esbuild/sunos-x64@0.25.12':
|
||||
resolution: {integrity: sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==}
|
||||
'@esbuild/sunos-x64@0.28.1':
|
||||
resolution: {integrity: sha512-BEjgtECkL3vY+SaSQ6nzVfiALUeFxpawyp8Jmf5PtYhf1Ug40N1h/hxlhts+f1FvSvarEigdxS3BlSMI2PJLcQ==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [x64]
|
||||
os: [sunos]
|
||||
|
||||
'@esbuild/sunos-x64@0.27.4':
|
||||
resolution: {integrity: sha512-/gOzgaewZJfeJTlsWhvUEmUG4tWEY2Spp5M20INYRg2ZKl9QPO3QEEgPeRtLjEWSW8FilRNacPOg8R1uaYkA6g==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [x64]
|
||||
os: [sunos]
|
||||
|
||||
'@esbuild/win32-arm64@0.25.12':
|
||||
resolution: {integrity: sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==}
|
||||
'@esbuild/win32-arm64@0.28.1':
|
||||
resolution: {integrity: sha512-lCv9eK/H6ZJWbE7bh2nw54CZ9M2nupBxJcTsdk/QQnWkdSjKGuxmmH8/GWrlT1eMmZfn4dGcCjRte397WqfQXA==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm64]
|
||||
os: [win32]
|
||||
|
||||
'@esbuild/win32-arm64@0.27.4':
|
||||
resolution: {integrity: sha512-Z9SExBg2y32smoDQdf1HRwHRt6vAHLXcxD2uGgO/v2jK7Y718Ix4ndsbNMU/+1Qiem9OiOdaqitioZwxivhXYg==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm64]
|
||||
os: [win32]
|
||||
|
||||
'@esbuild/win32-ia32@0.25.12':
|
||||
resolution: {integrity: sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==}
|
||||
'@esbuild/win32-ia32@0.28.1':
|
||||
resolution: {integrity: sha512-zvb/mB2bSCoJOpoCBgYKKpX6YM6mJBlBUVUtVj41DlZJVEB6/0CKlRYxP5wWl1C1ILiCoAU5wZZ4q1P3qeS6Eg==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [ia32]
|
||||
os: [win32]
|
||||
|
||||
'@esbuild/win32-ia32@0.27.4':
|
||||
resolution: {integrity: sha512-DAyGLS0Jz5G5iixEbMHi5KdiApqHBWMGzTtMiJ72ZOLhbu/bzxgAe8Ue8CTS3n3HbIUHQz/L51yMdGMeoxXNJw==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [ia32]
|
||||
os: [win32]
|
||||
|
||||
'@esbuild/win32-x64@0.25.12':
|
||||
resolution: {integrity: sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [x64]
|
||||
os: [win32]
|
||||
|
||||
'@esbuild/win32-x64@0.27.4':
|
||||
resolution: {integrity: sha512-+knoa0BDoeXgkNvvV1vvbZX4+hizelrkwmGJBdT17t8FNPwG2lKemmuMZlmaNQ3ws3DKKCxpb4zRZEIp3UxFCg==}
|
||||
'@esbuild/win32-x64@0.28.1':
|
||||
resolution: {integrity: sha512-bm4Mowrv+GXMlpWX++EcXw/iLyd1o3+bJkC2DkWXYVvgZCqD/bSj9ctZeAMC3cIxgjRVR2Dufaiu4YPxr5gW1A==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [x64]
|
||||
os: [win32]
|
||||
@@ -475,79 +316,66 @@ packages:
|
||||
resolution: {integrity: sha512-RzeBwv0B3qtVBWtcuABtSuCzToo2IEAIQrcyB/b2zMvBWVbjo8bZDjACUpnaafaxhTw2W+imQbP2BD1usasK4g==}
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rollup/rollup-linux-arm-musleabihf@4.60.0':
|
||||
resolution: {integrity: sha512-Sf7zusNI2CIU1HLzuu9Tc5YGAHEZs5Lu7N1ssJG4Tkw6e0MEsN7NdjUDDfGNHy2IU+ENyWT+L2obgWiguWibWQ==}
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@rollup/rollup-linux-arm64-gnu@4.60.0':
|
||||
resolution: {integrity: sha512-DX2x7CMcrJzsE91q7/O02IJQ5/aLkVtYFryqCjduJhUfGKG6yJV8hxaw8pZa93lLEpPTP/ohdN4wFz7yp/ry9A==}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rollup/rollup-linux-arm64-musl@4.60.0':
|
||||
resolution: {integrity: sha512-09EL+yFVbJZlhcQfShpswwRZ0Rg+z/CsSELFCnPt3iK+iqwGsI4zht3secj5vLEs957QvFFXnzAT0FFPIxSrkQ==}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@rollup/rollup-linux-loong64-gnu@4.60.0':
|
||||
resolution: {integrity: sha512-i9IcCMPr3EXm8EQg5jnja0Zyc1iFxJjZWlb4wr7U2Wx/GrddOuEafxRdMPRYVaXjgbhvqalp6np07hN1w9kAKw==}
|
||||
cpu: [loong64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rollup/rollup-linux-loong64-musl@4.60.0':
|
||||
resolution: {integrity: sha512-DGzdJK9kyJ+B78MCkWeGnpXJ91tK/iKA6HwHxF4TAlPIY7GXEvMe8hBFRgdrR9Ly4qebR/7gfUs9y2IoaVEyog==}
|
||||
cpu: [loong64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@rollup/rollup-linux-ppc64-gnu@4.60.0':
|
||||
resolution: {integrity: sha512-RwpnLsqC8qbS8z1H1AxBA1H6qknR4YpPR9w2XX0vo2Sz10miu57PkNcnHVaZkbqyw/kUWfKMI73jhmfi9BRMUQ==}
|
||||
cpu: [ppc64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rollup/rollup-linux-ppc64-musl@4.60.0':
|
||||
resolution: {integrity: sha512-Z8pPf54Ly3aqtdWC3G4rFigZgNvd+qJlOE52fmko3KST9SoGfAdSRCwyoyG05q1HrrAblLbk1/PSIV+80/pxLg==}
|
||||
cpu: [ppc64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@rollup/rollup-linux-riscv64-gnu@4.60.0':
|
||||
resolution: {integrity: sha512-3a3qQustp3COCGvnP4SvrMHnPQ9d1vzCakQVRTliaz8cIp/wULGjiGpbcqrkv0WrHTEp8bQD/B3HBjzujVWLOA==}
|
||||
cpu: [riscv64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rollup/rollup-linux-riscv64-musl@4.60.0':
|
||||
resolution: {integrity: sha512-pjZDsVH/1VsghMJ2/kAaxt6dL0psT6ZexQVrijczOf+PeP2BUqTHYejk3l6TlPRydggINOeNRhvpLa0AYpCWSQ==}
|
||||
cpu: [riscv64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@rollup/rollup-linux-s390x-gnu@4.60.0':
|
||||
resolution: {integrity: sha512-3ObQs0BhvPgiUVZrN7gqCSvmFuMWvWvsjG5ayJ3Lraqv+2KhOsp+pUbigqbeWqueGIsnn+09HBw27rJ+gYK4VQ==}
|
||||
cpu: [s390x]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rollup/rollup-linux-x64-gnu@4.60.0':
|
||||
resolution: {integrity: sha512-EtylprDtQPdS5rXvAayrNDYoJhIz1/vzN2fEubo3yLE7tfAw+948dO0g4M0vkTVFhKojnF+n6C8bDNe+gDRdTg==}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rollup/rollup-linux-x64-musl@4.60.0':
|
||||
resolution: {integrity: sha512-k09oiRCi/bHU9UVFqD17r3eJR9bn03TyKraCrlz5ULFJGdJGi7VOmm9jl44vOJvRJ6P7WuBi/s2A97LxxHGIdw==}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@rollup/rollup-openbsd-x64@4.60.0':
|
||||
resolution: {integrity: sha512-1o/0/pIhozoSaDJoDcec+IVLbnRtQmHwPV730+AOD29lHEEo4F5BEUB24H0OBdhbBBDwIOSuf7vgg0Ywxdfiiw==}
|
||||
@@ -658,7 +486,7 @@ packages:
|
||||
resolution: {integrity: sha512-3WrrOuZiyaaZPWiEt4G3+IffISVC9HYlWueJEBWED4ZH4aIAC2PnkdnuRrR94M+w6yGWn4AglWtJtBI8YqvgoA==}
|
||||
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
|
||||
peerDependencies:
|
||||
esbuild: '>=0.18'
|
||||
esbuild: '>=0.28.1'
|
||||
|
||||
cac@6.7.14:
|
||||
resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==}
|
||||
@@ -738,13 +566,8 @@ packages:
|
||||
es-module-lexer@2.1.0:
|
||||
resolution: {integrity: sha512-n27zTYMjYu1aj4MjCWzSP7G9r75utsaoc8m61weK+W8JMBGGQybd43GstCXZ3WNmSFtGT9wi59qQTW6mhTR5LQ==}
|
||||
|
||||
esbuild@0.25.12:
|
||||
resolution: {integrity: sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==}
|
||||
engines: {node: '>=18'}
|
||||
hasBin: true
|
||||
|
||||
esbuild@0.27.4:
|
||||
resolution: {integrity: sha512-Rq4vbHnYkK5fws5NF7MYTU68FPRE1ajX7heQ/8QXXWqNgqqJ/GkmmyxIzUnf2Sr/bakf8l54716CcMGHYhMrrQ==}
|
||||
esbuild@0.28.1:
|
||||
resolution: {integrity: sha512-HrJrvZv5ayxBzPfwphOoNzkzOIIlifzk0KJrGK2c8R4+LKpMtpYLQeUdjnwjWv/LZlkH2laZk+4w78pi99D4Vw==}
|
||||
engines: {node: '>=18'}
|
||||
hasBin: true
|
||||
|
||||
@@ -1164,160 +987,82 @@ snapshots:
|
||||
'@colors/colors@1.5.0':
|
||||
optional: true
|
||||
|
||||
'@esbuild/aix-ppc64@0.25.12':
|
||||
'@esbuild/aix-ppc64@0.28.1':
|
||||
optional: true
|
||||
|
||||
'@esbuild/aix-ppc64@0.27.4':
|
||||
'@esbuild/android-arm64@0.28.1':
|
||||
optional: true
|
||||
|
||||
'@esbuild/android-arm64@0.25.12':
|
||||
'@esbuild/android-arm@0.28.1':
|
||||
optional: true
|
||||
|
||||
'@esbuild/android-arm64@0.27.4':
|
||||
'@esbuild/android-x64@0.28.1':
|
||||
optional: true
|
||||
|
||||
'@esbuild/android-arm@0.25.12':
|
||||
'@esbuild/darwin-arm64@0.28.1':
|
||||
optional: true
|
||||
|
||||
'@esbuild/android-arm@0.27.4':
|
||||
'@esbuild/darwin-x64@0.28.1':
|
||||
optional: true
|
||||
|
||||
'@esbuild/android-x64@0.25.12':
|
||||
'@esbuild/freebsd-arm64@0.28.1':
|
||||
optional: true
|
||||
|
||||
'@esbuild/android-x64@0.27.4':
|
||||
'@esbuild/freebsd-x64@0.28.1':
|
||||
optional: true
|
||||
|
||||
'@esbuild/darwin-arm64@0.25.12':
|
||||
'@esbuild/linux-arm64@0.28.1':
|
||||
optional: true
|
||||
|
||||
'@esbuild/darwin-arm64@0.27.4':
|
||||
'@esbuild/linux-arm@0.28.1':
|
||||
optional: true
|
||||
|
||||
'@esbuild/darwin-x64@0.25.12':
|
||||
'@esbuild/linux-ia32@0.28.1':
|
||||
optional: true
|
||||
|
||||
'@esbuild/darwin-x64@0.27.4':
|
||||
'@esbuild/linux-loong64@0.28.1':
|
||||
optional: true
|
||||
|
||||
'@esbuild/freebsd-arm64@0.25.12':
|
||||
'@esbuild/linux-mips64el@0.28.1':
|
||||
optional: true
|
||||
|
||||
'@esbuild/freebsd-arm64@0.27.4':
|
||||
'@esbuild/linux-ppc64@0.28.1':
|
||||
optional: true
|
||||
|
||||
'@esbuild/freebsd-x64@0.25.12':
|
||||
'@esbuild/linux-riscv64@0.28.1':
|
||||
optional: true
|
||||
|
||||
'@esbuild/freebsd-x64@0.27.4':
|
||||
'@esbuild/linux-s390x@0.28.1':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-arm64@0.25.12':
|
||||
'@esbuild/linux-x64@0.28.1':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-arm64@0.27.4':
|
||||
'@esbuild/netbsd-arm64@0.28.1':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-arm@0.25.12':
|
||||
'@esbuild/netbsd-x64@0.28.1':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-arm@0.27.4':
|
||||
'@esbuild/openbsd-arm64@0.28.1':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-ia32@0.25.12':
|
||||
'@esbuild/openbsd-x64@0.28.1':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-ia32@0.27.4':
|
||||
'@esbuild/openharmony-arm64@0.28.1':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-loong64@0.25.12':
|
||||
'@esbuild/sunos-x64@0.28.1':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-loong64@0.27.4':
|
||||
'@esbuild/win32-arm64@0.28.1':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-mips64el@0.25.12':
|
||||
'@esbuild/win32-ia32@0.28.1':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-mips64el@0.27.4':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-ppc64@0.25.12':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-ppc64@0.27.4':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-riscv64@0.25.12':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-riscv64@0.27.4':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-s390x@0.25.12':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-s390x@0.27.4':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-x64@0.25.12':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-x64@0.27.4':
|
||||
optional: true
|
||||
|
||||
'@esbuild/netbsd-arm64@0.25.12':
|
||||
optional: true
|
||||
|
||||
'@esbuild/netbsd-arm64@0.27.4':
|
||||
optional: true
|
||||
|
||||
'@esbuild/netbsd-x64@0.25.12':
|
||||
optional: true
|
||||
|
||||
'@esbuild/netbsd-x64@0.27.4':
|
||||
optional: true
|
||||
|
||||
'@esbuild/openbsd-arm64@0.25.12':
|
||||
optional: true
|
||||
|
||||
'@esbuild/openbsd-arm64@0.27.4':
|
||||
optional: true
|
||||
|
||||
'@esbuild/openbsd-x64@0.25.12':
|
||||
optional: true
|
||||
|
||||
'@esbuild/openbsd-x64@0.27.4':
|
||||
optional: true
|
||||
|
||||
'@esbuild/openharmony-arm64@0.25.12':
|
||||
optional: true
|
||||
|
||||
'@esbuild/openharmony-arm64@0.27.4':
|
||||
optional: true
|
||||
|
||||
'@esbuild/sunos-x64@0.25.12':
|
||||
optional: true
|
||||
|
||||
'@esbuild/sunos-x64@0.27.4':
|
||||
optional: true
|
||||
|
||||
'@esbuild/win32-arm64@0.25.12':
|
||||
optional: true
|
||||
|
||||
'@esbuild/win32-arm64@0.27.4':
|
||||
optional: true
|
||||
|
||||
'@esbuild/win32-ia32@0.25.12':
|
||||
optional: true
|
||||
|
||||
'@esbuild/win32-ia32@0.27.4':
|
||||
optional: true
|
||||
|
||||
'@esbuild/win32-x64@0.25.12':
|
||||
optional: true
|
||||
|
||||
'@esbuild/win32-x64@0.27.4':
|
||||
'@esbuild/win32-x64@0.28.1':
|
||||
optional: true
|
||||
|
||||
'@jridgewell/gen-mapping@0.3.13':
|
||||
@@ -1492,9 +1237,9 @@ snapshots:
|
||||
widest-line: 4.0.1
|
||||
wrap-ansi: 8.1.0
|
||||
|
||||
bundle-require@5.1.0(esbuild@0.27.4):
|
||||
bundle-require@5.1.0(esbuild@0.28.1):
|
||||
dependencies:
|
||||
esbuild: 0.27.4
|
||||
esbuild: 0.28.1
|
||||
load-tsconfig: 0.2.5
|
||||
|
||||
cac@6.7.14: {}
|
||||
@@ -1547,63 +1292,34 @@ snapshots:
|
||||
|
||||
es-module-lexer@2.1.0: {}
|
||||
|
||||
esbuild@0.25.12:
|
||||
esbuild@0.28.1:
|
||||
optionalDependencies:
|
||||
'@esbuild/aix-ppc64': 0.25.12
|
||||
'@esbuild/android-arm': 0.25.12
|
||||
'@esbuild/android-arm64': 0.25.12
|
||||
'@esbuild/android-x64': 0.25.12
|
||||
'@esbuild/darwin-arm64': 0.25.12
|
||||
'@esbuild/darwin-x64': 0.25.12
|
||||
'@esbuild/freebsd-arm64': 0.25.12
|
||||
'@esbuild/freebsd-x64': 0.25.12
|
||||
'@esbuild/linux-arm': 0.25.12
|
||||
'@esbuild/linux-arm64': 0.25.12
|
||||
'@esbuild/linux-ia32': 0.25.12
|
||||
'@esbuild/linux-loong64': 0.25.12
|
||||
'@esbuild/linux-mips64el': 0.25.12
|
||||
'@esbuild/linux-ppc64': 0.25.12
|
||||
'@esbuild/linux-riscv64': 0.25.12
|
||||
'@esbuild/linux-s390x': 0.25.12
|
||||
'@esbuild/linux-x64': 0.25.12
|
||||
'@esbuild/netbsd-arm64': 0.25.12
|
||||
'@esbuild/netbsd-x64': 0.25.12
|
||||
'@esbuild/openbsd-arm64': 0.25.12
|
||||
'@esbuild/openbsd-x64': 0.25.12
|
||||
'@esbuild/openharmony-arm64': 0.25.12
|
||||
'@esbuild/sunos-x64': 0.25.12
|
||||
'@esbuild/win32-arm64': 0.25.12
|
||||
'@esbuild/win32-ia32': 0.25.12
|
||||
'@esbuild/win32-x64': 0.25.12
|
||||
|
||||
esbuild@0.27.4:
|
||||
optionalDependencies:
|
||||
'@esbuild/aix-ppc64': 0.27.4
|
||||
'@esbuild/android-arm': 0.27.4
|
||||
'@esbuild/android-arm64': 0.27.4
|
||||
'@esbuild/android-x64': 0.27.4
|
||||
'@esbuild/darwin-arm64': 0.27.4
|
||||
'@esbuild/darwin-x64': 0.27.4
|
||||
'@esbuild/freebsd-arm64': 0.27.4
|
||||
'@esbuild/freebsd-x64': 0.27.4
|
||||
'@esbuild/linux-arm': 0.27.4
|
||||
'@esbuild/linux-arm64': 0.27.4
|
||||
'@esbuild/linux-ia32': 0.27.4
|
||||
'@esbuild/linux-loong64': 0.27.4
|
||||
'@esbuild/linux-mips64el': 0.27.4
|
||||
'@esbuild/linux-ppc64': 0.27.4
|
||||
'@esbuild/linux-riscv64': 0.27.4
|
||||
'@esbuild/linux-s390x': 0.27.4
|
||||
'@esbuild/linux-x64': 0.27.4
|
||||
'@esbuild/netbsd-arm64': 0.27.4
|
||||
'@esbuild/netbsd-x64': 0.27.4
|
||||
'@esbuild/openbsd-arm64': 0.27.4
|
||||
'@esbuild/openbsd-x64': 0.27.4
|
||||
'@esbuild/openharmony-arm64': 0.27.4
|
||||
'@esbuild/sunos-x64': 0.27.4
|
||||
'@esbuild/win32-arm64': 0.27.4
|
||||
'@esbuild/win32-ia32': 0.27.4
|
||||
'@esbuild/win32-x64': 0.27.4
|
||||
'@esbuild/aix-ppc64': 0.28.1
|
||||
'@esbuild/android-arm': 0.28.1
|
||||
'@esbuild/android-arm64': 0.28.1
|
||||
'@esbuild/android-x64': 0.28.1
|
||||
'@esbuild/darwin-arm64': 0.28.1
|
||||
'@esbuild/darwin-x64': 0.28.1
|
||||
'@esbuild/freebsd-arm64': 0.28.1
|
||||
'@esbuild/freebsd-x64': 0.28.1
|
||||
'@esbuild/linux-arm': 0.28.1
|
||||
'@esbuild/linux-arm64': 0.28.1
|
||||
'@esbuild/linux-ia32': 0.28.1
|
||||
'@esbuild/linux-loong64': 0.28.1
|
||||
'@esbuild/linux-mips64el': 0.28.1
|
||||
'@esbuild/linux-ppc64': 0.28.1
|
||||
'@esbuild/linux-riscv64': 0.28.1
|
||||
'@esbuild/linux-s390x': 0.28.1
|
||||
'@esbuild/linux-x64': 0.28.1
|
||||
'@esbuild/netbsd-arm64': 0.28.1
|
||||
'@esbuild/netbsd-x64': 0.28.1
|
||||
'@esbuild/openbsd-arm64': 0.28.1
|
||||
'@esbuild/openbsd-x64': 0.28.1
|
||||
'@esbuild/openharmony-arm64': 0.28.1
|
||||
'@esbuild/sunos-x64': 0.28.1
|
||||
'@esbuild/win32-arm64': 0.28.1
|
||||
'@esbuild/win32-ia32': 0.28.1
|
||||
'@esbuild/win32-x64': 0.28.1
|
||||
|
||||
estree-walker@3.0.3:
|
||||
dependencies:
|
||||
@@ -1840,12 +1556,12 @@ snapshots:
|
||||
|
||||
tsup@8.5.1(postcss@8.5.15)(tsx@4.21.0)(typescript@5.9.3):
|
||||
dependencies:
|
||||
bundle-require: 5.1.0(esbuild@0.27.4)
|
||||
bundle-require: 5.1.0(esbuild@0.28.1)
|
||||
cac: 6.7.14
|
||||
chokidar: 4.0.3
|
||||
consola: 3.4.2
|
||||
debug: 4.4.3
|
||||
esbuild: 0.27.4
|
||||
esbuild: 0.28.1
|
||||
fix-dts-default-cjs-exports: 1.0.1
|
||||
joycon: 3.1.1
|
||||
picocolors: 1.1.1
|
||||
@@ -1868,7 +1584,7 @@ snapshots:
|
||||
|
||||
tsx@4.21.0:
|
||||
dependencies:
|
||||
esbuild: 0.27.4
|
||||
esbuild: 0.28.1
|
||||
get-tsconfig: 4.13.7
|
||||
optionalDependencies:
|
||||
fsevents: 2.3.3
|
||||
@@ -1883,7 +1599,7 @@ snapshots:
|
||||
|
||||
vite@6.4.3(@types/node@20.19.37)(tsx@4.21.0):
|
||||
dependencies:
|
||||
esbuild: 0.25.12
|
||||
esbuild: 0.28.1
|
||||
fdir: 6.5.0(picomatch@4.0.4)
|
||||
picomatch: 4.0.4
|
||||
postcss: 8.5.15
|
||||
|
||||
@@ -11,3 +11,4 @@ overrides:
|
||||
tar-fs@>=2.0.0 <2.1.4: ^2.1.4
|
||||
picomatch@<2.3.2: ^2.3.2
|
||||
"postcss@<8.5.10": ">=8.5.10"
|
||||
"esbuild": ">=0.28.1"
|
||||
|
||||
@@ -42,7 +42,7 @@ import {
|
||||
isSubagentSession,
|
||||
} from "./isolation.ts";
|
||||
import {
|
||||
loadTriagePrompt,
|
||||
loadCompactTriagePrompt,
|
||||
loadDreamPrompt,
|
||||
isSkillsMode,
|
||||
} from "./skill-loader.ts";
|
||||
@@ -464,7 +464,7 @@ function registerHooks(
|
||||
"openclaw-mem0: skills-mode skipping recall for system/bootstrap prompt",
|
||||
);
|
||||
// Still inject the protocol, just skip recall search
|
||||
const systemContext = loadTriagePrompt(cfg.skills ?? {});
|
||||
const systemContext = loadCompactTriagePrompt(cfg.skills ?? {});
|
||||
return { prependSystemContext: systemContext };
|
||||
}
|
||||
|
||||
@@ -474,7 +474,7 @@ function registerHooks(
|
||||
const userId = _effectiveUserId(isSubagent ? undefined : sessionId);
|
||||
|
||||
// Static protocol goes in prependSystemContext (cacheable across turns)
|
||||
let systemContext = loadTriagePrompt(cfg.skills ?? {});
|
||||
let systemContext = loadCompactTriagePrompt(cfg.skills ?? {});
|
||||
if (isSubagent) {
|
||||
systemContext =
|
||||
"You are a subagent — use these memories for context but do not assume you are this user. Do NOT store new memories.\n\n" +
|
||||
|
||||
@@ -69,7 +69,8 @@
|
||||
"langsmith@<0.6.0": "^0.6.0",
|
||||
"picomatch@<2.3.2": "^2.3.2",
|
||||
"@qdrant/js-client-rest": "^1.18.0",
|
||||
"uuid@<11.1.1": ">=11.1.1"
|
||||
"uuid@<11.1.1": ">=11.1.1",
|
||||
"esbuild": ">=0.28.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Generated
+124
-123
@@ -11,6 +11,7 @@ overrides:
|
||||
picomatch@<2.3.2: ^2.3.2
|
||||
'@qdrant/js-client-rest': ^1.18.0
|
||||
uuid@<11.1.1: '>=11.1.1'
|
||||
esbuild: '>=0.28.1'
|
||||
|
||||
importers:
|
||||
|
||||
@@ -40,10 +41,10 @@ importers:
|
||||
version: 5.9.3
|
||||
vite:
|
||||
specifier: ^8.0.5
|
||||
version: 8.0.16(@types/node@22.19.20)(esbuild@0.27.7)
|
||||
version: 8.0.16(@types/node@22.19.20)(esbuild@0.28.1)
|
||||
vitest:
|
||||
specifier: ^4.1.7
|
||||
version: 4.1.8(@types/node@22.19.20)(@vitest/coverage-v8@4.1.8)(vite@8.0.16(@types/node@22.19.20)(esbuild@0.27.7))
|
||||
version: 4.1.8(@types/node@22.19.20)(@vitest/coverage-v8@4.1.8)(vite@8.0.16(@types/node@22.19.20)(esbuild@0.28.1))
|
||||
|
||||
packages:
|
||||
|
||||
@@ -149,158 +150,158 @@ packages:
|
||||
'@emnapi/wasi-threads@1.2.1':
|
||||
resolution: {integrity: sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==}
|
||||
|
||||
'@esbuild/aix-ppc64@0.27.7':
|
||||
resolution: {integrity: sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg==}
|
||||
'@esbuild/aix-ppc64@0.28.1':
|
||||
resolution: {integrity: sha512-Svl7tq8k/08+p6CXPpRjQ1fKX+1odH/BQbb48fV6fj3CWHhsoIOoY87w1oHXm0qEpkIK3ZfVgp0hed3XBXzXMQ==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [ppc64]
|
||||
os: [aix]
|
||||
|
||||
'@esbuild/android-arm64@0.27.7':
|
||||
resolution: {integrity: sha512-62dPZHpIXzvChfvfLJow3q5dDtiNMkwiRzPylSCfriLvZeq0a1bWChrGx/BbUbPwOrsWKMn8idSllklzBy+dgQ==}
|
||||
'@esbuild/android-arm64@0.28.1':
|
||||
resolution: {integrity: sha512-34EGEbCIAgosYz6goLcopX6Mo7NyGv9tfwEM2/7Ce2VcVRk568iSvniGWcUXIy7wEDR1wzolcxcriFVrWYcwBg==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm64]
|
||||
os: [android]
|
||||
|
||||
'@esbuild/android-arm@0.27.7':
|
||||
resolution: {integrity: sha512-jbPXvB4Yj2yBV7HUfE2KHe4GJX51QplCN1pGbYjvsyCZbQmies29EoJbkEc+vYuU5o45AfQn37vZlyXy4YJ8RQ==}
|
||||
'@esbuild/android-arm@0.28.1':
|
||||
resolution: {integrity: sha512-0k2F129Xdio1TdJfzJ8sy1Q47vUD2NnwdhiAf7drUN1EBTfPf4hsFCtmMgu/6m8JSzsBrlmVjudMBQqOfG8usQ==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm]
|
||||
os: [android]
|
||||
|
||||
'@esbuild/android-x64@0.27.7':
|
||||
resolution: {integrity: sha512-x5VpMODneVDb70PYV2VQOmIUUiBtY3D3mPBG8NxVk5CogneYhkR7MmM3yR/uMdITLrC1ml/NV1rj4bMJuy9MCg==}
|
||||
'@esbuild/android-x64@0.28.1':
|
||||
resolution: {integrity: sha512-dbwY7ltSMDWsRatcRpCnES4F+im88OCUgGZjy52shC7GqHRE/cYlxNbB4Z4UpJswpcc4Qxd2oE/ufM0p61IKng==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [x64]
|
||||
os: [android]
|
||||
|
||||
'@esbuild/darwin-arm64@0.27.7':
|
||||
resolution: {integrity: sha512-5lckdqeuBPlKUwvoCXIgI2D9/ABmPq3Rdp7IfL70393YgaASt7tbju3Ac+ePVi3KDH6N2RqePfHnXkaDtY9fkw==}
|
||||
'@esbuild/darwin-arm64@0.28.1':
|
||||
resolution: {integrity: sha512-TZbWkQY7kvTAXbXUT7uVACR5cMHsDiSz9z7ZKAX/RTq/WJEk3QyRr0wZpNhBDX+/0CtdqUIJlOiodQcta6tY3Q==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm64]
|
||||
os: [darwin]
|
||||
|
||||
'@esbuild/darwin-x64@0.27.7':
|
||||
resolution: {integrity: sha512-rYnXrKcXuT7Z+WL5K980jVFdvVKhCHhUwid+dDYQpH+qu+TefcomiMAJpIiC2EM3Rjtq0sO3StMV/+3w3MyyqQ==}
|
||||
'@esbuild/darwin-x64@0.28.1':
|
||||
resolution: {integrity: sha512-zfdzgK9ACBNZLI/CyHTOx81SyNbM6YXn7rxSgX97VjyiPl9W1i4Ka4fgKECEoFCKGpvBj5qArWIGgQjOwkgskQ==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [x64]
|
||||
os: [darwin]
|
||||
|
||||
'@esbuild/freebsd-arm64@0.27.7':
|
||||
resolution: {integrity: sha512-B48PqeCsEgOtzME2GbNM2roU29AMTuOIN91dsMO30t+Ydis3z/3Ngoj5hhnsOSSwNzS+6JppqWsuhTp6E82l2w==}
|
||||
'@esbuild/freebsd-arm64@0.28.1':
|
||||
resolution: {integrity: sha512-wG2EA8ENdEI0qhkSZMjfqrdY+ziCYCPMmtZjjIwOmXFjmyzEHn+UUxk5of+SYsjtfs3VpnlC7QLzSI5hY/rOAw==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm64]
|
||||
os: [freebsd]
|
||||
|
||||
'@esbuild/freebsd-x64@0.27.7':
|
||||
resolution: {integrity: sha512-jOBDK5XEjA4m5IJK3bpAQF9/Lelu/Z9ZcdhTRLf4cajlB+8VEhFFRjWgfy3M1O4rO2GQ/b2dLwCUGpiF/eATNQ==}
|
||||
'@esbuild/freebsd-x64@0.28.1':
|
||||
resolution: {integrity: sha512-i7dZ9vQgnvSCzi/rYCXNgtF/U+eKZNJBzu3eTQbRgHnM7tNSizLOkRFAl3qzVc/Op/u5YkHHa4pf/3DOYHthLQ==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [x64]
|
||||
os: [freebsd]
|
||||
|
||||
'@esbuild/linux-arm64@0.27.7':
|
||||
resolution: {integrity: sha512-RZPHBoxXuNnPQO9rvjh5jdkRmVizktkT7TCDkDmQ0W2SwHInKCAV95GRuvdSvA7w4VMwfCjUiPwDi0ZO6Nfe9A==}
|
||||
'@esbuild/linux-arm64@0.28.1':
|
||||
resolution: {integrity: sha512-yHs+0uc8+nvEAfAfxrWQKK5peSNzBc4PegcMO0EJ2hT71uA7vB8Ihg2e77R2P7SG5uYjPbHlLLmve4LLLRCf0g==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-arm@0.27.7':
|
||||
resolution: {integrity: sha512-RkT/YXYBTSULo3+af8Ib0ykH8u2MBh57o7q/DAs3lTJlyVQkgQvlrPTnjIzzRPQyavxtPtfg0EopvDyIt0j1rA==}
|
||||
'@esbuild/linux-arm@0.28.1':
|
||||
resolution: {integrity: sha512-qVXBOHQS+d5Y722GwJzJUtOLlX7km3CraOaGormF1pDtPd2C/l1SHRPgjLunLGe51Sh5YYWKMFDyV4SxgMQYTQ==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-ia32@0.27.7':
|
||||
resolution: {integrity: sha512-GA48aKNkyQDbd3KtkplYWT102C5sn/EZTY4XROkxONgruHPU72l+gW+FfF8tf2cFjeHaRbWpOYa/uRBz/Xq1Pg==}
|
||||
'@esbuild/linux-ia32@0.28.1':
|
||||
resolution: {integrity: sha512-d1z4ZuP0ajrfz/FhGT4vv278rX8KnPPJx8i5+AtK7TYbx9Le9F1hyzurZpkEyjkGa9dUGhQow4C1NmeGvqxN2w==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [ia32]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-loong64@0.27.7':
|
||||
resolution: {integrity: sha512-a4POruNM2oWsD4WKvBSEKGIiWQF8fZOAsycHOt6JBpZ+JN2n2JH9WAv56SOyu9X5IqAjqSIPTaJkqN8F7XOQ5Q==}
|
||||
'@esbuild/linux-loong64@0.28.1':
|
||||
resolution: {integrity: sha512-M5sRjUVZrkm1OAPR3dlOYzNmN+loZKGVi1VUQGrwuqLcbR6qeAz+famMhjASeH3YVKvZz+zT1jlh/keC3Rj/lg==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [loong64]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-mips64el@0.27.7':
|
||||
resolution: {integrity: sha512-KabT5I6StirGfIz0FMgl1I+R1H73Gp0ofL9A3nG3i/cYFJzKHhouBV5VWK1CSgKvVaG4q1RNpCTR2LuTVB3fIw==}
|
||||
'@esbuild/linux-mips64el@0.28.1':
|
||||
resolution: {integrity: sha512-mRObBZeHh2OxcBFPWE/FjylkRgZdYuiTR3vaTozquCGOH14iP9oN4x4Ge81CoIDYQrXmIxpFumJBu5MtZpnQJQ==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [mips64el]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-ppc64@0.27.7':
|
||||
resolution: {integrity: sha512-gRsL4x6wsGHGRqhtI+ifpN/vpOFTQtnbsupUF5R5YTAg+y/lKelYR1hXbnBdzDjGbMYjVJLJTd2OFmMewAgwlQ==}
|
||||
'@esbuild/linux-ppc64@0.28.1':
|
||||
resolution: {integrity: sha512-slScBsMAb3GFDcdrCgLwZtPYRoH2H/youv10QiZyRjmsP48fznoveWytSgCI/R0ZcUgpc0ZhIUEx6LHts8yrfQ==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [ppc64]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-riscv64@0.27.7':
|
||||
resolution: {integrity: sha512-hL25LbxO1QOngGzu2U5xeXtxXcW+/GvMN3ejANqXkxZ/opySAZMrc+9LY/WyjAan41unrR3YrmtTsUpwT66InQ==}
|
||||
'@esbuild/linux-riscv64@0.28.1':
|
||||
resolution: {integrity: sha512-kw0owk1o0GFETUJyW0jc0G4Yzs0BHZn0JDZ8JRT088vjJYX777BAs1fDGxAC+q831qOs2DTC96mNsG2opdfyyQ==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [riscv64]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-s390x@0.27.7':
|
||||
resolution: {integrity: sha512-2k8go8Ycu1Kb46vEelhu1vqEP+UeRVj2zY1pSuPdgvbd5ykAw82Lrro28vXUrRmzEsUV0NzCf54yARIK8r0fdw==}
|
||||
'@esbuild/linux-s390x@0.28.1':
|
||||
resolution: {integrity: sha512-/lAIjX8aYFRByhh6L5rYtPEDRqa9de/4V/juOXcta5frjvzXO4/sqEtyytse0g3zZFuWu5cDN0MkLz2qRDD2Ag==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [s390x]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-x64@0.27.7':
|
||||
resolution: {integrity: sha512-hzznmADPt+OmsYzw1EE33ccA+HPdIqiCRq7cQeL1Jlq2gb1+OyWBkMCrYGBJ+sxVzve2ZJEVeePbLM2iEIZSxA==}
|
||||
'@esbuild/linux-x64@0.28.1':
|
||||
resolution: {integrity: sha512-u/anNYF2mmVOEDwLtnQ1wOr3EZ9sTNGLWrsYGYwHWzGA3Si84IOkHXlbWTD1NB+9/1lcnweYKO54uhxZydNzfA==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/netbsd-arm64@0.27.7':
|
||||
resolution: {integrity: sha512-b6pqtrQdigZBwZxAn1UpazEisvwaIDvdbMbmrly7cDTMFnw/+3lVxxCTGOrkPVnsYIosJJXAsILG9XcQS+Yu6w==}
|
||||
'@esbuild/netbsd-arm64@0.28.1':
|
||||
resolution: {integrity: sha512-oks0DYbLwWMmaakTsCb+zL4E+aHRVLom9IJZOAthMQEPiQmydXHkziYEsGYRx0uNV/IjEKGAV941JzH02pflqw==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm64]
|
||||
os: [netbsd]
|
||||
|
||||
'@esbuild/netbsd-x64@0.27.7':
|
||||
resolution: {integrity: sha512-OfatkLojr6U+WN5EDYuoQhtM+1xco+/6FSzJJnuWiUw5eVcicbyK3dq5EeV/QHT1uy6GoDhGbFpprUiHUYggrw==}
|
||||
'@esbuild/netbsd-x64@0.28.1':
|
||||
resolution: {integrity: sha512-aeL6lAnN89Hz43Mlh1G8ARasbuoYvSITDEx0tHh5b7jJnHcssqgjy9Yx430GDpmCa6OyrKoS0aNRjKundRizGg==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [x64]
|
||||
os: [netbsd]
|
||||
|
||||
'@esbuild/openbsd-arm64@0.27.7':
|
||||
resolution: {integrity: sha512-AFuojMQTxAz75Fo8idVcqoQWEHIXFRbOc1TrVcFSgCZtQfSdc1RXgB3tjOn/krRHENUB4j00bfGjyl2mJrU37A==}
|
||||
'@esbuild/openbsd-arm64@0.28.1':
|
||||
resolution: {integrity: sha512-MEFJe5C3R8pwXdZ5Y21oo6m7ePiS0d9pWucn99O/wvyJZChoIQKrQDxKrGeW8F5+T0okTHesAmDeiHDTIq0V/Q==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm64]
|
||||
os: [openbsd]
|
||||
|
||||
'@esbuild/openbsd-x64@0.27.7':
|
||||
resolution: {integrity: sha512-+A1NJmfM8WNDv5CLVQYJ5PshuRm/4cI6WMZRg1by1GwPIQPCTs1GLEUHwiiQGT5zDdyLiRM/l1G0Pv54gvtKIg==}
|
||||
'@esbuild/openbsd-x64@0.28.1':
|
||||
resolution: {integrity: sha512-i/ZLIOafE0Z8cI/XANJAixoJL/uRAoS2xOA3rb0xN+KK0K177cMAsQYkzHtBrtMXAKuAc7HGgcWiZ/sRC1Nxgw==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [x64]
|
||||
os: [openbsd]
|
||||
|
||||
'@esbuild/openharmony-arm64@0.27.7':
|
||||
resolution: {integrity: sha512-+KrvYb/C8zA9CU/g0sR6w2RBw7IGc5J2BPnc3dYc5VJxHCSF1yNMxTV5LQ7GuKteQXZtspjFbiuW5/dOj7H4Yw==}
|
||||
'@esbuild/openharmony-arm64@0.28.1':
|
||||
resolution: {integrity: sha512-ge+Z7EXFNt2BO1oAMsVpiQ8EwndV9i1xXerAeTIK7AtPs3bKFXQM7nlRxDSIUIMeueR1CNXxqztLzdNeReKBJg==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm64]
|
||||
os: [openharmony]
|
||||
|
||||
'@esbuild/sunos-x64@0.27.7':
|
||||
resolution: {integrity: sha512-ikktIhFBzQNt/QDyOL580ti9+5mL/YZeUPKU2ivGtGjdTYoqz6jObj6nOMfhASpS4GU4Q/Clh1QtxWAvcYKamA==}
|
||||
'@esbuild/sunos-x64@0.28.1':
|
||||
resolution: {integrity: sha512-BEjgtECkL3vY+SaSQ6nzVfiALUeFxpawyp8Jmf5PtYhf1Ug40N1h/hxlhts+f1FvSvarEigdxS3BlSMI2PJLcQ==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [x64]
|
||||
os: [sunos]
|
||||
|
||||
'@esbuild/win32-arm64@0.27.7':
|
||||
resolution: {integrity: sha512-7yRhbHvPqSpRUV7Q20VuDwbjW5kIMwTHpptuUzV+AA46kiPze5Z7qgt6CLCK3pWFrHeNfDd1VKgyP4O+ng17CA==}
|
||||
'@esbuild/win32-arm64@0.28.1':
|
||||
resolution: {integrity: sha512-lCv9eK/H6ZJWbE7bh2nw54CZ9M2nupBxJcTsdk/QQnWkdSjKGuxmmH8/GWrlT1eMmZfn4dGcCjRte397WqfQXA==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm64]
|
||||
os: [win32]
|
||||
|
||||
'@esbuild/win32-ia32@0.27.7':
|
||||
resolution: {integrity: sha512-SmwKXe6VHIyZYbBLJrhOoCJRB/Z1tckzmgTLfFYOfpMAx63BJEaL9ExI8x7v0oAO3Zh6D/Oi1gVxEYr5oUCFhw==}
|
||||
'@esbuild/win32-ia32@0.28.1':
|
||||
resolution: {integrity: sha512-zvb/mB2bSCoJOpoCBgYKKpX6YM6mJBlBUVUtVj41DlZJVEB6/0CKlRYxP5wWl1C1ILiCoAU5wZZ4q1P3qeS6Eg==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [ia32]
|
||||
os: [win32]
|
||||
|
||||
'@esbuild/win32-x64@0.27.7':
|
||||
resolution: {integrity: sha512-56hiAJPhwQ1R4i+21FVF7V8kSD5zZTdHcVuRFMW0hn753vVfQN8xlx4uOPT4xoGH0Z/oVATuR82AiqSTDIpaHg==}
|
||||
'@esbuild/win32-x64@0.28.1':
|
||||
resolution: {integrity: sha512-bm4Mowrv+GXMlpWX++EcXw/iLyd1o3+bJkC2DkWXYVvgZCqD/bSj9ctZeAMC3cIxgjRVR2Dufaiu4YPxr5gW1A==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [x64]
|
||||
os: [win32]
|
||||
@@ -879,7 +880,7 @@ packages:
|
||||
resolution: {integrity: sha512-3WrrOuZiyaaZPWiEt4G3+IffISVC9HYlWueJEBWED4ZH4aIAC2PnkdnuRrR94M+w6yGWn4AglWtJtBI8YqvgoA==}
|
||||
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
|
||||
peerDependencies:
|
||||
esbuild: '>=0.18'
|
||||
esbuild: '>=0.28.1'
|
||||
|
||||
cac@6.7.14:
|
||||
resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==}
|
||||
@@ -1035,8 +1036,8 @@ packages:
|
||||
resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
esbuild@0.27.7:
|
||||
resolution: {integrity: sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w==}
|
||||
esbuild@0.28.1:
|
||||
resolution: {integrity: sha512-HrJrvZv5ayxBzPfwphOoNzkzOIIlifzk0KJrGK2c8R4+LKpMtpYLQeUdjnwjWv/LZlkH2laZk+4w78pi99D4Vw==}
|
||||
engines: {node: '>=18'}
|
||||
hasBin: true
|
||||
|
||||
@@ -2016,7 +2017,7 @@ packages:
|
||||
peerDependencies:
|
||||
'@types/node': ^20.19.0 || >=22.12.0
|
||||
'@vitejs/devtools': ^0.1.18
|
||||
esbuild: ^0.27.0 || ^0.28.0
|
||||
esbuild: '>=0.28.1'
|
||||
jiti: '>=1.21.0'
|
||||
less: ^4.0.0
|
||||
sass: ^1.70.0
|
||||
@@ -2323,82 +2324,82 @@ snapshots:
|
||||
tslib: 2.8.1
|
||||
optional: true
|
||||
|
||||
'@esbuild/aix-ppc64@0.27.7':
|
||||
'@esbuild/aix-ppc64@0.28.1':
|
||||
optional: true
|
||||
|
||||
'@esbuild/android-arm64@0.27.7':
|
||||
'@esbuild/android-arm64@0.28.1':
|
||||
optional: true
|
||||
|
||||
'@esbuild/android-arm@0.27.7':
|
||||
'@esbuild/android-arm@0.28.1':
|
||||
optional: true
|
||||
|
||||
'@esbuild/android-x64@0.27.7':
|
||||
'@esbuild/android-x64@0.28.1':
|
||||
optional: true
|
||||
|
||||
'@esbuild/darwin-arm64@0.27.7':
|
||||
'@esbuild/darwin-arm64@0.28.1':
|
||||
optional: true
|
||||
|
||||
'@esbuild/darwin-x64@0.27.7':
|
||||
'@esbuild/darwin-x64@0.28.1':
|
||||
optional: true
|
||||
|
||||
'@esbuild/freebsd-arm64@0.27.7':
|
||||
'@esbuild/freebsd-arm64@0.28.1':
|
||||
optional: true
|
||||
|
||||
'@esbuild/freebsd-x64@0.27.7':
|
||||
'@esbuild/freebsd-x64@0.28.1':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-arm64@0.27.7':
|
||||
'@esbuild/linux-arm64@0.28.1':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-arm@0.27.7':
|
||||
'@esbuild/linux-arm@0.28.1':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-ia32@0.27.7':
|
||||
'@esbuild/linux-ia32@0.28.1':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-loong64@0.27.7':
|
||||
'@esbuild/linux-loong64@0.28.1':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-mips64el@0.27.7':
|
||||
'@esbuild/linux-mips64el@0.28.1':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-ppc64@0.27.7':
|
||||
'@esbuild/linux-ppc64@0.28.1':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-riscv64@0.27.7':
|
||||
'@esbuild/linux-riscv64@0.28.1':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-s390x@0.27.7':
|
||||
'@esbuild/linux-s390x@0.28.1':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-x64@0.27.7':
|
||||
'@esbuild/linux-x64@0.28.1':
|
||||
optional: true
|
||||
|
||||
'@esbuild/netbsd-arm64@0.27.7':
|
||||
'@esbuild/netbsd-arm64@0.28.1':
|
||||
optional: true
|
||||
|
||||
'@esbuild/netbsd-x64@0.27.7':
|
||||
'@esbuild/netbsd-x64@0.28.1':
|
||||
optional: true
|
||||
|
||||
'@esbuild/openbsd-arm64@0.27.7':
|
||||
'@esbuild/openbsd-arm64@0.28.1':
|
||||
optional: true
|
||||
|
||||
'@esbuild/openbsd-x64@0.27.7':
|
||||
'@esbuild/openbsd-x64@0.28.1':
|
||||
optional: true
|
||||
|
||||
'@esbuild/openharmony-arm64@0.27.7':
|
||||
'@esbuild/openharmony-arm64@0.28.1':
|
||||
optional: true
|
||||
|
||||
'@esbuild/sunos-x64@0.27.7':
|
||||
'@esbuild/sunos-x64@0.28.1':
|
||||
optional: true
|
||||
|
||||
'@esbuild/win32-arm64@0.27.7':
|
||||
'@esbuild/win32-arm64@0.28.1':
|
||||
optional: true
|
||||
|
||||
'@esbuild/win32-ia32@0.27.7':
|
||||
'@esbuild/win32-ia32@0.28.1':
|
||||
optional: true
|
||||
|
||||
'@esbuild/win32-x64@0.27.7':
|
||||
'@esbuild/win32-x64@0.28.1':
|
||||
optional: true
|
||||
|
||||
'@google/genai@1.52.0':
|
||||
@@ -2779,7 +2780,7 @@ snapshots:
|
||||
obug: 2.1.2
|
||||
std-env: 4.1.0
|
||||
tinyrainbow: 3.1.0
|
||||
vitest: 4.1.8(@types/node@22.19.20)(@vitest/coverage-v8@4.1.8)(vite@8.0.16(@types/node@22.19.20)(esbuild@0.27.7))
|
||||
vitest: 4.1.8(@types/node@22.19.20)(@vitest/coverage-v8@4.1.8)(vite@8.0.16(@types/node@22.19.20)(esbuild@0.28.1))
|
||||
|
||||
'@vitest/expect@4.1.8':
|
||||
dependencies:
|
||||
@@ -2790,13 +2791,13 @@ snapshots:
|
||||
chai: 6.2.2
|
||||
tinyrainbow: 3.1.0
|
||||
|
||||
'@vitest/mocker@4.1.8(vite@8.0.16(@types/node@22.19.20)(esbuild@0.27.7))':
|
||||
'@vitest/mocker@4.1.8(vite@8.0.16(@types/node@22.19.20)(esbuild@0.28.1))':
|
||||
dependencies:
|
||||
'@vitest/spy': 4.1.8
|
||||
estree-walker: 3.0.3
|
||||
magic-string: 0.30.21
|
||||
optionalDependencies:
|
||||
vite: 8.0.16(@types/node@22.19.20)(esbuild@0.27.7)
|
||||
vite: 8.0.16(@types/node@22.19.20)(esbuild@0.28.1)
|
||||
|
||||
'@vitest/pretty-format@4.1.8':
|
||||
dependencies:
|
||||
@@ -2914,9 +2915,9 @@ snapshots:
|
||||
dependencies:
|
||||
run-applescript: 7.1.0
|
||||
|
||||
bundle-require@5.1.0(esbuild@0.27.7):
|
||||
bundle-require@5.1.0(esbuild@0.28.1):
|
||||
dependencies:
|
||||
esbuild: 0.27.7
|
||||
esbuild: 0.28.1
|
||||
load-tsconfig: 0.2.5
|
||||
|
||||
cac@6.7.14: {}
|
||||
@@ -3050,34 +3051,34 @@ snapshots:
|
||||
has-tostringtag: 1.0.2
|
||||
hasown: 2.0.4
|
||||
|
||||
esbuild@0.27.7:
|
||||
esbuild@0.28.1:
|
||||
optionalDependencies:
|
||||
'@esbuild/aix-ppc64': 0.27.7
|
||||
'@esbuild/android-arm': 0.27.7
|
||||
'@esbuild/android-arm64': 0.27.7
|
||||
'@esbuild/android-x64': 0.27.7
|
||||
'@esbuild/darwin-arm64': 0.27.7
|
||||
'@esbuild/darwin-x64': 0.27.7
|
||||
'@esbuild/freebsd-arm64': 0.27.7
|
||||
'@esbuild/freebsd-x64': 0.27.7
|
||||
'@esbuild/linux-arm': 0.27.7
|
||||
'@esbuild/linux-arm64': 0.27.7
|
||||
'@esbuild/linux-ia32': 0.27.7
|
||||
'@esbuild/linux-loong64': 0.27.7
|
||||
'@esbuild/linux-mips64el': 0.27.7
|
||||
'@esbuild/linux-ppc64': 0.27.7
|
||||
'@esbuild/linux-riscv64': 0.27.7
|
||||
'@esbuild/linux-s390x': 0.27.7
|
||||
'@esbuild/linux-x64': 0.27.7
|
||||
'@esbuild/netbsd-arm64': 0.27.7
|
||||
'@esbuild/netbsd-x64': 0.27.7
|
||||
'@esbuild/openbsd-arm64': 0.27.7
|
||||
'@esbuild/openbsd-x64': 0.27.7
|
||||
'@esbuild/openharmony-arm64': 0.27.7
|
||||
'@esbuild/sunos-x64': 0.27.7
|
||||
'@esbuild/win32-arm64': 0.27.7
|
||||
'@esbuild/win32-ia32': 0.27.7
|
||||
'@esbuild/win32-x64': 0.27.7
|
||||
'@esbuild/aix-ppc64': 0.28.1
|
||||
'@esbuild/android-arm': 0.28.1
|
||||
'@esbuild/android-arm64': 0.28.1
|
||||
'@esbuild/android-x64': 0.28.1
|
||||
'@esbuild/darwin-arm64': 0.28.1
|
||||
'@esbuild/darwin-x64': 0.28.1
|
||||
'@esbuild/freebsd-arm64': 0.28.1
|
||||
'@esbuild/freebsd-x64': 0.28.1
|
||||
'@esbuild/linux-arm': 0.28.1
|
||||
'@esbuild/linux-arm64': 0.28.1
|
||||
'@esbuild/linux-ia32': 0.28.1
|
||||
'@esbuild/linux-loong64': 0.28.1
|
||||
'@esbuild/linux-mips64el': 0.28.1
|
||||
'@esbuild/linux-ppc64': 0.28.1
|
||||
'@esbuild/linux-riscv64': 0.28.1
|
||||
'@esbuild/linux-s390x': 0.28.1
|
||||
'@esbuild/linux-x64': 0.28.1
|
||||
'@esbuild/netbsd-arm64': 0.28.1
|
||||
'@esbuild/netbsd-x64': 0.28.1
|
||||
'@esbuild/openbsd-arm64': 0.28.1
|
||||
'@esbuild/openbsd-x64': 0.28.1
|
||||
'@esbuild/openharmony-arm64': 0.28.1
|
||||
'@esbuild/sunos-x64': 0.28.1
|
||||
'@esbuild/win32-arm64': 0.28.1
|
||||
'@esbuild/win32-ia32': 0.28.1
|
||||
'@esbuild/win32-x64': 0.28.1
|
||||
|
||||
escape-string-regexp@2.0.0: {}
|
||||
|
||||
@@ -4021,12 +4022,12 @@ snapshots:
|
||||
|
||||
tsup@8.5.1(postcss@8.5.15)(typescript@5.9.3):
|
||||
dependencies:
|
||||
bundle-require: 5.1.0(esbuild@0.27.7)
|
||||
bundle-require: 5.1.0(esbuild@0.28.1)
|
||||
cac: 6.7.14
|
||||
chokidar: 4.0.3
|
||||
consola: 3.4.2
|
||||
debug: 4.4.3
|
||||
esbuild: 0.27.7
|
||||
esbuild: 0.28.1
|
||||
fix-dts-default-cjs-exports: 1.0.1
|
||||
joycon: 3.1.1
|
||||
picocolors: 1.1.1
|
||||
@@ -4069,7 +4070,7 @@ snapshots:
|
||||
|
||||
uuid@14.0.0: {}
|
||||
|
||||
vite@8.0.16(@types/node@22.19.20)(esbuild@0.27.7):
|
||||
vite@8.0.16(@types/node@22.19.20)(esbuild@0.28.1):
|
||||
dependencies:
|
||||
lightningcss: 1.32.0
|
||||
picomatch: 4.0.4
|
||||
@@ -4078,13 +4079,13 @@ snapshots:
|
||||
tinyglobby: 0.2.17
|
||||
optionalDependencies:
|
||||
'@types/node': 22.19.20
|
||||
esbuild: 0.27.7
|
||||
esbuild: 0.28.1
|
||||
fsevents: 2.3.3
|
||||
|
||||
vitest@4.1.8(@types/node@22.19.20)(@vitest/coverage-v8@4.1.8)(vite@8.0.16(@types/node@22.19.20)(esbuild@0.27.7)):
|
||||
vitest@4.1.8(@types/node@22.19.20)(@vitest/coverage-v8@4.1.8)(vite@8.0.16(@types/node@22.19.20)(esbuild@0.28.1)):
|
||||
dependencies:
|
||||
'@vitest/expect': 4.1.8
|
||||
'@vitest/mocker': 4.1.8(vite@8.0.16(@types/node@22.19.20)(esbuild@0.27.7))
|
||||
'@vitest/mocker': 4.1.8(vite@8.0.16(@types/node@22.19.20)(esbuild@0.28.1))
|
||||
'@vitest/pretty-format': 4.1.8
|
||||
'@vitest/runner': 4.1.8
|
||||
'@vitest/snapshot': 4.1.8
|
||||
@@ -4101,7 +4102,7 @@ snapshots:
|
||||
tinyexec: 1.2.4
|
||||
tinyglobby: 0.2.17
|
||||
tinyrainbow: 3.1.0
|
||||
vite: 8.0.16(@types/node@22.19.20)(esbuild@0.27.7)
|
||||
vite: 8.0.16(@types/node@22.19.20)(esbuild@0.28.1)
|
||||
why-is-node-running: 2.3.0
|
||||
optionalDependencies:
|
||||
'@types/node': 22.19.20
|
||||
|
||||
@@ -19,3 +19,4 @@ overrides:
|
||||
"picomatch@<2.3.2": "^2.3.2"
|
||||
"@qdrant/js-client-rest": "^1.18.0"
|
||||
"uuid@<11.1.1": ">=11.1.1"
|
||||
"esbuild": ">=0.28.1"
|
||||
|
||||
@@ -2,7 +2,12 @@
|
||||
* Tests for path traversal prevention in skill-loader.
|
||||
*/
|
||||
import { describe, it, expect } from "vitest";
|
||||
import { safePath, loadSkill } from "./skill-loader.ts";
|
||||
import {
|
||||
safePath,
|
||||
loadSkill,
|
||||
loadTriagePrompt,
|
||||
loadCompactTriagePrompt,
|
||||
} from "./skill-loader.ts";
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// safePath — path containment
|
||||
@@ -68,3 +73,71 @@ describe("loadSkill path traversal", () => {
|
||||
expect(result?.prompt).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
describe("loadCompactTriagePrompt", () => {
|
||||
it("keeps the core triage instructions without inlining the full skill body", () => {
|
||||
const prompt = loadCompactTriagePrompt();
|
||||
|
||||
expect(prompt).toContain("Use `memory_add` tool for ALL user facts");
|
||||
expect(prompt).toContain("Batch facts by CATEGORY");
|
||||
expect(prompt).toContain("ALWAYS rewrite the query");
|
||||
expect(prompt).not.toContain("## Worked Examples");
|
||||
expect(prompt).not.toContain("### memory_search");
|
||||
expect(prompt).not.toContain("Conference requires at least 4 breakout rooms");
|
||||
expect(prompt.length).toBeLessThan(3500);
|
||||
});
|
||||
|
||||
it("keeps the always-recall guidance aligned with the full triage prompt", () => {
|
||||
const config = { recall: { strategy: "always" as const } };
|
||||
const expected =
|
||||
"Automatic recall runs for both long-term and session memory. Use manual searches only when you need more specific context.";
|
||||
|
||||
expect(loadCompactTriagePrompt(config)).toContain(expected);
|
||||
expect(loadTriagePrompt(config)).toContain(expected);
|
||||
});
|
||||
|
||||
it("keeps the manual-recall guidance in compact mode", () => {
|
||||
const prompt = loadCompactTriagePrompt({
|
||||
recall: { strategy: "manual" },
|
||||
});
|
||||
|
||||
expect(prompt).toContain("No automatic recall happens in manual mode.");
|
||||
});
|
||||
|
||||
it("includes short config summaries and truncates oversized custom rules", () => {
|
||||
const prompt = loadCompactTriagePrompt({
|
||||
categories: {
|
||||
travel: { importance: 0.7, ttl: "30d" },
|
||||
},
|
||||
customRules: {
|
||||
include: [
|
||||
"Always remember workshop venue requirements.",
|
||||
"Keep track of recurring conference planning constraints.",
|
||||
"Capture every catering preference, transit note, and presenter dependency in detail.",
|
||||
],
|
||||
exclude: [
|
||||
"Never store one-off demo logs, temporary ETA chatter, or transitory checklist updates.",
|
||||
"Skip verbose retrospectives unless the user explicitly says the lesson should persist.",
|
||||
],
|
||||
},
|
||||
});
|
||||
|
||||
expect(prompt).toContain("travel (importance 0.7, expires: 30d)");
|
||||
expect(prompt).toContain("include rule(s) and 2 exclude rule(s) are configured");
|
||||
expect(prompt).toContain("Prompt kept compact, full rule text omitted");
|
||||
expect(prompt).toContain('Preview: include "Always remember workshop venue requirements."');
|
||||
});
|
||||
|
||||
it("omits default credential patterns in compact mode unless custom patterns are configured", () => {
|
||||
const defaultPrompt = loadCompactTriagePrompt();
|
||||
const customPrompt = loadCompactTriagePrompt({
|
||||
triage: {
|
||||
credentialPatterns: ["mem0-secret=", "Bearer "],
|
||||
},
|
||||
});
|
||||
|
||||
expect(defaultPrompt).not.toContain("Credential patterns to scan");
|
||||
expect(customPrompt).toContain("Credential patterns to scan");
|
||||
expect(customPrompt).toContain("mem0-secret=");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -191,8 +191,16 @@ function renderCategoriesBlock(
|
||||
return lines.join("\n");
|
||||
}
|
||||
|
||||
function renderTriageKnobs(config: SkillsConfig): string {
|
||||
function renderTriageKnobs(
|
||||
config: SkillsConfig,
|
||||
options: {
|
||||
includeCredentialPatterns?: boolean;
|
||||
includeDefaultCredentialPatterns?: boolean;
|
||||
} = {},
|
||||
): string {
|
||||
const lines: string[] = [];
|
||||
const includeCredentialPatterns = options.includeCredentialPatterns ?? true;
|
||||
const includeDefaultCredentialPatterns = options.includeDefaultCredentialPatterns ?? true;
|
||||
|
||||
if (config.triage?.importanceThreshold !== undefined) {
|
||||
lines.push(
|
||||
@@ -200,13 +208,82 @@ function renderTriageKnobs(config: SkillsConfig): string {
|
||||
);
|
||||
}
|
||||
|
||||
const patterns = resolveCredentialPatterns(config);
|
||||
lines.push(`- Credential patterns to scan: ${patterns.map((p) => `\`${p}\``).join(", ")}`);
|
||||
const hasCustomCredentialPatterns = config.triage?.credentialPatterns !== undefined;
|
||||
if (includeCredentialPatterns && (includeDefaultCredentialPatterns || hasCustomCredentialPatterns)) {
|
||||
const patterns = resolveCredentialPatterns(config);
|
||||
lines.push(`- Credential patterns to scan: ${patterns.map((p) => `\`${p}\``).join(", ")}`);
|
||||
}
|
||||
|
||||
if (lines.length === 0) return "";
|
||||
return "\n## Active Configuration Overrides\n\n" + lines.join("\n");
|
||||
}
|
||||
|
||||
const COMPACT_CUSTOM_RULE_CHAR_BUDGET = 280;
|
||||
const COMPACT_CUSTOM_RULE_PREVIEW_LIMIT = 2;
|
||||
|
||||
function formatCategoryConfig(
|
||||
name: string,
|
||||
cat: CategoryConfig,
|
||||
): string {
|
||||
const ttlLabel = cat.ttl ? `expires: ${cat.ttl}` : "permanent";
|
||||
const immLabel = cat.immutable ? ", immutable" : "";
|
||||
return `${name} (importance ${cat.importance}, ${ttlLabel}${immLabel})`;
|
||||
}
|
||||
|
||||
function renderCompactCategories(config: SkillsConfig): string[] {
|
||||
if (!config.categories || Object.keys(config.categories).length === 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const mergedCategories = resolveCategories(config);
|
||||
return [
|
||||
"## Active Category Overrides",
|
||||
"",
|
||||
...Object.entries(config.categories).map(([name]) =>
|
||||
`- ${formatCategoryConfig(name, mergedCategories[name]!)}`,
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
function renderCompactCustomRules(config: SkillsConfig): string[] {
|
||||
const includeRules = config.customRules?.include ?? [];
|
||||
const excludeRules = config.customRules?.exclude ?? [];
|
||||
if (includeRules.length === 0 && excludeRules.length === 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const formatRuleList = (label: string, rules: string[]) =>
|
||||
`${label}: ${rules.map((rule) => `"${rule}"`).join("; ")}`;
|
||||
|
||||
const lines: string[] = [];
|
||||
if (includeRules.length > 0) {
|
||||
lines.push(formatRuleList("Include", includeRules));
|
||||
}
|
||||
if (excludeRules.length > 0) {
|
||||
lines.push(formatRuleList("Exclude", excludeRules));
|
||||
}
|
||||
|
||||
const combined = lines.join(" ");
|
||||
if (combined.length <= COMPACT_CUSTOM_RULE_CHAR_BUDGET) {
|
||||
return ["## Active Custom Rules", "", ...lines.map((line) => `- ${line}`)];
|
||||
}
|
||||
|
||||
const preview = [
|
||||
...includeRules.slice(0, COMPACT_CUSTOM_RULE_PREVIEW_LIMIT).map((rule) => `include "${rule}"`),
|
||||
...excludeRules.slice(0, COMPACT_CUSTOM_RULE_PREVIEW_LIMIT).map((rule) => `exclude "${rule}"`),
|
||||
];
|
||||
|
||||
return [
|
||||
"## Active Custom Rules",
|
||||
"",
|
||||
`- ${includeRules.length} include rule(s) and ${excludeRules.length} exclude rule(s) are configured.`,
|
||||
`- Prompt kept compact, full rule text omitted because it exceeded ${COMPACT_CUSTOM_RULE_CHAR_BUDGET} characters.`,
|
||||
...(preview.length > 0
|
||||
? [`- Preview: ${preview.join("; ")}`]
|
||||
: []),
|
||||
];
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// TTL Helpers
|
||||
// ============================================================================
|
||||
@@ -358,6 +435,11 @@ export function loadTriagePrompt(config: SkillsConfig = {}): string {
|
||||
"- Before updating a memory, search to find the existing version.",
|
||||
);
|
||||
parts.push("");
|
||||
} else if (strategy === "always") {
|
||||
parts.push(
|
||||
"Automatic recall runs for both long-term and session memory. Use manual searches only when you need more specific context.",
|
||||
);
|
||||
parts.push("");
|
||||
}
|
||||
|
||||
parts.push(
|
||||
@@ -453,6 +535,122 @@ export function loadTriagePrompt(config: SkillsConfig = {}): string {
|
||||
return parts.join("\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a compact memory system prompt for skills mode turns.
|
||||
*
|
||||
* This keeps the required storage and search protocol, plus short config
|
||||
* summaries, without inlining the full memory-triage skill body every turn.
|
||||
* If the skill file cannot be read, delegate to loadTriagePrompt(), which has
|
||||
* its own minimal inline fallback.
|
||||
*/
|
||||
export function loadCompactTriagePrompt(config: SkillsConfig = {}): string {
|
||||
if (!readSkillFile("memory-triage")) {
|
||||
return loadTriagePrompt(config);
|
||||
}
|
||||
|
||||
const parts: string[] = [];
|
||||
parts.push("<memory-system>");
|
||||
parts.push(
|
||||
"IMPORTANT: Use `memory_add` tool for ALL user facts. NEVER write user info to workspace files (USER.md, memory/).",
|
||||
);
|
||||
parts.push(
|
||||
"After every response, evaluate whether a new agent would benefit from remembering this days later. Most turns should produce zero memory operations.",
|
||||
);
|
||||
parts.push(
|
||||
"Only store durable, self-contained, third-person facts: identity, preferences with rationale, standing rules, decisions, projects, configurations, technical context, and relationships.",
|
||||
);
|
||||
parts.push(
|
||||
"Never store credentials, tokens, webhook secrets, or raw tool output. If a secret was configured, store only that the credential was configured.",
|
||||
);
|
||||
parts.push(
|
||||
"When a recalled fact materially changes, search for the existing memory and update it in place. Skip cosmetic rewording.",
|
||||
);
|
||||
parts.push("");
|
||||
parts.push("## Tool Usage");
|
||||
parts.push("");
|
||||
parts.push(
|
||||
"Batch facts by CATEGORY. All facts in one memory_add call must share the same category because category determines retention policy (TTL, immutability). If a turn has facts in different categories, make one call per category.",
|
||||
);
|
||||
parts.push(
|
||||
'Format: memory_add(facts: ["User is Alex, backend engineer at Stripe, PST timezone"], category: "identity")',
|
||||
);
|
||||
parts.push(
|
||||
'Mixed categories: memory_add(..., category: "identity") and memory_add(..., category: "decision") in separate calls.',
|
||||
);
|
||||
parts.push(
|
||||
"Categories: identity, configuration, rule, preference, decision, technical, relationship, project.",
|
||||
);
|
||||
|
||||
const categoryLines = renderCompactCategories(config);
|
||||
if (categoryLines.length > 0) {
|
||||
parts.push("");
|
||||
parts.push(...categoryLines);
|
||||
}
|
||||
|
||||
const knobLines = renderTriageKnobs(config, {
|
||||
includeDefaultCredentialPatterns: false,
|
||||
})
|
||||
.split("\n")
|
||||
.filter(Boolean);
|
||||
if (knobLines.length > 0) {
|
||||
parts.push("");
|
||||
parts.push(...knobLines);
|
||||
}
|
||||
|
||||
const customRuleLines = renderCompactCustomRules(config);
|
||||
if (customRuleLines.length > 0) {
|
||||
parts.push("");
|
||||
parts.push(...customRuleLines);
|
||||
}
|
||||
|
||||
if (config.recall?.enabled !== false) {
|
||||
const strategy = config.recall?.strategy ?? "smart";
|
||||
parts.push("");
|
||||
parts.push("## Searching Memory");
|
||||
parts.push("");
|
||||
|
||||
if (strategy === "manual") {
|
||||
parts.push(
|
||||
"No automatic recall happens in manual mode. Use memory_search proactively at conversation start, when context is missing, when topics shift, and before updating a memory.",
|
||||
);
|
||||
} else if (strategy === "always") {
|
||||
parts.push(
|
||||
"Automatic recall runs for both long-term and session memory. Use manual searches only when you need more specific context.",
|
||||
);
|
||||
} else {
|
||||
parts.push(
|
||||
"Automatic recall runs for long-term memory. Use manual searches when the injected context is not enough.",
|
||||
);
|
||||
}
|
||||
|
||||
parts.push(
|
||||
"When calling memory_search, ALWAYS rewrite the query. NEVER pass the user's raw message.",
|
||||
);
|
||||
parts.push(
|
||||
"Convert the request into 3-6 factual keywords that match stored memory language: user, decided, prefers, rule, configured, based in, plus the concrete nouns and names from the request.",
|
||||
);
|
||||
parts.push(
|
||||
'WRONG: memory_search("Who was that nutritionist my wife recommended?")',
|
||||
);
|
||||
parts.push(
|
||||
'RIGHT: memory_search("nutritionist wife recommended relationship")',
|
||||
);
|
||||
parts.push('WRONG: memory_search("What timezone am I in?")');
|
||||
parts.push('RIGHT: memory_search("user timezone location based")');
|
||||
// Intentionally omitted from the compact path: ENTITY SCOPING and SEARCH SCOPE.
|
||||
// loadTriagePrompt() keeps the full explanatory sections for the non-compact path.
|
||||
parts.push(
|
||||
'Scope: use "long-term" for durable user context, "session" for this conversation, and "all" only when you truly need both.',
|
||||
);
|
||||
parts.push(
|
||||
"When the request implies a time range or category, add filters or categories instead of broadening the query text.",
|
||||
);
|
||||
}
|
||||
|
||||
parts.push("</memory-system>");
|
||||
return parts.join("\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the dream skill prompt for consolidation sessions.
|
||||
*/
|
||||
|
||||
@@ -71,7 +71,8 @@
|
||||
},
|
||||
"pnpm": {
|
||||
"overrides": {
|
||||
"uuid@<11.1.1": ">=11.1.1"
|
||||
"uuid@<11.1.1": ">=11.1.1",
|
||||
"esbuild": ">=0.28.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+189
-124
@@ -6,6 +6,7 @@ settings:
|
||||
|
||||
overrides:
|
||||
uuid@<11.1.1: '>=11.1.1'
|
||||
esbuild: '>=0.28.1'
|
||||
|
||||
importers:
|
||||
|
||||
@@ -13,7 +14,7 @@ importers:
|
||||
dependencies:
|
||||
mem0ai:
|
||||
specifier: ^3.0.7
|
||||
version: 3.0.7(@anthropic-ai/sdk@0.91.1(zod@3.25.76))(@azure/identity@4.13.1)(@azure/search-documents@12.2.0)(@cloudflare/workers-types@4.20260610.1)(@google/genai@1.52.0)(@langchain/core@1.1.48(openai@6.26.0(ws@8.21.0)(zod@3.25.76))(ws@8.21.0))(@mistralai/mistralai@2.2.1)(@qdrant/js-client-rest@1.18.0(typescript@6.0.3))(@supabase/supabase-js@2.108.1)(@types/jest@29.5.14)(@types/pg@8.11.0)(better-sqlite3@12.10.0)(cloudflare@4.5.0)(compromise@14.15.1)(groq-sdk@0.3.0)(natural@8.1.1)(ollama@0.5.18)(pg@8.21.0)(redis@5.12.1)(ws@8.21.0)
|
||||
version: 3.0.7(@anthropic-ai/sdk@0.91.1(zod@3.25.76))(@azure/identity@4.13.1)(@azure/search-documents@12.2.0)(@cloudflare/workers-types@4.20260610.1)(@google/genai@1.52.0)(@langchain/core@1.1.48(openai@6.26.0(ws@8.21.0)(zod@3.25.76))(ws@8.21.0))(@mistralai/mistralai@2.2.1)(@qdrant/js-client-rest@1.18.0(typescript@6.0.3))(@supabase/supabase-js@2.108.1)(@types/jest@29.5.14)(@types/pg@8.11.0)(better-sqlite3@12.10.0)(cloudflare@4.5.0)(compromise@14.15.1)(groq-sdk@0.3.0)(natural@8.1.1)(ollama@0.5.18)(pg@8.11.3)(redis@5.12.1)(ws@8.21.0)
|
||||
devDependencies:
|
||||
'@earendil-works/pi-ai':
|
||||
specifier: ^0.79.0
|
||||
@@ -35,7 +36,7 @@ importers:
|
||||
version: 6.0.3
|
||||
vitest:
|
||||
specifier: ^4.1.7
|
||||
version: 4.1.8(@types/node@25.9.2)(vite@8.0.16(@types/node@25.9.2)(esbuild@0.27.7)(jiti@2.7.0)(yaml@2.9.0))
|
||||
version: 4.1.8(@types/node@25.9.2)(vite@8.0.16(@types/node@25.9.2)(esbuild@0.28.1)(jiti@2.7.0)(yaml@2.9.0))
|
||||
|
||||
packages:
|
||||
|
||||
@@ -253,158 +254,158 @@ packages:
|
||||
'@emnapi/wasi-threads@1.2.1':
|
||||
resolution: {integrity: sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==}
|
||||
|
||||
'@esbuild/aix-ppc64@0.27.7':
|
||||
resolution: {integrity: sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg==}
|
||||
'@esbuild/aix-ppc64@0.28.1':
|
||||
resolution: {integrity: sha512-Svl7tq8k/08+p6CXPpRjQ1fKX+1odH/BQbb48fV6fj3CWHhsoIOoY87w1oHXm0qEpkIK3ZfVgp0hed3XBXzXMQ==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [ppc64]
|
||||
os: [aix]
|
||||
|
||||
'@esbuild/android-arm64@0.27.7':
|
||||
resolution: {integrity: sha512-62dPZHpIXzvChfvfLJow3q5dDtiNMkwiRzPylSCfriLvZeq0a1bWChrGx/BbUbPwOrsWKMn8idSllklzBy+dgQ==}
|
||||
'@esbuild/android-arm64@0.28.1':
|
||||
resolution: {integrity: sha512-34EGEbCIAgosYz6goLcopX6Mo7NyGv9tfwEM2/7Ce2VcVRk568iSvniGWcUXIy7wEDR1wzolcxcriFVrWYcwBg==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm64]
|
||||
os: [android]
|
||||
|
||||
'@esbuild/android-arm@0.27.7':
|
||||
resolution: {integrity: sha512-jbPXvB4Yj2yBV7HUfE2KHe4GJX51QplCN1pGbYjvsyCZbQmies29EoJbkEc+vYuU5o45AfQn37vZlyXy4YJ8RQ==}
|
||||
'@esbuild/android-arm@0.28.1':
|
||||
resolution: {integrity: sha512-0k2F129Xdio1TdJfzJ8sy1Q47vUD2NnwdhiAf7drUN1EBTfPf4hsFCtmMgu/6m8JSzsBrlmVjudMBQqOfG8usQ==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm]
|
||||
os: [android]
|
||||
|
||||
'@esbuild/android-x64@0.27.7':
|
||||
resolution: {integrity: sha512-x5VpMODneVDb70PYV2VQOmIUUiBtY3D3mPBG8NxVk5CogneYhkR7MmM3yR/uMdITLrC1ml/NV1rj4bMJuy9MCg==}
|
||||
'@esbuild/android-x64@0.28.1':
|
||||
resolution: {integrity: sha512-dbwY7ltSMDWsRatcRpCnES4F+im88OCUgGZjy52shC7GqHRE/cYlxNbB4Z4UpJswpcc4Qxd2oE/ufM0p61IKng==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [x64]
|
||||
os: [android]
|
||||
|
||||
'@esbuild/darwin-arm64@0.27.7':
|
||||
resolution: {integrity: sha512-5lckdqeuBPlKUwvoCXIgI2D9/ABmPq3Rdp7IfL70393YgaASt7tbju3Ac+ePVi3KDH6N2RqePfHnXkaDtY9fkw==}
|
||||
'@esbuild/darwin-arm64@0.28.1':
|
||||
resolution: {integrity: sha512-TZbWkQY7kvTAXbXUT7uVACR5cMHsDiSz9z7ZKAX/RTq/WJEk3QyRr0wZpNhBDX+/0CtdqUIJlOiodQcta6tY3Q==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm64]
|
||||
os: [darwin]
|
||||
|
||||
'@esbuild/darwin-x64@0.27.7':
|
||||
resolution: {integrity: sha512-rYnXrKcXuT7Z+WL5K980jVFdvVKhCHhUwid+dDYQpH+qu+TefcomiMAJpIiC2EM3Rjtq0sO3StMV/+3w3MyyqQ==}
|
||||
'@esbuild/darwin-x64@0.28.1':
|
||||
resolution: {integrity: sha512-zfdzgK9ACBNZLI/CyHTOx81SyNbM6YXn7rxSgX97VjyiPl9W1i4Ka4fgKECEoFCKGpvBj5qArWIGgQjOwkgskQ==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [x64]
|
||||
os: [darwin]
|
||||
|
||||
'@esbuild/freebsd-arm64@0.27.7':
|
||||
resolution: {integrity: sha512-B48PqeCsEgOtzME2GbNM2roU29AMTuOIN91dsMO30t+Ydis3z/3Ngoj5hhnsOSSwNzS+6JppqWsuhTp6E82l2w==}
|
||||
'@esbuild/freebsd-arm64@0.28.1':
|
||||
resolution: {integrity: sha512-wG2EA8ENdEI0qhkSZMjfqrdY+ziCYCPMmtZjjIwOmXFjmyzEHn+UUxk5of+SYsjtfs3VpnlC7QLzSI5hY/rOAw==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm64]
|
||||
os: [freebsd]
|
||||
|
||||
'@esbuild/freebsd-x64@0.27.7':
|
||||
resolution: {integrity: sha512-jOBDK5XEjA4m5IJK3bpAQF9/Lelu/Z9ZcdhTRLf4cajlB+8VEhFFRjWgfy3M1O4rO2GQ/b2dLwCUGpiF/eATNQ==}
|
||||
'@esbuild/freebsd-x64@0.28.1':
|
||||
resolution: {integrity: sha512-i7dZ9vQgnvSCzi/rYCXNgtF/U+eKZNJBzu3eTQbRgHnM7tNSizLOkRFAl3qzVc/Op/u5YkHHa4pf/3DOYHthLQ==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [x64]
|
||||
os: [freebsd]
|
||||
|
||||
'@esbuild/linux-arm64@0.27.7':
|
||||
resolution: {integrity: sha512-RZPHBoxXuNnPQO9rvjh5jdkRmVizktkT7TCDkDmQ0W2SwHInKCAV95GRuvdSvA7w4VMwfCjUiPwDi0ZO6Nfe9A==}
|
||||
'@esbuild/linux-arm64@0.28.1':
|
||||
resolution: {integrity: sha512-yHs+0uc8+nvEAfAfxrWQKK5peSNzBc4PegcMO0EJ2hT71uA7vB8Ihg2e77R2P7SG5uYjPbHlLLmve4LLLRCf0g==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-arm@0.27.7':
|
||||
resolution: {integrity: sha512-RkT/YXYBTSULo3+af8Ib0ykH8u2MBh57o7q/DAs3lTJlyVQkgQvlrPTnjIzzRPQyavxtPtfg0EopvDyIt0j1rA==}
|
||||
'@esbuild/linux-arm@0.28.1':
|
||||
resolution: {integrity: sha512-qVXBOHQS+d5Y722GwJzJUtOLlX7km3CraOaGormF1pDtPd2C/l1SHRPgjLunLGe51Sh5YYWKMFDyV4SxgMQYTQ==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-ia32@0.27.7':
|
||||
resolution: {integrity: sha512-GA48aKNkyQDbd3KtkplYWT102C5sn/EZTY4XROkxONgruHPU72l+gW+FfF8tf2cFjeHaRbWpOYa/uRBz/Xq1Pg==}
|
||||
'@esbuild/linux-ia32@0.28.1':
|
||||
resolution: {integrity: sha512-d1z4ZuP0ajrfz/FhGT4vv278rX8KnPPJx8i5+AtK7TYbx9Le9F1hyzurZpkEyjkGa9dUGhQow4C1NmeGvqxN2w==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [ia32]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-loong64@0.27.7':
|
||||
resolution: {integrity: sha512-a4POruNM2oWsD4WKvBSEKGIiWQF8fZOAsycHOt6JBpZ+JN2n2JH9WAv56SOyu9X5IqAjqSIPTaJkqN8F7XOQ5Q==}
|
||||
'@esbuild/linux-loong64@0.28.1':
|
||||
resolution: {integrity: sha512-M5sRjUVZrkm1OAPR3dlOYzNmN+loZKGVi1VUQGrwuqLcbR6qeAz+famMhjASeH3YVKvZz+zT1jlh/keC3Rj/lg==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [loong64]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-mips64el@0.27.7':
|
||||
resolution: {integrity: sha512-KabT5I6StirGfIz0FMgl1I+R1H73Gp0ofL9A3nG3i/cYFJzKHhouBV5VWK1CSgKvVaG4q1RNpCTR2LuTVB3fIw==}
|
||||
'@esbuild/linux-mips64el@0.28.1':
|
||||
resolution: {integrity: sha512-mRObBZeHh2OxcBFPWE/FjylkRgZdYuiTR3vaTozquCGOH14iP9oN4x4Ge81CoIDYQrXmIxpFumJBu5MtZpnQJQ==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [mips64el]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-ppc64@0.27.7':
|
||||
resolution: {integrity: sha512-gRsL4x6wsGHGRqhtI+ifpN/vpOFTQtnbsupUF5R5YTAg+y/lKelYR1hXbnBdzDjGbMYjVJLJTd2OFmMewAgwlQ==}
|
||||
'@esbuild/linux-ppc64@0.28.1':
|
||||
resolution: {integrity: sha512-slScBsMAb3GFDcdrCgLwZtPYRoH2H/youv10QiZyRjmsP48fznoveWytSgCI/R0ZcUgpc0ZhIUEx6LHts8yrfQ==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [ppc64]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-riscv64@0.27.7':
|
||||
resolution: {integrity: sha512-hL25LbxO1QOngGzu2U5xeXtxXcW+/GvMN3ejANqXkxZ/opySAZMrc+9LY/WyjAan41unrR3YrmtTsUpwT66InQ==}
|
||||
'@esbuild/linux-riscv64@0.28.1':
|
||||
resolution: {integrity: sha512-kw0owk1o0GFETUJyW0jc0G4Yzs0BHZn0JDZ8JRT088vjJYX777BAs1fDGxAC+q831qOs2DTC96mNsG2opdfyyQ==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [riscv64]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-s390x@0.27.7':
|
||||
resolution: {integrity: sha512-2k8go8Ycu1Kb46vEelhu1vqEP+UeRVj2zY1pSuPdgvbd5ykAw82Lrro28vXUrRmzEsUV0NzCf54yARIK8r0fdw==}
|
||||
'@esbuild/linux-s390x@0.28.1':
|
||||
resolution: {integrity: sha512-/lAIjX8aYFRByhh6L5rYtPEDRqa9de/4V/juOXcta5frjvzXO4/sqEtyytse0g3zZFuWu5cDN0MkLz2qRDD2Ag==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [s390x]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-x64@0.27.7':
|
||||
resolution: {integrity: sha512-hzznmADPt+OmsYzw1EE33ccA+HPdIqiCRq7cQeL1Jlq2gb1+OyWBkMCrYGBJ+sxVzve2ZJEVeePbLM2iEIZSxA==}
|
||||
'@esbuild/linux-x64@0.28.1':
|
||||
resolution: {integrity: sha512-u/anNYF2mmVOEDwLtnQ1wOr3EZ9sTNGLWrsYGYwHWzGA3Si84IOkHXlbWTD1NB+9/1lcnweYKO54uhxZydNzfA==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/netbsd-arm64@0.27.7':
|
||||
resolution: {integrity: sha512-b6pqtrQdigZBwZxAn1UpazEisvwaIDvdbMbmrly7cDTMFnw/+3lVxxCTGOrkPVnsYIosJJXAsILG9XcQS+Yu6w==}
|
||||
'@esbuild/netbsd-arm64@0.28.1':
|
||||
resolution: {integrity: sha512-oks0DYbLwWMmaakTsCb+zL4E+aHRVLom9IJZOAthMQEPiQmydXHkziYEsGYRx0uNV/IjEKGAV941JzH02pflqw==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm64]
|
||||
os: [netbsd]
|
||||
|
||||
'@esbuild/netbsd-x64@0.27.7':
|
||||
resolution: {integrity: sha512-OfatkLojr6U+WN5EDYuoQhtM+1xco+/6FSzJJnuWiUw5eVcicbyK3dq5EeV/QHT1uy6GoDhGbFpprUiHUYggrw==}
|
||||
'@esbuild/netbsd-x64@0.28.1':
|
||||
resolution: {integrity: sha512-aeL6lAnN89Hz43Mlh1G8ARasbuoYvSITDEx0tHh5b7jJnHcssqgjy9Yx430GDpmCa6OyrKoS0aNRjKundRizGg==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [x64]
|
||||
os: [netbsd]
|
||||
|
||||
'@esbuild/openbsd-arm64@0.27.7':
|
||||
resolution: {integrity: sha512-AFuojMQTxAz75Fo8idVcqoQWEHIXFRbOc1TrVcFSgCZtQfSdc1RXgB3tjOn/krRHENUB4j00bfGjyl2mJrU37A==}
|
||||
'@esbuild/openbsd-arm64@0.28.1':
|
||||
resolution: {integrity: sha512-MEFJe5C3R8pwXdZ5Y21oo6m7ePiS0d9pWucn99O/wvyJZChoIQKrQDxKrGeW8F5+T0okTHesAmDeiHDTIq0V/Q==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm64]
|
||||
os: [openbsd]
|
||||
|
||||
'@esbuild/openbsd-x64@0.27.7':
|
||||
resolution: {integrity: sha512-+A1NJmfM8WNDv5CLVQYJ5PshuRm/4cI6WMZRg1by1GwPIQPCTs1GLEUHwiiQGT5zDdyLiRM/l1G0Pv54gvtKIg==}
|
||||
'@esbuild/openbsd-x64@0.28.1':
|
||||
resolution: {integrity: sha512-i/ZLIOafE0Z8cI/XANJAixoJL/uRAoS2xOA3rb0xN+KK0K177cMAsQYkzHtBrtMXAKuAc7HGgcWiZ/sRC1Nxgw==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [x64]
|
||||
os: [openbsd]
|
||||
|
||||
'@esbuild/openharmony-arm64@0.27.7':
|
||||
resolution: {integrity: sha512-+KrvYb/C8zA9CU/g0sR6w2RBw7IGc5J2BPnc3dYc5VJxHCSF1yNMxTV5LQ7GuKteQXZtspjFbiuW5/dOj7H4Yw==}
|
||||
'@esbuild/openharmony-arm64@0.28.1':
|
||||
resolution: {integrity: sha512-ge+Z7EXFNt2BO1oAMsVpiQ8EwndV9i1xXerAeTIK7AtPs3bKFXQM7nlRxDSIUIMeueR1CNXxqztLzdNeReKBJg==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm64]
|
||||
os: [openharmony]
|
||||
|
||||
'@esbuild/sunos-x64@0.27.7':
|
||||
resolution: {integrity: sha512-ikktIhFBzQNt/QDyOL580ti9+5mL/YZeUPKU2ivGtGjdTYoqz6jObj6nOMfhASpS4GU4Q/Clh1QtxWAvcYKamA==}
|
||||
'@esbuild/sunos-x64@0.28.1':
|
||||
resolution: {integrity: sha512-BEjgtECkL3vY+SaSQ6nzVfiALUeFxpawyp8Jmf5PtYhf1Ug40N1h/hxlhts+f1FvSvarEigdxS3BlSMI2PJLcQ==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [x64]
|
||||
os: [sunos]
|
||||
|
||||
'@esbuild/win32-arm64@0.27.7':
|
||||
resolution: {integrity: sha512-7yRhbHvPqSpRUV7Q20VuDwbjW5kIMwTHpptuUzV+AA46kiPze5Z7qgt6CLCK3pWFrHeNfDd1VKgyP4O+ng17CA==}
|
||||
'@esbuild/win32-arm64@0.28.1':
|
||||
resolution: {integrity: sha512-lCv9eK/H6ZJWbE7bh2nw54CZ9M2nupBxJcTsdk/QQnWkdSjKGuxmmH8/GWrlT1eMmZfn4dGcCjRte397WqfQXA==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm64]
|
||||
os: [win32]
|
||||
|
||||
'@esbuild/win32-ia32@0.27.7':
|
||||
resolution: {integrity: sha512-SmwKXe6VHIyZYbBLJrhOoCJRB/Z1tckzmgTLfFYOfpMAx63BJEaL9ExI8x7v0oAO3Zh6D/Oi1gVxEYr5oUCFhw==}
|
||||
'@esbuild/win32-ia32@0.28.1':
|
||||
resolution: {integrity: sha512-zvb/mB2bSCoJOpoCBgYKKpX6YM6mJBlBUVUtVj41DlZJVEB6/0CKlRYxP5wWl1C1ILiCoAU5wZZ4q1P3qeS6Eg==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [ia32]
|
||||
os: [win32]
|
||||
|
||||
'@esbuild/win32-x64@0.27.7':
|
||||
resolution: {integrity: sha512-56hiAJPhwQ1R4i+21FVF7V8kSD5zZTdHcVuRFMW0hn753vVfQN8xlx4uOPT4xoGH0Z/oVATuR82AiqSTDIpaHg==}
|
||||
'@esbuild/win32-x64@0.28.1':
|
||||
resolution: {integrity: sha512-bm4Mowrv+GXMlpWX++EcXw/iLyd1o3+bJkC2DkWXYVvgZCqD/bSj9ctZeAMC3cIxgjRVR2Dufaiu4YPxr5gW1A==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [x64]
|
||||
os: [win32]
|
||||
@@ -469,30 +470,35 @@ packages:
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@mariozechner/clipboard-linux-arm64-musl@0.3.9':
|
||||
resolution: {integrity: sha512-AGuJdgKsmJdm4Pych7kv3sqe591ERRaAHW3xjLooiFzn8J+PxUyof++7YZrB5Y5tpnTO+K18Og3taj2NpluCRQ==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@mariozechner/clipboard-linux-riscv64-gnu@0.3.9':
|
||||
resolution: {integrity: sha512-DXBEAiuMpk7dhS1a9NzNxVAFi1vaKoPu7rQNgY8LIDLGrK3lnIp3nT10DUum+PKVJoJppIP+NAA8IZe4DMNDPw==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [riscv64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@mariozechner/clipboard-linux-x64-gnu@0.3.9':
|
||||
resolution: {integrity: sha512-WORrMLd6EpElEME7JRKfSaY34nW1P5LbdgK5YNCS1ncG2LqmITsSMEJ8nh2mpvxb3TxqbOOKgY7k9eMJYlW9Mw==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@mariozechner/clipboard-linux-x64-musl@0.3.9':
|
||||
resolution: {integrity: sha512-/DHn+1DrfL6oRaPPWXaOKvonFFrni666fxd+zFqiQEfvBH0tsHVWjq9iqBk0oDp0qaPA72lIMy5BptxISBEhZQ==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@mariozechner/clipboard-win32-arm64-msvc@0.3.9':
|
||||
resolution: {integrity: sha512-O5FHD3ErkMwMhNzAfu3ggy0ug4z7btZuoQgwwxlzPrwV2bxlD6WDpqBY4NCgICAgZdDKdp+loUEKVAVt8aYnhQ==}
|
||||
@@ -639,36 +645,42 @@ packages:
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rolldown/binding-linux-arm64-musl@1.0.3':
|
||||
resolution: {integrity: sha512-VWkUHwWriDciit80wleYwKILoR/KMvxh/IdwS/paX+ZgpuRpCrKLUdadJbc0NpBEiyhpYawsJ73j9aCvOH+f7Q==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@rolldown/binding-linux-ppc64-gnu@1.0.3':
|
||||
resolution: {integrity: sha512-5f1laC0SlIR0yDbFCd8acUhvJIag6N3zC5P7oUPN6wX0aOma+uKJ0wBDH5aq7I1PVI2ttTlhJwzwRIBnLiSGEg==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [ppc64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rolldown/binding-linux-s390x-gnu@1.0.3':
|
||||
resolution: {integrity: sha512-Iq4ko0r4XsgbrF/LunNgHtAGLRRVE2kXonAXQ/MV0mC6jQpMOhW1SvtZja2EhC/kd05++bP78dsqBeIQyYJ6Yg==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [s390x]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rolldown/binding-linux-x64-gnu@1.0.3':
|
||||
resolution: {integrity: sha512-B8m6tD5+/N5FeNQFbKlLA/2yVq9ycQP1SeedyEYYKWBNR3ZQbkvIUcNnDNM03lO1l5F2roiiFJGgvoLLyZXtSg==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rolldown/binding-linux-x64-musl@1.0.3':
|
||||
resolution: {integrity: sha512-pSdpdUJHkuCxun9LE7jvgUB9qsRgaiyNNCX7m/AvHTcq67AiT/Yhoxvw5zPfhrM8k/BfP8ce/hMOpthKDpEUow==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@rolldown/binding-openharmony-arm64@1.0.3':
|
||||
resolution: {integrity: sha512-OXXS3RKJgX2uLwM+gYyuH5omcH8fL1LJs96pZGgtetVCahON57+d4SJHzTgZiOjxgGkSnpXpOsWuPDGAKAigEg==}
|
||||
@@ -730,66 +742,79 @@ packages:
|
||||
resolution: {integrity: sha512-Q8CBCCQtDFrYtXoeUXSrnFXKOnyUhx6bz+SkL6A0E7V8kAiCJ5pamq1WtbfpVGhR5TSpXY6ak3avmDc5fHTyJA==}
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rollup/rollup-linux-arm-musleabihf@4.61.1':
|
||||
resolution: {integrity: sha512-nwnhk1581l0FBVellGcVCAT0Oi06onEA3WB53sf01VO3I0UPBkMH9sXONYME2K0ovXcNayJfNtHfm6mpJElatQ==}
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@rollup/rollup-linux-arm64-gnu@4.61.1':
|
||||
resolution: {integrity: sha512-x5Xr49hwt3hdW75UOZm3395YwwzPyauktslv29KpWL/T+vVAzoT3azLcTWv0eMciBNrx+DYjH4paehHoLpPvpg==}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rollup/rollup-linux-arm64-musl@4.61.1':
|
||||
resolution: {integrity: sha512-unMS3H73DpaoPyyEVPjGKleM/s0mkmsauTENpw4INQY8y4+IuLNjkueQ5QCtC0D3N38Y38yhAU8OoZ20S2Tm6w==}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@rollup/rollup-linux-loong64-gnu@4.61.1':
|
||||
resolution: {integrity: sha512-zNZzGRnAhwjFEYmvphJRV5XaQGjs62cCmeYYHUT//NbvEnHauw+I85nGG+SiVg5ld4GX8D1IbKIX+ozITQnhMQ==}
|
||||
cpu: [loong64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rollup/rollup-linux-loong64-musl@4.61.1':
|
||||
resolution: {integrity: sha512-LdpWGL8X209B2SIvWjqlc8VZgM6PKfontSerGepuldQmHYrAOtnMCXeJkxXGbC+PPZVOuu5czJo7fNV6aeW8rQ==}
|
||||
cpu: [loong64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@rollup/rollup-linux-ppc64-gnu@4.61.1':
|
||||
resolution: {integrity: sha512-EC5kTtNaNGOmbMGqar8dvJy6y/hg99GAwjfBz++pxZhQATXGcRjd6c5en5wcbru0vkRmiMGsQKdMJOOf6sza4g==}
|
||||
cpu: [ppc64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rollup/rollup-linux-ppc64-musl@4.61.1':
|
||||
resolution: {integrity: sha512-8hiwp6D4acEcNK78I4rP0/XtS1sknWIAMJBPdR4l6zUtyTm5KiTDr5bXmWt4foY7nAN7AThDHgkLIEZOWKbzWw==}
|
||||
cpu: [ppc64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@rollup/rollup-linux-riscv64-gnu@4.61.1':
|
||||
resolution: {integrity: sha512-10dh/h/BqA7DuMPWSxkR8uks18FRwnwOEqr5zOTEl+NOwP/OMzKX8OFR/Of9xxDA7D5qef1Nzar5WDD2kCCr1g==}
|
||||
cpu: [riscv64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rollup/rollup-linux-riscv64-musl@4.61.1':
|
||||
resolution: {integrity: sha512-YKJ5lg35DP17gcAOggnihe+APw9HLyj1Xn7gsmGumBJAUDa6NGXNixJzmkWLhcK9TOuuyQjdamzvJefkO7qHZQ==}
|
||||
cpu: [riscv64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@rollup/rollup-linux-s390x-gnu@4.61.1':
|
||||
resolution: {integrity: sha512-Mlil5G2Jj6a7B3LWGctg+XPL9vdXYuzCtNXfxOQ0nPjc2m6ueUktocPGH9bnAM0bNRKb/bAWTujUU7IJQdQA+g==}
|
||||
cpu: [s390x]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rollup/rollup-linux-x64-gnu@4.61.1':
|
||||
resolution: {integrity: sha512-bVWIOIk6pV01p4CdUbPP7CJ/434z+OooYjDuFcR+44N35YvKUC66G8MGnvcWx5mWKW3g61J+t74l3Kj15Kwn2Q==}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@rollup/rollup-linux-x64-musl@4.61.1':
|
||||
resolution: {integrity: sha512-qy5pBvZbqNFheBz61R1rzsezjm0J7O2oNGoWtGoY89SZYLUfxAJTBAqDChqAIdB4rCiIbi9nF7yZ83GnNiLwSw==}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@rollup/rollup-openbsd-x64@4.61.1':
|
||||
resolution: {integrity: sha512-E83TXjI4zm0+5f2qO+UOudaCYIhYwpJ5jq6YCZNIZ+6CbfhKrkAGezeiASBL9ElxAxFsRS9ZhESv8mfnj6TKeg==}
|
||||
@@ -1080,6 +1105,10 @@ packages:
|
||||
buffer-equal-constant-time@1.0.1:
|
||||
resolution: {integrity: sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==}
|
||||
|
||||
buffer-writer@2.0.0:
|
||||
resolution: {integrity: sha512-a7ZpuTZU1TRtnwyCNW3I5dc0wWNC3VR9S++Ewyk2HHZdrO3CQJqSpd+95Us590V6AL7JqUAH2IwZ/398PmNFgw==}
|
||||
engines: {node: '>=4'}
|
||||
|
||||
buffer@5.7.1:
|
||||
resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==}
|
||||
|
||||
@@ -1091,7 +1120,7 @@ packages:
|
||||
resolution: {integrity: sha512-3WrrOuZiyaaZPWiEt4G3+IffISVC9HYlWueJEBWED4ZH4aIAC2PnkdnuRrR94M+w6yGWn4AglWtJtBI8YqvgoA==}
|
||||
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
|
||||
peerDependencies:
|
||||
esbuild: '>=0.18'
|
||||
esbuild: '>=0.28.1'
|
||||
|
||||
cac@6.7.14:
|
||||
resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==}
|
||||
@@ -1259,8 +1288,8 @@ packages:
|
||||
resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
esbuild@0.27.7:
|
||||
resolution: {integrity: sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w==}
|
||||
esbuild@0.28.1:
|
||||
resolution: {integrity: sha512-HrJrvZv5ayxBzPfwphOoNzkzOIIlifzk0KJrGK2c8R4+LKpMtpYLQeUdjnwjWv/LZlkH2laZk+4w78pi99D4Vw==}
|
||||
engines: {node: '>=18'}
|
||||
hasBin: true
|
||||
|
||||
@@ -1600,24 +1629,28 @@ packages:
|
||||
engines: {node: '>= 12.0.0'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
lightningcss-linux-arm64-musl@1.32.0:
|
||||
resolution: {integrity: sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==}
|
||||
engines: {node: '>= 12.0.0'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
lightningcss-linux-x64-gnu@1.32.0:
|
||||
resolution: {integrity: sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==}
|
||||
engines: {node: '>= 12.0.0'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
lightningcss-linux-x64-musl@1.32.0:
|
||||
resolution: {integrity: sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==}
|
||||
engines: {node: '>= 12.0.0'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
lightningcss-win32-arm64-msvc@1.32.0:
|
||||
resolution: {integrity: sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==}
|
||||
@@ -1901,6 +1934,9 @@ packages:
|
||||
resolution: {integrity: sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
packet-reader@1.0.0:
|
||||
resolution: {integrity: sha512-HAKu/fG3HpHFO0AA8WE8q2g+gBJaZ9MG7fcKk+IJPLTGAD6Psw4443l+9DGRbOIh3/aXr7Phy0TjilYivJo5XQ==}
|
||||
|
||||
partial-json@0.1.7:
|
||||
resolution: {integrity: sha512-Njv/59hHaokb/hRUjce3Hdv12wd60MtM9Z5Olmn+nehe0QDAsRtRbJPvJ0Z91TusF0SuZRIvnM+S4l6EIP8leA==}
|
||||
|
||||
@@ -1949,6 +1985,15 @@ packages:
|
||||
resolution: {integrity: sha512-o2XFanIMy/3+mThw69O8d4n1E5zsLhdO+OPqswezu7Z5ekP4hYDqlDjlmOpYMbzY2Br0ufCwJLdDIXeNVwcWFg==}
|
||||
engines: {node: '>=10'}
|
||||
|
||||
pg@8.11.3:
|
||||
resolution: {integrity: sha512-+9iuvG8QfaaUrrph+kpF24cXkH1YOOUeArRNYIxq1viYHZagBxrTno7cecY1Fa44tJeZvaoG+Djpkc3JwehN5g==}
|
||||
engines: {node: '>= 8.0.0'}
|
||||
peerDependencies:
|
||||
pg-native: '>=3.0.1'
|
||||
peerDependenciesMeta:
|
||||
pg-native:
|
||||
optional: true
|
||||
|
||||
pg@8.21.0:
|
||||
resolution: {integrity: sha512-AUP1EYJuHraQGsVoCQVIcM7TEJVGtDzxWtGFZd8rds9d+CCXlU5Js1rYgfLNvxy9iJrpHjGrRjoi/3BT9fRyiA==}
|
||||
engines: {node: '>= 16.0.0'}
|
||||
@@ -2330,7 +2375,7 @@ packages:
|
||||
peerDependencies:
|
||||
'@types/node': ^20.19.0 || >=22.12.0
|
||||
'@vitejs/devtools': ^0.1.18
|
||||
esbuild: ^0.27.0 || ^0.28.0
|
||||
esbuild: '>=0.28.1'
|
||||
jiti: '>=1.21.0'
|
||||
less: ^4.0.0
|
||||
sass: ^1.70.0
|
||||
@@ -2925,82 +2970,82 @@ snapshots:
|
||||
tslib: 2.8.1
|
||||
optional: true
|
||||
|
||||
'@esbuild/aix-ppc64@0.27.7':
|
||||
'@esbuild/aix-ppc64@0.28.1':
|
||||
optional: true
|
||||
|
||||
'@esbuild/android-arm64@0.27.7':
|
||||
'@esbuild/android-arm64@0.28.1':
|
||||
optional: true
|
||||
|
||||
'@esbuild/android-arm@0.27.7':
|
||||
'@esbuild/android-arm@0.28.1':
|
||||
optional: true
|
||||
|
||||
'@esbuild/android-x64@0.27.7':
|
||||
'@esbuild/android-x64@0.28.1':
|
||||
optional: true
|
||||
|
||||
'@esbuild/darwin-arm64@0.27.7':
|
||||
'@esbuild/darwin-arm64@0.28.1':
|
||||
optional: true
|
||||
|
||||
'@esbuild/darwin-x64@0.27.7':
|
||||
'@esbuild/darwin-x64@0.28.1':
|
||||
optional: true
|
||||
|
||||
'@esbuild/freebsd-arm64@0.27.7':
|
||||
'@esbuild/freebsd-arm64@0.28.1':
|
||||
optional: true
|
||||
|
||||
'@esbuild/freebsd-x64@0.27.7':
|
||||
'@esbuild/freebsd-x64@0.28.1':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-arm64@0.27.7':
|
||||
'@esbuild/linux-arm64@0.28.1':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-arm@0.27.7':
|
||||
'@esbuild/linux-arm@0.28.1':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-ia32@0.27.7':
|
||||
'@esbuild/linux-ia32@0.28.1':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-loong64@0.27.7':
|
||||
'@esbuild/linux-loong64@0.28.1':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-mips64el@0.27.7':
|
||||
'@esbuild/linux-mips64el@0.28.1':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-ppc64@0.27.7':
|
||||
'@esbuild/linux-ppc64@0.28.1':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-riscv64@0.27.7':
|
||||
'@esbuild/linux-riscv64@0.28.1':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-s390x@0.27.7':
|
||||
'@esbuild/linux-s390x@0.28.1':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-x64@0.27.7':
|
||||
'@esbuild/linux-x64@0.28.1':
|
||||
optional: true
|
||||
|
||||
'@esbuild/netbsd-arm64@0.27.7':
|
||||
'@esbuild/netbsd-arm64@0.28.1':
|
||||
optional: true
|
||||
|
||||
'@esbuild/netbsd-x64@0.27.7':
|
||||
'@esbuild/netbsd-x64@0.28.1':
|
||||
optional: true
|
||||
|
||||
'@esbuild/openbsd-arm64@0.27.7':
|
||||
'@esbuild/openbsd-arm64@0.28.1':
|
||||
optional: true
|
||||
|
||||
'@esbuild/openbsd-x64@0.27.7':
|
||||
'@esbuild/openbsd-x64@0.28.1':
|
||||
optional: true
|
||||
|
||||
'@esbuild/openharmony-arm64@0.27.7':
|
||||
'@esbuild/openharmony-arm64@0.28.1':
|
||||
optional: true
|
||||
|
||||
'@esbuild/sunos-x64@0.27.7':
|
||||
'@esbuild/sunos-x64@0.28.1':
|
||||
optional: true
|
||||
|
||||
'@esbuild/win32-arm64@0.27.7':
|
||||
'@esbuild/win32-arm64@0.28.1':
|
||||
optional: true
|
||||
|
||||
'@esbuild/win32-ia32@0.27.7':
|
||||
'@esbuild/win32-ia32@0.28.1':
|
||||
optional: true
|
||||
|
||||
'@esbuild/win32-x64@0.27.7':
|
||||
'@esbuild/win32-x64@0.28.1':
|
||||
optional: true
|
||||
|
||||
'@google/genai@1.52.0':
|
||||
@@ -3478,13 +3523,13 @@ snapshots:
|
||||
chai: 6.2.2
|
||||
tinyrainbow: 3.1.0
|
||||
|
||||
'@vitest/mocker@4.1.8(vite@8.0.16(@types/node@25.9.2)(esbuild@0.27.7)(jiti@2.7.0)(yaml@2.9.0))':
|
||||
'@vitest/mocker@4.1.8(vite@8.0.16(@types/node@25.9.2)(esbuild@0.28.1)(jiti@2.7.0)(yaml@2.9.0))':
|
||||
dependencies:
|
||||
'@vitest/spy': 4.1.8
|
||||
estree-walker: 3.0.3
|
||||
magic-string: 0.30.21
|
||||
optionalDependencies:
|
||||
vite: 8.0.16(@types/node@25.9.2)(esbuild@0.27.7)(jiti@2.7.0)(yaml@2.9.0)
|
||||
vite: 8.0.16(@types/node@25.9.2)(esbuild@0.28.1)(jiti@2.7.0)(yaml@2.9.0)
|
||||
|
||||
'@vitest/pretty-format@4.1.8':
|
||||
dependencies:
|
||||
@@ -3597,6 +3642,8 @@ snapshots:
|
||||
|
||||
buffer-equal-constant-time@1.0.1: {}
|
||||
|
||||
buffer-writer@2.0.0: {}
|
||||
|
||||
buffer@5.7.1:
|
||||
dependencies:
|
||||
base64-js: 1.5.1
|
||||
@@ -3606,9 +3653,9 @@ snapshots:
|
||||
dependencies:
|
||||
run-applescript: 7.1.0
|
||||
|
||||
bundle-require@5.1.0(esbuild@0.27.7):
|
||||
bundle-require@5.1.0(esbuild@0.28.1):
|
||||
dependencies:
|
||||
esbuild: 0.27.7
|
||||
esbuild: 0.28.1
|
||||
load-tsconfig: 0.2.5
|
||||
|
||||
cac@6.7.14: {}
|
||||
@@ -3752,34 +3799,34 @@ snapshots:
|
||||
has-tostringtag: 1.0.2
|
||||
hasown: 2.0.4
|
||||
|
||||
esbuild@0.27.7:
|
||||
esbuild@0.28.1:
|
||||
optionalDependencies:
|
||||
'@esbuild/aix-ppc64': 0.27.7
|
||||
'@esbuild/android-arm': 0.27.7
|
||||
'@esbuild/android-arm64': 0.27.7
|
||||
'@esbuild/android-x64': 0.27.7
|
||||
'@esbuild/darwin-arm64': 0.27.7
|
||||
'@esbuild/darwin-x64': 0.27.7
|
||||
'@esbuild/freebsd-arm64': 0.27.7
|
||||
'@esbuild/freebsd-x64': 0.27.7
|
||||
'@esbuild/linux-arm': 0.27.7
|
||||
'@esbuild/linux-arm64': 0.27.7
|
||||
'@esbuild/linux-ia32': 0.27.7
|
||||
'@esbuild/linux-loong64': 0.27.7
|
||||
'@esbuild/linux-mips64el': 0.27.7
|
||||
'@esbuild/linux-ppc64': 0.27.7
|
||||
'@esbuild/linux-riscv64': 0.27.7
|
||||
'@esbuild/linux-s390x': 0.27.7
|
||||
'@esbuild/linux-x64': 0.27.7
|
||||
'@esbuild/netbsd-arm64': 0.27.7
|
||||
'@esbuild/netbsd-x64': 0.27.7
|
||||
'@esbuild/openbsd-arm64': 0.27.7
|
||||
'@esbuild/openbsd-x64': 0.27.7
|
||||
'@esbuild/openharmony-arm64': 0.27.7
|
||||
'@esbuild/sunos-x64': 0.27.7
|
||||
'@esbuild/win32-arm64': 0.27.7
|
||||
'@esbuild/win32-ia32': 0.27.7
|
||||
'@esbuild/win32-x64': 0.27.7
|
||||
'@esbuild/aix-ppc64': 0.28.1
|
||||
'@esbuild/android-arm': 0.28.1
|
||||
'@esbuild/android-arm64': 0.28.1
|
||||
'@esbuild/android-x64': 0.28.1
|
||||
'@esbuild/darwin-arm64': 0.28.1
|
||||
'@esbuild/darwin-x64': 0.28.1
|
||||
'@esbuild/freebsd-arm64': 0.28.1
|
||||
'@esbuild/freebsd-x64': 0.28.1
|
||||
'@esbuild/linux-arm': 0.28.1
|
||||
'@esbuild/linux-arm64': 0.28.1
|
||||
'@esbuild/linux-ia32': 0.28.1
|
||||
'@esbuild/linux-loong64': 0.28.1
|
||||
'@esbuild/linux-mips64el': 0.28.1
|
||||
'@esbuild/linux-ppc64': 0.28.1
|
||||
'@esbuild/linux-riscv64': 0.28.1
|
||||
'@esbuild/linux-s390x': 0.28.1
|
||||
'@esbuild/linux-x64': 0.28.1
|
||||
'@esbuild/netbsd-arm64': 0.28.1
|
||||
'@esbuild/netbsd-x64': 0.28.1
|
||||
'@esbuild/openbsd-arm64': 0.28.1
|
||||
'@esbuild/openbsd-x64': 0.28.1
|
||||
'@esbuild/openharmony-arm64': 0.28.1
|
||||
'@esbuild/sunos-x64': 0.28.1
|
||||
'@esbuild/win32-arm64': 0.28.1
|
||||
'@esbuild/win32-ia32': 0.28.1
|
||||
'@esbuild/win32-x64': 0.28.1
|
||||
|
||||
escape-string-regexp@2.0.0: {}
|
||||
|
||||
@@ -4190,7 +4237,7 @@ snapshots:
|
||||
crypt: 0.0.2
|
||||
is-buffer: 1.1.6
|
||||
|
||||
mem0ai@3.0.7(@anthropic-ai/sdk@0.91.1(zod@3.25.76))(@azure/identity@4.13.1)(@azure/search-documents@12.2.0)(@cloudflare/workers-types@4.20260610.1)(@google/genai@1.52.0)(@langchain/core@1.1.48(openai@6.26.0(ws@8.21.0)(zod@3.25.76))(ws@8.21.0))(@mistralai/mistralai@2.2.1)(@qdrant/js-client-rest@1.18.0(typescript@6.0.3))(@supabase/supabase-js@2.108.1)(@types/jest@29.5.14)(@types/pg@8.11.0)(better-sqlite3@12.10.0)(cloudflare@4.5.0)(compromise@14.15.1)(groq-sdk@0.3.0)(natural@8.1.1)(ollama@0.5.18)(pg@8.21.0)(redis@5.12.1)(ws@8.21.0):
|
||||
mem0ai@3.0.7(@anthropic-ai/sdk@0.91.1(zod@3.25.76))(@azure/identity@4.13.1)(@azure/search-documents@12.2.0)(@cloudflare/workers-types@4.20260610.1)(@google/genai@1.52.0)(@langchain/core@1.1.48(openai@6.26.0(ws@8.21.0)(zod@3.25.76))(ws@8.21.0))(@mistralai/mistralai@2.2.1)(@qdrant/js-client-rest@1.18.0(typescript@6.0.3))(@supabase/supabase-js@2.108.1)(@types/jest@29.5.14)(@types/pg@8.11.0)(better-sqlite3@12.10.0)(cloudflare@4.5.0)(compromise@14.15.1)(groq-sdk@0.3.0)(natural@8.1.1)(ollama@0.5.18)(pg@8.11.3)(redis@5.12.1)(ws@8.21.0):
|
||||
dependencies:
|
||||
'@anthropic-ai/sdk': 0.91.1(zod@3.25.76)
|
||||
'@azure/identity': 4.13.1
|
||||
@@ -4211,7 +4258,7 @@ snapshots:
|
||||
natural: 8.1.1
|
||||
ollama: 0.5.18
|
||||
openai: 4.104.0(ws@8.21.0)(zod@3.25.76)
|
||||
pg: 8.21.0
|
||||
pg: 8.11.3
|
||||
redis: 5.12.1
|
||||
uuid: 14.0.0
|
||||
zod: 3.25.76
|
||||
@@ -4402,6 +4449,8 @@ snapshots:
|
||||
dependencies:
|
||||
p-finally: 1.0.0
|
||||
|
||||
packet-reader@1.0.0: {}
|
||||
|
||||
partial-json@0.1.7: {}
|
||||
|
||||
path-expression-matcher@1.5.0: {}
|
||||
@@ -4424,6 +4473,10 @@ snapshots:
|
||||
|
||||
pg-numeric@1.0.2: {}
|
||||
|
||||
pg-pool@3.14.0(pg@8.11.3):
|
||||
dependencies:
|
||||
pg: 8.11.3
|
||||
|
||||
pg-pool@3.14.0(pg@8.21.0):
|
||||
dependencies:
|
||||
pg: 8.21.0
|
||||
@@ -4448,6 +4501,18 @@ snapshots:
|
||||
postgres-interval: 3.0.0
|
||||
postgres-range: 1.1.4
|
||||
|
||||
pg@8.11.3:
|
||||
dependencies:
|
||||
buffer-writer: 2.0.0
|
||||
packet-reader: 1.0.0
|
||||
pg-connection-string: 2.13.0
|
||||
pg-pool: 3.14.0(pg@8.11.3)
|
||||
pg-protocol: 1.14.0
|
||||
pg-types: 2.2.0
|
||||
pgpass: 1.0.5
|
||||
optionalDependencies:
|
||||
pg-cloudflare: 1.4.0
|
||||
|
||||
pg@8.21.0:
|
||||
dependencies:
|
||||
pg-connection-string: 2.13.0
|
||||
@@ -4783,12 +4848,12 @@ snapshots:
|
||||
|
||||
tsup@8.5.1(jiti@2.7.0)(postcss@8.5.15)(typescript@6.0.3)(yaml@2.9.0):
|
||||
dependencies:
|
||||
bundle-require: 5.1.0(esbuild@0.27.7)
|
||||
bundle-require: 5.1.0(esbuild@0.28.1)
|
||||
cac: 6.7.14
|
||||
chokidar: 4.0.3
|
||||
consola: 3.4.2
|
||||
debug: 4.4.3
|
||||
esbuild: 0.27.7
|
||||
esbuild: 0.28.1
|
||||
fix-dts-default-cjs-exports: 1.0.1
|
||||
joycon: 3.1.1
|
||||
picocolors: 1.1.1
|
||||
@@ -4837,7 +4902,7 @@ snapshots:
|
||||
|
||||
uuid@14.0.0: {}
|
||||
|
||||
vite@8.0.16(@types/node@25.9.2)(esbuild@0.27.7)(jiti@2.7.0)(yaml@2.9.0):
|
||||
vite@8.0.16(@types/node@25.9.2)(esbuild@0.28.1)(jiti@2.7.0)(yaml@2.9.0):
|
||||
dependencies:
|
||||
lightningcss: 1.32.0
|
||||
picomatch: 4.0.4
|
||||
@@ -4846,15 +4911,15 @@ snapshots:
|
||||
tinyglobby: 0.2.17
|
||||
optionalDependencies:
|
||||
'@types/node': 25.9.2
|
||||
esbuild: 0.27.7
|
||||
esbuild: 0.28.1
|
||||
fsevents: 2.3.3
|
||||
jiti: 2.7.0
|
||||
yaml: 2.9.0
|
||||
|
||||
vitest@4.1.8(@types/node@25.9.2)(vite@8.0.16(@types/node@25.9.2)(esbuild@0.27.7)(jiti@2.7.0)(yaml@2.9.0)):
|
||||
vitest@4.1.8(@types/node@25.9.2)(vite@8.0.16(@types/node@25.9.2)(esbuild@0.28.1)(jiti@2.7.0)(yaml@2.9.0)):
|
||||
dependencies:
|
||||
'@vitest/expect': 4.1.8
|
||||
'@vitest/mocker': 4.1.8(vite@8.0.16(@types/node@25.9.2)(esbuild@0.27.7)(jiti@2.7.0)(yaml@2.9.0))
|
||||
'@vitest/mocker': 4.1.8(vite@8.0.16(@types/node@25.9.2)(esbuild@0.28.1)(jiti@2.7.0)(yaml@2.9.0))
|
||||
'@vitest/pretty-format': 4.1.8
|
||||
'@vitest/runner': 4.1.8
|
||||
'@vitest/snapshot': 4.1.8
|
||||
@@ -4871,7 +4936,7 @@ snapshots:
|
||||
tinyexec: 1.2.4
|
||||
tinyglobby: 0.2.17
|
||||
tinyrainbow: 3.1.0
|
||||
vite: 8.0.16(@types/node@25.9.2)(esbuild@0.27.7)(jiti@2.7.0)(yaml@2.9.0)
|
||||
vite: 8.0.16(@types/node@25.9.2)(esbuild@0.28.1)(jiti@2.7.0)(yaml@2.9.0)
|
||||
why-is-node-running: 2.3.0
|
||||
optionalDependencies:
|
||||
'@types/node': 25.9.2
|
||||
|
||||
@@ -3,3 +3,4 @@ packages:
|
||||
|
||||
overrides:
|
||||
"uuid@<11.1.1": ">=11.1.1"
|
||||
"esbuild": ">=0.28.1"
|
||||
|
||||
@@ -84,7 +84,8 @@
|
||||
"minimatch@>=5.0.0 <5.1.8": "^5.1.8",
|
||||
"minimatch@>=9.0.0 <9.0.7": "^9.0.7",
|
||||
"picomatch@<2.3.2": "^2.3.2",
|
||||
"rollup@>=4.0.0 <4.59.0": "^4.59.0"
|
||||
"rollup@>=4.0.0 <4.59.0": "^4.59.0",
|
||||
"esbuild": ">=0.28.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+116
-115
@@ -11,6 +11,7 @@ overrides:
|
||||
minimatch@>=9.0.0 <9.0.7: ^9.0.7
|
||||
picomatch@<2.3.2: ^2.3.2
|
||||
rollup@>=4.0.0 <4.59.0: ^4.59.0
|
||||
esbuild: '>=0.28.1'
|
||||
|
||||
importers:
|
||||
|
||||
@@ -67,7 +68,7 @@ importers:
|
||||
version: 3.1.14
|
||||
ts-jest:
|
||||
specifier: ^29.4.11
|
||||
version: 29.4.11(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.29.7))(esbuild@0.27.7)(jest-util@29.7.0)(jest@29.7.0(@types/node@18.19.130)(ts-node@10.9.2(@types/node@18.19.130)(typescript@5.9.3)))(typescript@5.9.3)
|
||||
version: 29.4.11(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.29.7))(esbuild@0.28.1)(jest-util@29.7.0)(jest@29.7.0(@types/node@18.19.130)(ts-node@10.9.2(@types/node@18.19.130)(typescript@5.9.3)))(typescript@5.9.3)
|
||||
ts-node:
|
||||
specifier: ^10.9.2
|
||||
version: 10.9.2(@types/node@18.19.130)(typescript@5.9.3)
|
||||
@@ -303,158 +304,158 @@ packages:
|
||||
resolution: {integrity: sha512-0dEVyRLM/lG4gp1R/Ik5bfPl/1wX00xFwd5KcNH602tzBa09oF7pbTKETEhR1GjZ75K6OJnYFu8II2dyMhONMw==}
|
||||
engines: {node: '>=16'}
|
||||
|
||||
'@esbuild/aix-ppc64@0.27.7':
|
||||
resolution: {integrity: sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg==}
|
||||
'@esbuild/aix-ppc64@0.28.1':
|
||||
resolution: {integrity: sha512-Svl7tq8k/08+p6CXPpRjQ1fKX+1odH/BQbb48fV6fj3CWHhsoIOoY87w1oHXm0qEpkIK3ZfVgp0hed3XBXzXMQ==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [ppc64]
|
||||
os: [aix]
|
||||
|
||||
'@esbuild/android-arm64@0.27.7':
|
||||
resolution: {integrity: sha512-62dPZHpIXzvChfvfLJow3q5dDtiNMkwiRzPylSCfriLvZeq0a1bWChrGx/BbUbPwOrsWKMn8idSllklzBy+dgQ==}
|
||||
'@esbuild/android-arm64@0.28.1':
|
||||
resolution: {integrity: sha512-34EGEbCIAgosYz6goLcopX6Mo7NyGv9tfwEM2/7Ce2VcVRk568iSvniGWcUXIy7wEDR1wzolcxcriFVrWYcwBg==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm64]
|
||||
os: [android]
|
||||
|
||||
'@esbuild/android-arm@0.27.7':
|
||||
resolution: {integrity: sha512-jbPXvB4Yj2yBV7HUfE2KHe4GJX51QplCN1pGbYjvsyCZbQmies29EoJbkEc+vYuU5o45AfQn37vZlyXy4YJ8RQ==}
|
||||
'@esbuild/android-arm@0.28.1':
|
||||
resolution: {integrity: sha512-0k2F129Xdio1TdJfzJ8sy1Q47vUD2NnwdhiAf7drUN1EBTfPf4hsFCtmMgu/6m8JSzsBrlmVjudMBQqOfG8usQ==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm]
|
||||
os: [android]
|
||||
|
||||
'@esbuild/android-x64@0.27.7':
|
||||
resolution: {integrity: sha512-x5VpMODneVDb70PYV2VQOmIUUiBtY3D3mPBG8NxVk5CogneYhkR7MmM3yR/uMdITLrC1ml/NV1rj4bMJuy9MCg==}
|
||||
'@esbuild/android-x64@0.28.1':
|
||||
resolution: {integrity: sha512-dbwY7ltSMDWsRatcRpCnES4F+im88OCUgGZjy52shC7GqHRE/cYlxNbB4Z4UpJswpcc4Qxd2oE/ufM0p61IKng==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [x64]
|
||||
os: [android]
|
||||
|
||||
'@esbuild/darwin-arm64@0.27.7':
|
||||
resolution: {integrity: sha512-5lckdqeuBPlKUwvoCXIgI2D9/ABmPq3Rdp7IfL70393YgaASt7tbju3Ac+ePVi3KDH6N2RqePfHnXkaDtY9fkw==}
|
||||
'@esbuild/darwin-arm64@0.28.1':
|
||||
resolution: {integrity: sha512-TZbWkQY7kvTAXbXUT7uVACR5cMHsDiSz9z7ZKAX/RTq/WJEk3QyRr0wZpNhBDX+/0CtdqUIJlOiodQcta6tY3Q==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm64]
|
||||
os: [darwin]
|
||||
|
||||
'@esbuild/darwin-x64@0.27.7':
|
||||
resolution: {integrity: sha512-rYnXrKcXuT7Z+WL5K980jVFdvVKhCHhUwid+dDYQpH+qu+TefcomiMAJpIiC2EM3Rjtq0sO3StMV/+3w3MyyqQ==}
|
||||
'@esbuild/darwin-x64@0.28.1':
|
||||
resolution: {integrity: sha512-zfdzgK9ACBNZLI/CyHTOx81SyNbM6YXn7rxSgX97VjyiPl9W1i4Ka4fgKECEoFCKGpvBj5qArWIGgQjOwkgskQ==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [x64]
|
||||
os: [darwin]
|
||||
|
||||
'@esbuild/freebsd-arm64@0.27.7':
|
||||
resolution: {integrity: sha512-B48PqeCsEgOtzME2GbNM2roU29AMTuOIN91dsMO30t+Ydis3z/3Ngoj5hhnsOSSwNzS+6JppqWsuhTp6E82l2w==}
|
||||
'@esbuild/freebsd-arm64@0.28.1':
|
||||
resolution: {integrity: sha512-wG2EA8ENdEI0qhkSZMjfqrdY+ziCYCPMmtZjjIwOmXFjmyzEHn+UUxk5of+SYsjtfs3VpnlC7QLzSI5hY/rOAw==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm64]
|
||||
os: [freebsd]
|
||||
|
||||
'@esbuild/freebsd-x64@0.27.7':
|
||||
resolution: {integrity: sha512-jOBDK5XEjA4m5IJK3bpAQF9/Lelu/Z9ZcdhTRLf4cajlB+8VEhFFRjWgfy3M1O4rO2GQ/b2dLwCUGpiF/eATNQ==}
|
||||
'@esbuild/freebsd-x64@0.28.1':
|
||||
resolution: {integrity: sha512-i7dZ9vQgnvSCzi/rYCXNgtF/U+eKZNJBzu3eTQbRgHnM7tNSizLOkRFAl3qzVc/Op/u5YkHHa4pf/3DOYHthLQ==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [x64]
|
||||
os: [freebsd]
|
||||
|
||||
'@esbuild/linux-arm64@0.27.7':
|
||||
resolution: {integrity: sha512-RZPHBoxXuNnPQO9rvjh5jdkRmVizktkT7TCDkDmQ0W2SwHInKCAV95GRuvdSvA7w4VMwfCjUiPwDi0ZO6Nfe9A==}
|
||||
'@esbuild/linux-arm64@0.28.1':
|
||||
resolution: {integrity: sha512-yHs+0uc8+nvEAfAfxrWQKK5peSNzBc4PegcMO0EJ2hT71uA7vB8Ihg2e77R2P7SG5uYjPbHlLLmve4LLLRCf0g==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-arm@0.27.7':
|
||||
resolution: {integrity: sha512-RkT/YXYBTSULo3+af8Ib0ykH8u2MBh57o7q/DAs3lTJlyVQkgQvlrPTnjIzzRPQyavxtPtfg0EopvDyIt0j1rA==}
|
||||
'@esbuild/linux-arm@0.28.1':
|
||||
resolution: {integrity: sha512-qVXBOHQS+d5Y722GwJzJUtOLlX7km3CraOaGormF1pDtPd2C/l1SHRPgjLunLGe51Sh5YYWKMFDyV4SxgMQYTQ==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-ia32@0.27.7':
|
||||
resolution: {integrity: sha512-GA48aKNkyQDbd3KtkplYWT102C5sn/EZTY4XROkxONgruHPU72l+gW+FfF8tf2cFjeHaRbWpOYa/uRBz/Xq1Pg==}
|
||||
'@esbuild/linux-ia32@0.28.1':
|
||||
resolution: {integrity: sha512-d1z4ZuP0ajrfz/FhGT4vv278rX8KnPPJx8i5+AtK7TYbx9Le9F1hyzurZpkEyjkGa9dUGhQow4C1NmeGvqxN2w==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [ia32]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-loong64@0.27.7':
|
||||
resolution: {integrity: sha512-a4POruNM2oWsD4WKvBSEKGIiWQF8fZOAsycHOt6JBpZ+JN2n2JH9WAv56SOyu9X5IqAjqSIPTaJkqN8F7XOQ5Q==}
|
||||
'@esbuild/linux-loong64@0.28.1':
|
||||
resolution: {integrity: sha512-M5sRjUVZrkm1OAPR3dlOYzNmN+loZKGVi1VUQGrwuqLcbR6qeAz+famMhjASeH3YVKvZz+zT1jlh/keC3Rj/lg==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [loong64]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-mips64el@0.27.7':
|
||||
resolution: {integrity: sha512-KabT5I6StirGfIz0FMgl1I+R1H73Gp0ofL9A3nG3i/cYFJzKHhouBV5VWK1CSgKvVaG4q1RNpCTR2LuTVB3fIw==}
|
||||
'@esbuild/linux-mips64el@0.28.1':
|
||||
resolution: {integrity: sha512-mRObBZeHh2OxcBFPWE/FjylkRgZdYuiTR3vaTozquCGOH14iP9oN4x4Ge81CoIDYQrXmIxpFumJBu5MtZpnQJQ==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [mips64el]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-ppc64@0.27.7':
|
||||
resolution: {integrity: sha512-gRsL4x6wsGHGRqhtI+ifpN/vpOFTQtnbsupUF5R5YTAg+y/lKelYR1hXbnBdzDjGbMYjVJLJTd2OFmMewAgwlQ==}
|
||||
'@esbuild/linux-ppc64@0.28.1':
|
||||
resolution: {integrity: sha512-slScBsMAb3GFDcdrCgLwZtPYRoH2H/youv10QiZyRjmsP48fznoveWytSgCI/R0ZcUgpc0ZhIUEx6LHts8yrfQ==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [ppc64]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-riscv64@0.27.7':
|
||||
resolution: {integrity: sha512-hL25LbxO1QOngGzu2U5xeXtxXcW+/GvMN3ejANqXkxZ/opySAZMrc+9LY/WyjAan41unrR3YrmtTsUpwT66InQ==}
|
||||
'@esbuild/linux-riscv64@0.28.1':
|
||||
resolution: {integrity: sha512-kw0owk1o0GFETUJyW0jc0G4Yzs0BHZn0JDZ8JRT088vjJYX777BAs1fDGxAC+q831qOs2DTC96mNsG2opdfyyQ==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [riscv64]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-s390x@0.27.7':
|
||||
resolution: {integrity: sha512-2k8go8Ycu1Kb46vEelhu1vqEP+UeRVj2zY1pSuPdgvbd5ykAw82Lrro28vXUrRmzEsUV0NzCf54yARIK8r0fdw==}
|
||||
'@esbuild/linux-s390x@0.28.1':
|
||||
resolution: {integrity: sha512-/lAIjX8aYFRByhh6L5rYtPEDRqa9de/4V/juOXcta5frjvzXO4/sqEtyytse0g3zZFuWu5cDN0MkLz2qRDD2Ag==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [s390x]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-x64@0.27.7':
|
||||
resolution: {integrity: sha512-hzznmADPt+OmsYzw1EE33ccA+HPdIqiCRq7cQeL1Jlq2gb1+OyWBkMCrYGBJ+sxVzve2ZJEVeePbLM2iEIZSxA==}
|
||||
'@esbuild/linux-x64@0.28.1':
|
||||
resolution: {integrity: sha512-u/anNYF2mmVOEDwLtnQ1wOr3EZ9sTNGLWrsYGYwHWzGA3Si84IOkHXlbWTD1NB+9/1lcnweYKO54uhxZydNzfA==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/netbsd-arm64@0.27.7':
|
||||
resolution: {integrity: sha512-b6pqtrQdigZBwZxAn1UpazEisvwaIDvdbMbmrly7cDTMFnw/+3lVxxCTGOrkPVnsYIosJJXAsILG9XcQS+Yu6w==}
|
||||
'@esbuild/netbsd-arm64@0.28.1':
|
||||
resolution: {integrity: sha512-oks0DYbLwWMmaakTsCb+zL4E+aHRVLom9IJZOAthMQEPiQmydXHkziYEsGYRx0uNV/IjEKGAV941JzH02pflqw==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm64]
|
||||
os: [netbsd]
|
||||
|
||||
'@esbuild/netbsd-x64@0.27.7':
|
||||
resolution: {integrity: sha512-OfatkLojr6U+WN5EDYuoQhtM+1xco+/6FSzJJnuWiUw5eVcicbyK3dq5EeV/QHT1uy6GoDhGbFpprUiHUYggrw==}
|
||||
'@esbuild/netbsd-x64@0.28.1':
|
||||
resolution: {integrity: sha512-aeL6lAnN89Hz43Mlh1G8ARasbuoYvSITDEx0tHh5b7jJnHcssqgjy9Yx430GDpmCa6OyrKoS0aNRjKundRizGg==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [x64]
|
||||
os: [netbsd]
|
||||
|
||||
'@esbuild/openbsd-arm64@0.27.7':
|
||||
resolution: {integrity: sha512-AFuojMQTxAz75Fo8idVcqoQWEHIXFRbOc1TrVcFSgCZtQfSdc1RXgB3tjOn/krRHENUB4j00bfGjyl2mJrU37A==}
|
||||
'@esbuild/openbsd-arm64@0.28.1':
|
||||
resolution: {integrity: sha512-MEFJe5C3R8pwXdZ5Y21oo6m7ePiS0d9pWucn99O/wvyJZChoIQKrQDxKrGeW8F5+T0okTHesAmDeiHDTIq0V/Q==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm64]
|
||||
os: [openbsd]
|
||||
|
||||
'@esbuild/openbsd-x64@0.27.7':
|
||||
resolution: {integrity: sha512-+A1NJmfM8WNDv5CLVQYJ5PshuRm/4cI6WMZRg1by1GwPIQPCTs1GLEUHwiiQGT5zDdyLiRM/l1G0Pv54gvtKIg==}
|
||||
'@esbuild/openbsd-x64@0.28.1':
|
||||
resolution: {integrity: sha512-i/ZLIOafE0Z8cI/XANJAixoJL/uRAoS2xOA3rb0xN+KK0K177cMAsQYkzHtBrtMXAKuAc7HGgcWiZ/sRC1Nxgw==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [x64]
|
||||
os: [openbsd]
|
||||
|
||||
'@esbuild/openharmony-arm64@0.27.7':
|
||||
resolution: {integrity: sha512-+KrvYb/C8zA9CU/g0sR6w2RBw7IGc5J2BPnc3dYc5VJxHCSF1yNMxTV5LQ7GuKteQXZtspjFbiuW5/dOj7H4Yw==}
|
||||
'@esbuild/openharmony-arm64@0.28.1':
|
||||
resolution: {integrity: sha512-ge+Z7EXFNt2BO1oAMsVpiQ8EwndV9i1xXerAeTIK7AtPs3bKFXQM7nlRxDSIUIMeueR1CNXxqztLzdNeReKBJg==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm64]
|
||||
os: [openharmony]
|
||||
|
||||
'@esbuild/sunos-x64@0.27.7':
|
||||
resolution: {integrity: sha512-ikktIhFBzQNt/QDyOL580ti9+5mL/YZeUPKU2ivGtGjdTYoqz6jObj6nOMfhASpS4GU4Q/Clh1QtxWAvcYKamA==}
|
||||
'@esbuild/sunos-x64@0.28.1':
|
||||
resolution: {integrity: sha512-BEjgtECkL3vY+SaSQ6nzVfiALUeFxpawyp8Jmf5PtYhf1Ug40N1h/hxlhts+f1FvSvarEigdxS3BlSMI2PJLcQ==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [x64]
|
||||
os: [sunos]
|
||||
|
||||
'@esbuild/win32-arm64@0.27.7':
|
||||
resolution: {integrity: sha512-7yRhbHvPqSpRUV7Q20VuDwbjW5kIMwTHpptuUzV+AA46kiPze5Z7qgt6CLCK3pWFrHeNfDd1VKgyP4O+ng17CA==}
|
||||
'@esbuild/win32-arm64@0.28.1':
|
||||
resolution: {integrity: sha512-lCv9eK/H6ZJWbE7bh2nw54CZ9M2nupBxJcTsdk/QQnWkdSjKGuxmmH8/GWrlT1eMmZfn4dGcCjRte397WqfQXA==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm64]
|
||||
os: [win32]
|
||||
|
||||
'@esbuild/win32-ia32@0.27.7':
|
||||
resolution: {integrity: sha512-SmwKXe6VHIyZYbBLJrhOoCJRB/Z1tckzmgTLfFYOfpMAx63BJEaL9ExI8x7v0oAO3Zh6D/Oi1gVxEYr5oUCFhw==}
|
||||
'@esbuild/win32-ia32@0.28.1':
|
||||
resolution: {integrity: sha512-zvb/mB2bSCoJOpoCBgYKKpX6YM6mJBlBUVUtVj41DlZJVEB6/0CKlRYxP5wWl1C1ILiCoAU5wZZ4q1P3qeS6Eg==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [ia32]
|
||||
os: [win32]
|
||||
|
||||
'@esbuild/win32-x64@0.27.7':
|
||||
resolution: {integrity: sha512-56hiAJPhwQ1R4i+21FVF7V8kSD5zZTdHcVuRFMW0hn753vVfQN8xlx4uOPT4xoGH0Z/oVATuR82AiqSTDIpaHg==}
|
||||
'@esbuild/win32-x64@0.28.1':
|
||||
resolution: {integrity: sha512-bm4Mowrv+GXMlpWX++EcXw/iLyd1o3+bJkC2DkWXYVvgZCqD/bSj9ctZeAMC3cIxgjRVR2Dufaiu4YPxr5gW1A==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [x64]
|
||||
os: [win32]
|
||||
@@ -866,7 +867,7 @@ packages:
|
||||
resolution: {integrity: sha512-3WrrOuZiyaaZPWiEt4G3+IffISVC9HYlWueJEBWED4ZH4aIAC2PnkdnuRrR94M+w6yGWn4AglWtJtBI8YqvgoA==}
|
||||
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
|
||||
peerDependencies:
|
||||
esbuild: '>=0.18'
|
||||
esbuild: '>=0.28.1'
|
||||
|
||||
cac@6.7.14:
|
||||
resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==}
|
||||
@@ -1011,8 +1012,8 @@ packages:
|
||||
resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
esbuild@0.27.7:
|
||||
resolution: {integrity: sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w==}
|
||||
esbuild@0.28.1:
|
||||
resolution: {integrity: sha512-HrJrvZv5ayxBzPfwphOoNzkzOIIlifzk0KJrGK2c8R4+LKpMtpYLQeUdjnwjWv/LZlkH2laZk+4w78pi99D4Vw==}
|
||||
engines: {node: '>=18'}
|
||||
hasBin: true
|
||||
|
||||
@@ -2142,82 +2143,82 @@ snapshots:
|
||||
dependencies:
|
||||
'@edge-runtime/primitives': 4.1.0
|
||||
|
||||
'@esbuild/aix-ppc64@0.27.7':
|
||||
'@esbuild/aix-ppc64@0.28.1':
|
||||
optional: true
|
||||
|
||||
'@esbuild/android-arm64@0.27.7':
|
||||
'@esbuild/android-arm64@0.28.1':
|
||||
optional: true
|
||||
|
||||
'@esbuild/android-arm@0.27.7':
|
||||
'@esbuild/android-arm@0.28.1':
|
||||
optional: true
|
||||
|
||||
'@esbuild/android-x64@0.27.7':
|
||||
'@esbuild/android-x64@0.28.1':
|
||||
optional: true
|
||||
|
||||
'@esbuild/darwin-arm64@0.27.7':
|
||||
'@esbuild/darwin-arm64@0.28.1':
|
||||
optional: true
|
||||
|
||||
'@esbuild/darwin-x64@0.27.7':
|
||||
'@esbuild/darwin-x64@0.28.1':
|
||||
optional: true
|
||||
|
||||
'@esbuild/freebsd-arm64@0.27.7':
|
||||
'@esbuild/freebsd-arm64@0.28.1':
|
||||
optional: true
|
||||
|
||||
'@esbuild/freebsd-x64@0.27.7':
|
||||
'@esbuild/freebsd-x64@0.28.1':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-arm64@0.27.7':
|
||||
'@esbuild/linux-arm64@0.28.1':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-arm@0.27.7':
|
||||
'@esbuild/linux-arm@0.28.1':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-ia32@0.27.7':
|
||||
'@esbuild/linux-ia32@0.28.1':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-loong64@0.27.7':
|
||||
'@esbuild/linux-loong64@0.28.1':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-mips64el@0.27.7':
|
||||
'@esbuild/linux-mips64el@0.28.1':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-ppc64@0.27.7':
|
||||
'@esbuild/linux-ppc64@0.28.1':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-riscv64@0.27.7':
|
||||
'@esbuild/linux-riscv64@0.28.1':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-s390x@0.27.7':
|
||||
'@esbuild/linux-s390x@0.28.1':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-x64@0.27.7':
|
||||
'@esbuild/linux-x64@0.28.1':
|
||||
optional: true
|
||||
|
||||
'@esbuild/netbsd-arm64@0.27.7':
|
||||
'@esbuild/netbsd-arm64@0.28.1':
|
||||
optional: true
|
||||
|
||||
'@esbuild/netbsd-x64@0.27.7':
|
||||
'@esbuild/netbsd-x64@0.28.1':
|
||||
optional: true
|
||||
|
||||
'@esbuild/openbsd-arm64@0.27.7':
|
||||
'@esbuild/openbsd-arm64@0.28.1':
|
||||
optional: true
|
||||
|
||||
'@esbuild/openbsd-x64@0.27.7':
|
||||
'@esbuild/openbsd-x64@0.28.1':
|
||||
optional: true
|
||||
|
||||
'@esbuild/openharmony-arm64@0.27.7':
|
||||
'@esbuild/openharmony-arm64@0.28.1':
|
||||
optional: true
|
||||
|
||||
'@esbuild/sunos-x64@0.27.7':
|
||||
'@esbuild/sunos-x64@0.28.1':
|
||||
optional: true
|
||||
|
||||
'@esbuild/win32-arm64@0.27.7':
|
||||
'@esbuild/win32-arm64@0.28.1':
|
||||
optional: true
|
||||
|
||||
'@esbuild/win32-ia32@0.27.7':
|
||||
'@esbuild/win32-ia32@0.28.1':
|
||||
optional: true
|
||||
|
||||
'@esbuild/win32-x64@0.27.7':
|
||||
'@esbuild/win32-x64@0.28.1':
|
||||
optional: true
|
||||
|
||||
'@istanbuljs/load-nyc-config@1.1.0':
|
||||
@@ -2702,9 +2703,9 @@ snapshots:
|
||||
|
||||
buffer-from@1.1.2: {}
|
||||
|
||||
bundle-require@5.1.0(esbuild@0.27.7):
|
||||
bundle-require@5.1.0(esbuild@0.28.1):
|
||||
dependencies:
|
||||
esbuild: 0.27.7
|
||||
esbuild: 0.28.1
|
||||
load-tsconfig: 0.2.5
|
||||
|
||||
cac@6.7.14: {}
|
||||
@@ -2823,34 +2824,34 @@ snapshots:
|
||||
|
||||
es-errors@1.3.0: {}
|
||||
|
||||
esbuild@0.27.7:
|
||||
esbuild@0.28.1:
|
||||
optionalDependencies:
|
||||
'@esbuild/aix-ppc64': 0.27.7
|
||||
'@esbuild/android-arm': 0.27.7
|
||||
'@esbuild/android-arm64': 0.27.7
|
||||
'@esbuild/android-x64': 0.27.7
|
||||
'@esbuild/darwin-arm64': 0.27.7
|
||||
'@esbuild/darwin-x64': 0.27.7
|
||||
'@esbuild/freebsd-arm64': 0.27.7
|
||||
'@esbuild/freebsd-x64': 0.27.7
|
||||
'@esbuild/linux-arm': 0.27.7
|
||||
'@esbuild/linux-arm64': 0.27.7
|
||||
'@esbuild/linux-ia32': 0.27.7
|
||||
'@esbuild/linux-loong64': 0.27.7
|
||||
'@esbuild/linux-mips64el': 0.27.7
|
||||
'@esbuild/linux-ppc64': 0.27.7
|
||||
'@esbuild/linux-riscv64': 0.27.7
|
||||
'@esbuild/linux-s390x': 0.27.7
|
||||
'@esbuild/linux-x64': 0.27.7
|
||||
'@esbuild/netbsd-arm64': 0.27.7
|
||||
'@esbuild/netbsd-x64': 0.27.7
|
||||
'@esbuild/openbsd-arm64': 0.27.7
|
||||
'@esbuild/openbsd-x64': 0.27.7
|
||||
'@esbuild/openharmony-arm64': 0.27.7
|
||||
'@esbuild/sunos-x64': 0.27.7
|
||||
'@esbuild/win32-arm64': 0.27.7
|
||||
'@esbuild/win32-ia32': 0.27.7
|
||||
'@esbuild/win32-x64': 0.27.7
|
||||
'@esbuild/aix-ppc64': 0.28.1
|
||||
'@esbuild/android-arm': 0.28.1
|
||||
'@esbuild/android-arm64': 0.28.1
|
||||
'@esbuild/android-x64': 0.28.1
|
||||
'@esbuild/darwin-arm64': 0.28.1
|
||||
'@esbuild/darwin-x64': 0.28.1
|
||||
'@esbuild/freebsd-arm64': 0.28.1
|
||||
'@esbuild/freebsd-x64': 0.28.1
|
||||
'@esbuild/linux-arm': 0.28.1
|
||||
'@esbuild/linux-arm64': 0.28.1
|
||||
'@esbuild/linux-ia32': 0.28.1
|
||||
'@esbuild/linux-loong64': 0.28.1
|
||||
'@esbuild/linux-mips64el': 0.28.1
|
||||
'@esbuild/linux-ppc64': 0.28.1
|
||||
'@esbuild/linux-riscv64': 0.28.1
|
||||
'@esbuild/linux-s390x': 0.28.1
|
||||
'@esbuild/linux-x64': 0.28.1
|
||||
'@esbuild/netbsd-arm64': 0.28.1
|
||||
'@esbuild/netbsd-x64': 0.28.1
|
||||
'@esbuild/openbsd-arm64': 0.28.1
|
||||
'@esbuild/openbsd-x64': 0.28.1
|
||||
'@esbuild/openharmony-arm64': 0.28.1
|
||||
'@esbuild/sunos-x64': 0.28.1
|
||||
'@esbuild/win32-arm64': 0.28.1
|
||||
'@esbuild/win32-ia32': 0.28.1
|
||||
'@esbuild/win32-x64': 0.28.1
|
||||
|
||||
escalade@3.2.0: {}
|
||||
|
||||
@@ -3711,7 +3712,7 @@ snapshots:
|
||||
|
||||
ts-interface-checker@0.1.13: {}
|
||||
|
||||
ts-jest@29.4.11(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.29.7))(esbuild@0.27.7)(jest-util@29.7.0)(jest@29.7.0(@types/node@18.19.130)(ts-node@10.9.2(@types/node@18.19.130)(typescript@5.9.3)))(typescript@5.9.3):
|
||||
ts-jest@29.4.11(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.29.7))(esbuild@0.28.1)(jest-util@29.7.0)(jest@29.7.0(@types/node@18.19.130)(ts-node@10.9.2(@types/node@18.19.130)(typescript@5.9.3)))(typescript@5.9.3):
|
||||
dependencies:
|
||||
bs-logger: 0.2.6
|
||||
fast-json-stable-stringify: 2.1.0
|
||||
@@ -3729,7 +3730,7 @@ snapshots:
|
||||
'@jest/transform': 29.7.0
|
||||
'@jest/types': 29.6.3
|
||||
babel-jest: 29.7.0(@babel/core@7.29.7)
|
||||
esbuild: 0.27.7
|
||||
esbuild: 0.28.1
|
||||
jest-util: 29.7.0
|
||||
|
||||
ts-node@10.9.2(@types/node@18.19.130)(typescript@5.9.3):
|
||||
@@ -3752,12 +3753,12 @@ snapshots:
|
||||
|
||||
tsup@8.5.1(typescript@5.9.3):
|
||||
dependencies:
|
||||
bundle-require: 5.1.0(esbuild@0.27.7)
|
||||
bundle-require: 5.1.0(esbuild@0.28.1)
|
||||
cac: 6.7.14
|
||||
chokidar: 4.0.3
|
||||
consola: 3.4.2
|
||||
debug: 4.4.3(supports-color@5.5.0)
|
||||
esbuild: 0.27.7
|
||||
esbuild: 0.28.1
|
||||
fix-dts-default-cjs-exports: 1.0.1
|
||||
joycon: 3.1.1
|
||||
picocolors: 1.1.1
|
||||
|
||||
@@ -12,3 +12,4 @@ overrides:
|
||||
"minimatch@>=9.0.0 <9.0.7": "^9.0.7"
|
||||
"picomatch@<2.3.2": "^2.3.2"
|
||||
"rollup@>=4.0.0 <4.59.0": "^4.59.0"
|
||||
"esbuild": ">=0.28.1"
|
||||
|
||||
@@ -154,7 +154,8 @@
|
||||
"rollup@>=4.0.0 <4.59.0": "^4.59.0",
|
||||
"tar-fs@>=2.0.0 <2.1.4": "^2.1.4",
|
||||
"glob@>=10.2.0 <10.5.0": "^10.5.0",
|
||||
"@modelcontextprotocol/sdk": "^1.25.4"
|
||||
"@modelcontextprotocol/sdk": "^1.25.4",
|
||||
"esbuild": ">=0.28.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Generated
+116
-115
@@ -21,6 +21,7 @@ overrides:
|
||||
tar-fs@>=2.0.0 <2.1.4: ^2.1.4
|
||||
glob@>=10.2.0 <10.5.0: ^10.5.0
|
||||
'@modelcontextprotocol/sdk': ^1.25.4
|
||||
esbuild: '>=0.28.1'
|
||||
|
||||
importers:
|
||||
|
||||
@@ -125,7 +126,7 @@ importers:
|
||||
version: 5.0.10
|
||||
ts-jest:
|
||||
specifier: ^29.2.6
|
||||
version: 29.4.11(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.29.7))(esbuild@0.27.7)(jest-util@29.7.0)(jest@29.7.0(@types/node@22.19.21)(ts-node@10.9.2(@types/node@22.19.21)(typescript@5.5.4)))(typescript@5.5.4)
|
||||
version: 29.4.11(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.29.7))(esbuild@0.28.1)(jest-util@29.7.0)(jest@29.7.0(@types/node@22.19.21)(ts-node@10.9.2(@types/node@22.19.21)(typescript@5.5.4)))(typescript@5.5.4)
|
||||
ts-node:
|
||||
specifier: ^10.9.2
|
||||
version: 10.9.2(@types/node@22.19.21)(typescript@5.5.4)
|
||||
@@ -375,158 +376,158 @@ packages:
|
||||
resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
'@esbuild/aix-ppc64@0.27.7':
|
||||
resolution: {integrity: sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg==}
|
||||
'@esbuild/aix-ppc64@0.28.1':
|
||||
resolution: {integrity: sha512-Svl7tq8k/08+p6CXPpRjQ1fKX+1odH/BQbb48fV6fj3CWHhsoIOoY87w1oHXm0qEpkIK3ZfVgp0hed3XBXzXMQ==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [ppc64]
|
||||
os: [aix]
|
||||
|
||||
'@esbuild/android-arm64@0.27.7':
|
||||
resolution: {integrity: sha512-62dPZHpIXzvChfvfLJow3q5dDtiNMkwiRzPylSCfriLvZeq0a1bWChrGx/BbUbPwOrsWKMn8idSllklzBy+dgQ==}
|
||||
'@esbuild/android-arm64@0.28.1':
|
||||
resolution: {integrity: sha512-34EGEbCIAgosYz6goLcopX6Mo7NyGv9tfwEM2/7Ce2VcVRk568iSvniGWcUXIy7wEDR1wzolcxcriFVrWYcwBg==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm64]
|
||||
os: [android]
|
||||
|
||||
'@esbuild/android-arm@0.27.7':
|
||||
resolution: {integrity: sha512-jbPXvB4Yj2yBV7HUfE2KHe4GJX51QplCN1pGbYjvsyCZbQmies29EoJbkEc+vYuU5o45AfQn37vZlyXy4YJ8RQ==}
|
||||
'@esbuild/android-arm@0.28.1':
|
||||
resolution: {integrity: sha512-0k2F129Xdio1TdJfzJ8sy1Q47vUD2NnwdhiAf7drUN1EBTfPf4hsFCtmMgu/6m8JSzsBrlmVjudMBQqOfG8usQ==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm]
|
||||
os: [android]
|
||||
|
||||
'@esbuild/android-x64@0.27.7':
|
||||
resolution: {integrity: sha512-x5VpMODneVDb70PYV2VQOmIUUiBtY3D3mPBG8NxVk5CogneYhkR7MmM3yR/uMdITLrC1ml/NV1rj4bMJuy9MCg==}
|
||||
'@esbuild/android-x64@0.28.1':
|
||||
resolution: {integrity: sha512-dbwY7ltSMDWsRatcRpCnES4F+im88OCUgGZjy52shC7GqHRE/cYlxNbB4Z4UpJswpcc4Qxd2oE/ufM0p61IKng==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [x64]
|
||||
os: [android]
|
||||
|
||||
'@esbuild/darwin-arm64@0.27.7':
|
||||
resolution: {integrity: sha512-5lckdqeuBPlKUwvoCXIgI2D9/ABmPq3Rdp7IfL70393YgaASt7tbju3Ac+ePVi3KDH6N2RqePfHnXkaDtY9fkw==}
|
||||
'@esbuild/darwin-arm64@0.28.1':
|
||||
resolution: {integrity: sha512-TZbWkQY7kvTAXbXUT7uVACR5cMHsDiSz9z7ZKAX/RTq/WJEk3QyRr0wZpNhBDX+/0CtdqUIJlOiodQcta6tY3Q==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm64]
|
||||
os: [darwin]
|
||||
|
||||
'@esbuild/darwin-x64@0.27.7':
|
||||
resolution: {integrity: sha512-rYnXrKcXuT7Z+WL5K980jVFdvVKhCHhUwid+dDYQpH+qu+TefcomiMAJpIiC2EM3Rjtq0sO3StMV/+3w3MyyqQ==}
|
||||
'@esbuild/darwin-x64@0.28.1':
|
||||
resolution: {integrity: sha512-zfdzgK9ACBNZLI/CyHTOx81SyNbM6YXn7rxSgX97VjyiPl9W1i4Ka4fgKECEoFCKGpvBj5qArWIGgQjOwkgskQ==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [x64]
|
||||
os: [darwin]
|
||||
|
||||
'@esbuild/freebsd-arm64@0.27.7':
|
||||
resolution: {integrity: sha512-B48PqeCsEgOtzME2GbNM2roU29AMTuOIN91dsMO30t+Ydis3z/3Ngoj5hhnsOSSwNzS+6JppqWsuhTp6E82l2w==}
|
||||
'@esbuild/freebsd-arm64@0.28.1':
|
||||
resolution: {integrity: sha512-wG2EA8ENdEI0qhkSZMjfqrdY+ziCYCPMmtZjjIwOmXFjmyzEHn+UUxk5of+SYsjtfs3VpnlC7QLzSI5hY/rOAw==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm64]
|
||||
os: [freebsd]
|
||||
|
||||
'@esbuild/freebsd-x64@0.27.7':
|
||||
resolution: {integrity: sha512-jOBDK5XEjA4m5IJK3bpAQF9/Lelu/Z9ZcdhTRLf4cajlB+8VEhFFRjWgfy3M1O4rO2GQ/b2dLwCUGpiF/eATNQ==}
|
||||
'@esbuild/freebsd-x64@0.28.1':
|
||||
resolution: {integrity: sha512-i7dZ9vQgnvSCzi/rYCXNgtF/U+eKZNJBzu3eTQbRgHnM7tNSizLOkRFAl3qzVc/Op/u5YkHHa4pf/3DOYHthLQ==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [x64]
|
||||
os: [freebsd]
|
||||
|
||||
'@esbuild/linux-arm64@0.27.7':
|
||||
resolution: {integrity: sha512-RZPHBoxXuNnPQO9rvjh5jdkRmVizktkT7TCDkDmQ0W2SwHInKCAV95GRuvdSvA7w4VMwfCjUiPwDi0ZO6Nfe9A==}
|
||||
'@esbuild/linux-arm64@0.28.1':
|
||||
resolution: {integrity: sha512-yHs+0uc8+nvEAfAfxrWQKK5peSNzBc4PegcMO0EJ2hT71uA7vB8Ihg2e77R2P7SG5uYjPbHlLLmve4LLLRCf0g==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-arm@0.27.7':
|
||||
resolution: {integrity: sha512-RkT/YXYBTSULo3+af8Ib0ykH8u2MBh57o7q/DAs3lTJlyVQkgQvlrPTnjIzzRPQyavxtPtfg0EopvDyIt0j1rA==}
|
||||
'@esbuild/linux-arm@0.28.1':
|
||||
resolution: {integrity: sha512-qVXBOHQS+d5Y722GwJzJUtOLlX7km3CraOaGormF1pDtPd2C/l1SHRPgjLunLGe51Sh5YYWKMFDyV4SxgMQYTQ==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-ia32@0.27.7':
|
||||
resolution: {integrity: sha512-GA48aKNkyQDbd3KtkplYWT102C5sn/EZTY4XROkxONgruHPU72l+gW+FfF8tf2cFjeHaRbWpOYa/uRBz/Xq1Pg==}
|
||||
'@esbuild/linux-ia32@0.28.1':
|
||||
resolution: {integrity: sha512-d1z4ZuP0ajrfz/FhGT4vv278rX8KnPPJx8i5+AtK7TYbx9Le9F1hyzurZpkEyjkGa9dUGhQow4C1NmeGvqxN2w==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [ia32]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-loong64@0.27.7':
|
||||
resolution: {integrity: sha512-a4POruNM2oWsD4WKvBSEKGIiWQF8fZOAsycHOt6JBpZ+JN2n2JH9WAv56SOyu9X5IqAjqSIPTaJkqN8F7XOQ5Q==}
|
||||
'@esbuild/linux-loong64@0.28.1':
|
||||
resolution: {integrity: sha512-M5sRjUVZrkm1OAPR3dlOYzNmN+loZKGVi1VUQGrwuqLcbR6qeAz+famMhjASeH3YVKvZz+zT1jlh/keC3Rj/lg==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [loong64]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-mips64el@0.27.7':
|
||||
resolution: {integrity: sha512-KabT5I6StirGfIz0FMgl1I+R1H73Gp0ofL9A3nG3i/cYFJzKHhouBV5VWK1CSgKvVaG4q1RNpCTR2LuTVB3fIw==}
|
||||
'@esbuild/linux-mips64el@0.28.1':
|
||||
resolution: {integrity: sha512-mRObBZeHh2OxcBFPWE/FjylkRgZdYuiTR3vaTozquCGOH14iP9oN4x4Ge81CoIDYQrXmIxpFumJBu5MtZpnQJQ==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [mips64el]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-ppc64@0.27.7':
|
||||
resolution: {integrity: sha512-gRsL4x6wsGHGRqhtI+ifpN/vpOFTQtnbsupUF5R5YTAg+y/lKelYR1hXbnBdzDjGbMYjVJLJTd2OFmMewAgwlQ==}
|
||||
'@esbuild/linux-ppc64@0.28.1':
|
||||
resolution: {integrity: sha512-slScBsMAb3GFDcdrCgLwZtPYRoH2H/youv10QiZyRjmsP48fznoveWytSgCI/R0ZcUgpc0ZhIUEx6LHts8yrfQ==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [ppc64]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-riscv64@0.27.7':
|
||||
resolution: {integrity: sha512-hL25LbxO1QOngGzu2U5xeXtxXcW+/GvMN3ejANqXkxZ/opySAZMrc+9LY/WyjAan41unrR3YrmtTsUpwT66InQ==}
|
||||
'@esbuild/linux-riscv64@0.28.1':
|
||||
resolution: {integrity: sha512-kw0owk1o0GFETUJyW0jc0G4Yzs0BHZn0JDZ8JRT088vjJYX777BAs1fDGxAC+q831qOs2DTC96mNsG2opdfyyQ==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [riscv64]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-s390x@0.27.7':
|
||||
resolution: {integrity: sha512-2k8go8Ycu1Kb46vEelhu1vqEP+UeRVj2zY1pSuPdgvbd5ykAw82Lrro28vXUrRmzEsUV0NzCf54yARIK8r0fdw==}
|
||||
'@esbuild/linux-s390x@0.28.1':
|
||||
resolution: {integrity: sha512-/lAIjX8aYFRByhh6L5rYtPEDRqa9de/4V/juOXcta5frjvzXO4/sqEtyytse0g3zZFuWu5cDN0MkLz2qRDD2Ag==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [s390x]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-x64@0.27.7':
|
||||
resolution: {integrity: sha512-hzznmADPt+OmsYzw1EE33ccA+HPdIqiCRq7cQeL1Jlq2gb1+OyWBkMCrYGBJ+sxVzve2ZJEVeePbLM2iEIZSxA==}
|
||||
'@esbuild/linux-x64@0.28.1':
|
||||
resolution: {integrity: sha512-u/anNYF2mmVOEDwLtnQ1wOr3EZ9sTNGLWrsYGYwHWzGA3Si84IOkHXlbWTD1NB+9/1lcnweYKO54uhxZydNzfA==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/netbsd-arm64@0.27.7':
|
||||
resolution: {integrity: sha512-b6pqtrQdigZBwZxAn1UpazEisvwaIDvdbMbmrly7cDTMFnw/+3lVxxCTGOrkPVnsYIosJJXAsILG9XcQS+Yu6w==}
|
||||
'@esbuild/netbsd-arm64@0.28.1':
|
||||
resolution: {integrity: sha512-oks0DYbLwWMmaakTsCb+zL4E+aHRVLom9IJZOAthMQEPiQmydXHkziYEsGYRx0uNV/IjEKGAV941JzH02pflqw==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm64]
|
||||
os: [netbsd]
|
||||
|
||||
'@esbuild/netbsd-x64@0.27.7':
|
||||
resolution: {integrity: sha512-OfatkLojr6U+WN5EDYuoQhtM+1xco+/6FSzJJnuWiUw5eVcicbyK3dq5EeV/QHT1uy6GoDhGbFpprUiHUYggrw==}
|
||||
'@esbuild/netbsd-x64@0.28.1':
|
||||
resolution: {integrity: sha512-aeL6lAnN89Hz43Mlh1G8ARasbuoYvSITDEx0tHh5b7jJnHcssqgjy9Yx430GDpmCa6OyrKoS0aNRjKundRizGg==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [x64]
|
||||
os: [netbsd]
|
||||
|
||||
'@esbuild/openbsd-arm64@0.27.7':
|
||||
resolution: {integrity: sha512-AFuojMQTxAz75Fo8idVcqoQWEHIXFRbOc1TrVcFSgCZtQfSdc1RXgB3tjOn/krRHENUB4j00bfGjyl2mJrU37A==}
|
||||
'@esbuild/openbsd-arm64@0.28.1':
|
||||
resolution: {integrity: sha512-MEFJe5C3R8pwXdZ5Y21oo6m7ePiS0d9pWucn99O/wvyJZChoIQKrQDxKrGeW8F5+T0okTHesAmDeiHDTIq0V/Q==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm64]
|
||||
os: [openbsd]
|
||||
|
||||
'@esbuild/openbsd-x64@0.27.7':
|
||||
resolution: {integrity: sha512-+A1NJmfM8WNDv5CLVQYJ5PshuRm/4cI6WMZRg1by1GwPIQPCTs1GLEUHwiiQGT5zDdyLiRM/l1G0Pv54gvtKIg==}
|
||||
'@esbuild/openbsd-x64@0.28.1':
|
||||
resolution: {integrity: sha512-i/ZLIOafE0Z8cI/XANJAixoJL/uRAoS2xOA3rb0xN+KK0K177cMAsQYkzHtBrtMXAKuAc7HGgcWiZ/sRC1Nxgw==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [x64]
|
||||
os: [openbsd]
|
||||
|
||||
'@esbuild/openharmony-arm64@0.27.7':
|
||||
resolution: {integrity: sha512-+KrvYb/C8zA9CU/g0sR6w2RBw7IGc5J2BPnc3dYc5VJxHCSF1yNMxTV5LQ7GuKteQXZtspjFbiuW5/dOj7H4Yw==}
|
||||
'@esbuild/openharmony-arm64@0.28.1':
|
||||
resolution: {integrity: sha512-ge+Z7EXFNt2BO1oAMsVpiQ8EwndV9i1xXerAeTIK7AtPs3bKFXQM7nlRxDSIUIMeueR1CNXxqztLzdNeReKBJg==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm64]
|
||||
os: [openharmony]
|
||||
|
||||
'@esbuild/sunos-x64@0.27.7':
|
||||
resolution: {integrity: sha512-ikktIhFBzQNt/QDyOL580ti9+5mL/YZeUPKU2ivGtGjdTYoqz6jObj6nOMfhASpS4GU4Q/Clh1QtxWAvcYKamA==}
|
||||
'@esbuild/sunos-x64@0.28.1':
|
||||
resolution: {integrity: sha512-BEjgtECkL3vY+SaSQ6nzVfiALUeFxpawyp8Jmf5PtYhf1Ug40N1h/hxlhts+f1FvSvarEigdxS3BlSMI2PJLcQ==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [x64]
|
||||
os: [sunos]
|
||||
|
||||
'@esbuild/win32-arm64@0.27.7':
|
||||
resolution: {integrity: sha512-7yRhbHvPqSpRUV7Q20VuDwbjW5kIMwTHpptuUzV+AA46kiPze5Z7qgt6CLCK3pWFrHeNfDd1VKgyP4O+ng17CA==}
|
||||
'@esbuild/win32-arm64@0.28.1':
|
||||
resolution: {integrity: sha512-lCv9eK/H6ZJWbE7bh2nw54CZ9M2nupBxJcTsdk/QQnWkdSjKGuxmmH8/GWrlT1eMmZfn4dGcCjRte397WqfQXA==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [arm64]
|
||||
os: [win32]
|
||||
|
||||
'@esbuild/win32-ia32@0.27.7':
|
||||
resolution: {integrity: sha512-SmwKXe6VHIyZYbBLJrhOoCJRB/Z1tckzmgTLfFYOfpMAx63BJEaL9ExI8x7v0oAO3Zh6D/Oi1gVxEYr5oUCFhw==}
|
||||
'@esbuild/win32-ia32@0.28.1':
|
||||
resolution: {integrity: sha512-zvb/mB2bSCoJOpoCBgYKKpX6YM6mJBlBUVUtVj41DlZJVEB6/0CKlRYxP5wWl1C1ILiCoAU5wZZ4q1P3qeS6Eg==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [ia32]
|
||||
os: [win32]
|
||||
|
||||
'@esbuild/win32-x64@0.27.7':
|
||||
resolution: {integrity: sha512-56hiAJPhwQ1R4i+21FVF7V8kSD5zZTdHcVuRFMW0hn753vVfQN8xlx4uOPT4xoGH0Z/oVATuR82AiqSTDIpaHg==}
|
||||
'@esbuild/win32-x64@0.28.1':
|
||||
resolution: {integrity: sha512-bm4Mowrv+GXMlpWX++EcXw/iLyd1o3+bJkC2DkWXYVvgZCqD/bSj9ctZeAMC3cIxgjRVR2Dufaiu4YPxr5gW1A==}
|
||||
engines: {node: '>=18'}
|
||||
cpu: [x64]
|
||||
os: [win32]
|
||||
@@ -1206,7 +1207,7 @@ packages:
|
||||
resolution: {integrity: sha512-3WrrOuZiyaaZPWiEt4G3+IffISVC9HYlWueJEBWED4ZH4aIAC2PnkdnuRrR94M+w6yGWn4AglWtJtBI8YqvgoA==}
|
||||
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
|
||||
peerDependencies:
|
||||
esbuild: '>=0.18'
|
||||
esbuild: '>=0.28.1'
|
||||
|
||||
cac@6.7.14:
|
||||
resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==}
|
||||
@@ -1450,8 +1451,8 @@ packages:
|
||||
resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
esbuild@0.27.7:
|
||||
resolution: {integrity: sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w==}
|
||||
esbuild@0.28.1:
|
||||
resolution: {integrity: sha512-HrJrvZv5ayxBzPfwphOoNzkzOIIlifzk0KJrGK2c8R4+LKpMtpYLQeUdjnwjWv/LZlkH2laZk+4w78pi99D4Vw==}
|
||||
engines: {node: '>=18'}
|
||||
hasBin: true
|
||||
|
||||
@@ -3381,82 +3382,82 @@ snapshots:
|
||||
dependencies:
|
||||
'@jridgewell/trace-mapping': 0.3.9
|
||||
|
||||
'@esbuild/aix-ppc64@0.27.7':
|
||||
'@esbuild/aix-ppc64@0.28.1':
|
||||
optional: true
|
||||
|
||||
'@esbuild/android-arm64@0.27.7':
|
||||
'@esbuild/android-arm64@0.28.1':
|
||||
optional: true
|
||||
|
||||
'@esbuild/android-arm@0.27.7':
|
||||
'@esbuild/android-arm@0.28.1':
|
||||
optional: true
|
||||
|
||||
'@esbuild/android-x64@0.27.7':
|
||||
'@esbuild/android-x64@0.28.1':
|
||||
optional: true
|
||||
|
||||
'@esbuild/darwin-arm64@0.27.7':
|
||||
'@esbuild/darwin-arm64@0.28.1':
|
||||
optional: true
|
||||
|
||||
'@esbuild/darwin-x64@0.27.7':
|
||||
'@esbuild/darwin-x64@0.28.1':
|
||||
optional: true
|
||||
|
||||
'@esbuild/freebsd-arm64@0.27.7':
|
||||
'@esbuild/freebsd-arm64@0.28.1':
|
||||
optional: true
|
||||
|
||||
'@esbuild/freebsd-x64@0.27.7':
|
||||
'@esbuild/freebsd-x64@0.28.1':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-arm64@0.27.7':
|
||||
'@esbuild/linux-arm64@0.28.1':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-arm@0.27.7':
|
||||
'@esbuild/linux-arm@0.28.1':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-ia32@0.27.7':
|
||||
'@esbuild/linux-ia32@0.28.1':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-loong64@0.27.7':
|
||||
'@esbuild/linux-loong64@0.28.1':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-mips64el@0.27.7':
|
||||
'@esbuild/linux-mips64el@0.28.1':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-ppc64@0.27.7':
|
||||
'@esbuild/linux-ppc64@0.28.1':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-riscv64@0.27.7':
|
||||
'@esbuild/linux-riscv64@0.28.1':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-s390x@0.27.7':
|
||||
'@esbuild/linux-s390x@0.28.1':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-x64@0.27.7':
|
||||
'@esbuild/linux-x64@0.28.1':
|
||||
optional: true
|
||||
|
||||
'@esbuild/netbsd-arm64@0.27.7':
|
||||
'@esbuild/netbsd-arm64@0.28.1':
|
||||
optional: true
|
||||
|
||||
'@esbuild/netbsd-x64@0.27.7':
|
||||
'@esbuild/netbsd-x64@0.28.1':
|
||||
optional: true
|
||||
|
||||
'@esbuild/openbsd-arm64@0.27.7':
|
||||
'@esbuild/openbsd-arm64@0.28.1':
|
||||
optional: true
|
||||
|
||||
'@esbuild/openbsd-x64@0.27.7':
|
||||
'@esbuild/openbsd-x64@0.28.1':
|
||||
optional: true
|
||||
|
||||
'@esbuild/openharmony-arm64@0.27.7':
|
||||
'@esbuild/openharmony-arm64@0.28.1':
|
||||
optional: true
|
||||
|
||||
'@esbuild/sunos-x64@0.27.7':
|
||||
'@esbuild/sunos-x64@0.28.1':
|
||||
optional: true
|
||||
|
||||
'@esbuild/win32-arm64@0.27.7':
|
||||
'@esbuild/win32-arm64@0.28.1':
|
||||
optional: true
|
||||
|
||||
'@esbuild/win32-ia32@0.27.7':
|
||||
'@esbuild/win32-ia32@0.28.1':
|
||||
optional: true
|
||||
|
||||
'@esbuild/win32-x64@0.27.7':
|
||||
'@esbuild/win32-x64@0.28.1':
|
||||
optional: true
|
||||
|
||||
'@google/genai@1.52.0':
|
||||
@@ -4218,9 +4219,9 @@ snapshots:
|
||||
dependencies:
|
||||
run-applescript: 7.1.0
|
||||
|
||||
bundle-require@5.1.0(esbuild@0.27.7):
|
||||
bundle-require@5.1.0(esbuild@0.28.1):
|
||||
dependencies:
|
||||
esbuild: 0.27.7
|
||||
esbuild: 0.28.1
|
||||
load-tsconfig: 0.2.5
|
||||
|
||||
cac@6.7.14: {}
|
||||
@@ -4435,34 +4436,34 @@ snapshots:
|
||||
has-tostringtag: 1.0.2
|
||||
hasown: 2.0.4
|
||||
|
||||
esbuild@0.27.7:
|
||||
esbuild@0.28.1:
|
||||
optionalDependencies:
|
||||
'@esbuild/aix-ppc64': 0.27.7
|
||||
'@esbuild/android-arm': 0.27.7
|
||||
'@esbuild/android-arm64': 0.27.7
|
||||
'@esbuild/android-x64': 0.27.7
|
||||
'@esbuild/darwin-arm64': 0.27.7
|
||||
'@esbuild/darwin-x64': 0.27.7
|
||||
'@esbuild/freebsd-arm64': 0.27.7
|
||||
'@esbuild/freebsd-x64': 0.27.7
|
||||
'@esbuild/linux-arm': 0.27.7
|
||||
'@esbuild/linux-arm64': 0.27.7
|
||||
'@esbuild/linux-ia32': 0.27.7
|
||||
'@esbuild/linux-loong64': 0.27.7
|
||||
'@esbuild/linux-mips64el': 0.27.7
|
||||
'@esbuild/linux-ppc64': 0.27.7
|
||||
'@esbuild/linux-riscv64': 0.27.7
|
||||
'@esbuild/linux-s390x': 0.27.7
|
||||
'@esbuild/linux-x64': 0.27.7
|
||||
'@esbuild/netbsd-arm64': 0.27.7
|
||||
'@esbuild/netbsd-x64': 0.27.7
|
||||
'@esbuild/openbsd-arm64': 0.27.7
|
||||
'@esbuild/openbsd-x64': 0.27.7
|
||||
'@esbuild/openharmony-arm64': 0.27.7
|
||||
'@esbuild/sunos-x64': 0.27.7
|
||||
'@esbuild/win32-arm64': 0.27.7
|
||||
'@esbuild/win32-ia32': 0.27.7
|
||||
'@esbuild/win32-x64': 0.27.7
|
||||
'@esbuild/aix-ppc64': 0.28.1
|
||||
'@esbuild/android-arm': 0.28.1
|
||||
'@esbuild/android-arm64': 0.28.1
|
||||
'@esbuild/android-x64': 0.28.1
|
||||
'@esbuild/darwin-arm64': 0.28.1
|
||||
'@esbuild/darwin-x64': 0.28.1
|
||||
'@esbuild/freebsd-arm64': 0.28.1
|
||||
'@esbuild/freebsd-x64': 0.28.1
|
||||
'@esbuild/linux-arm': 0.28.1
|
||||
'@esbuild/linux-arm64': 0.28.1
|
||||
'@esbuild/linux-ia32': 0.28.1
|
||||
'@esbuild/linux-loong64': 0.28.1
|
||||
'@esbuild/linux-mips64el': 0.28.1
|
||||
'@esbuild/linux-ppc64': 0.28.1
|
||||
'@esbuild/linux-riscv64': 0.28.1
|
||||
'@esbuild/linux-s390x': 0.28.1
|
||||
'@esbuild/linux-x64': 0.28.1
|
||||
'@esbuild/netbsd-arm64': 0.28.1
|
||||
'@esbuild/netbsd-x64': 0.28.1
|
||||
'@esbuild/openbsd-arm64': 0.28.1
|
||||
'@esbuild/openbsd-x64': 0.28.1
|
||||
'@esbuild/openharmony-arm64': 0.28.1
|
||||
'@esbuild/sunos-x64': 0.28.1
|
||||
'@esbuild/win32-arm64': 0.28.1
|
||||
'@esbuild/win32-ia32': 0.28.1
|
||||
'@esbuild/win32-x64': 0.28.1
|
||||
|
||||
escalade@3.2.0: {}
|
||||
|
||||
@@ -6016,7 +6017,7 @@ snapshots:
|
||||
|
||||
ts-interface-checker@0.1.13: {}
|
||||
|
||||
ts-jest@29.4.11(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.29.7))(esbuild@0.27.7)(jest-util@29.7.0)(jest@29.7.0(@types/node@22.19.21)(ts-node@10.9.2(@types/node@22.19.21)(typescript@5.5.4)))(typescript@5.5.4):
|
||||
ts-jest@29.4.11(@babel/core@7.29.7)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.29.7))(esbuild@0.28.1)(jest-util@29.7.0)(jest@29.7.0(@types/node@22.19.21)(ts-node@10.9.2(@types/node@22.19.21)(typescript@5.5.4)))(typescript@5.5.4):
|
||||
dependencies:
|
||||
bs-logger: 0.2.6
|
||||
fast-json-stable-stringify: 2.1.0
|
||||
@@ -6034,7 +6035,7 @@ snapshots:
|
||||
'@jest/transform': 29.7.0
|
||||
'@jest/types': 29.6.3
|
||||
babel-jest: 29.7.0(@babel/core@7.29.7)
|
||||
esbuild: 0.27.7
|
||||
esbuild: 0.28.1
|
||||
jest-util: 29.7.0
|
||||
|
||||
ts-node@10.9.2(@types/node@22.19.21)(typescript@5.5.4):
|
||||
@@ -6059,12 +6060,12 @@ snapshots:
|
||||
|
||||
tsup@8.5.1(typescript@5.5.4):
|
||||
dependencies:
|
||||
bundle-require: 5.1.0(esbuild@0.27.7)
|
||||
bundle-require: 5.1.0(esbuild@0.28.1)
|
||||
cac: 6.7.14
|
||||
chokidar: 4.0.3
|
||||
consola: 3.4.2
|
||||
debug: 4.4.3(supports-color@5.5.0)
|
||||
esbuild: 0.27.7
|
||||
esbuild: 0.28.1
|
||||
fix-dts-default-cjs-exports: 1.0.1
|
||||
joycon: 3.1.1
|
||||
picocolors: 1.1.1
|
||||
|
||||
@@ -22,3 +22,4 @@ overrides:
|
||||
"tar-fs@>=2.0.0 <2.1.4": "^2.1.4"
|
||||
"glob@>=10.2.0 <10.5.0": "^10.5.0"
|
||||
"@modelcontextprotocol/sdk": "^1.25.4"
|
||||
"esbuild": ">=0.28.1"
|
||||
|
||||
@@ -3,9 +3,7 @@
|
||||
*
|
||||
* Used to stitch PostHog identities: SDKs and CLIs persist anonymous
|
||||
* distinct_id values here, and the TS MemoryClient reads those on init to
|
||||
* fire $identify and merge them into the email identity. The OSS user_id is
|
||||
* only a stitch candidate when telemetry.oss_used_at proves OSS Memory
|
||||
* actually ran here (the platform client never mints ids itself).
|
||||
* fire $identify and merge them into the email identity.
|
||||
*
|
||||
* Node-only. Browsers (no `process.versions.node`) no-op.
|
||||
*/
|
||||
@@ -13,7 +11,6 @@
|
||||
export interface Mem0AnonIds {
|
||||
oss?: string;
|
||||
cli?: string;
|
||||
ossUsedAt?: string;
|
||||
aliasedPairs: string[];
|
||||
}
|
||||
|
||||
@@ -113,10 +110,6 @@ export async function readMem0AnonIds(): Promise<Mem0AnonIds | null> {
|
||||
typeof telemetry.anonymous_id === "string"
|
||||
? telemetry.anonymous_id
|
||||
: undefined,
|
||||
ossUsedAt:
|
||||
typeof telemetry.oss_used_at === "string" && telemetry.oss_used_at
|
||||
? telemetry.oss_used_at
|
||||
: undefined,
|
||||
aliasedPairs: Array.isArray(telemetry.aliased_pairs)
|
||||
? telemetry.aliased_pairs.filter(
|
||||
(item: unknown) => typeof item === "string",
|
||||
@@ -144,26 +137,6 @@ export async function isMem0Aliased(
|
||||
return aliasedPairs.includes(aliasPairMarker(node, anonId, email));
|
||||
}
|
||||
|
||||
export async function markMem0OssUsed(): Promise<void> {
|
||||
const node = await getNodeFs();
|
||||
if (!node) return;
|
||||
try {
|
||||
const config = loadConfig(node) ?? {};
|
||||
const telemetry =
|
||||
config.telemetry && typeof config.telemetry === "object"
|
||||
? config.telemetry
|
||||
: {};
|
||||
if (typeof telemetry.oss_used_at === "string" && telemetry.oss_used_at) {
|
||||
return;
|
||||
}
|
||||
telemetry.oss_used_at = new Date().toISOString();
|
||||
config.telemetry = telemetry;
|
||||
writeConfig(node, config);
|
||||
} catch {
|
||||
// Best-effort: read-only filesystems and unwritable paths just skip.
|
||||
}
|
||||
}
|
||||
|
||||
export async function markMem0Aliased(
|
||||
anonId: string,
|
||||
email: string,
|
||||
|
||||
+11
-10
@@ -27,7 +27,12 @@ import {
|
||||
isTelemetryEnabled,
|
||||
telemetry,
|
||||
} from "./telemetry";
|
||||
import { isMem0Aliased, markMem0Aliased, readMem0AnonIds } from "./config";
|
||||
import {
|
||||
getOrCreateMem0UserId,
|
||||
isMem0Aliased,
|
||||
markMem0Aliased,
|
||||
readMem0AnonIds,
|
||||
} from "./config";
|
||||
import { camelToSnake, camelToSnakeKeys, snakeToCamelKeys } from "./utils";
|
||||
import { createExceptionFromResponse, MemoryError } from "../common/exceptions";
|
||||
|
||||
@@ -146,16 +151,12 @@ export default class MemoryClient {
|
||||
try {
|
||||
const email = this.telemetryId;
|
||||
if (!email || !email.includes("@")) return;
|
||||
const sharedAnonId = await getOrCreateMem0UserId();
|
||||
const anonIds = await readMem0AnonIds();
|
||||
if (!anonIds) return;
|
||||
// The OSS user_id is only a stitch candidate when telemetry.oss_used_at
|
||||
// proves OSS Memory actually ran here; never mint an id from the
|
||||
// platform client path. The CLI anon id is presence-based (only the
|
||||
// CLIs write it).
|
||||
const candidates = [
|
||||
anonIds.ossUsedAt ? anonIds.oss : undefined,
|
||||
anonIds.cli,
|
||||
].filter((id): id is string => !!id && id !== email);
|
||||
if (!anonIds && !sharedAnonId) return;
|
||||
const candidates = [anonIds?.oss || sharedAnonId, anonIds?.cli].filter(
|
||||
(id): id is string => !!id && id !== email,
|
||||
);
|
||||
const seen = new Set<string>();
|
||||
for (const anonId of candidates) {
|
||||
if (seen.has(anonId) || (await isMem0Aliased(anonId, email))) continue;
|
||||
|
||||
@@ -85,7 +85,6 @@ class UnifiedTelemetry implements TelemetryClient {
|
||||
properties: {
|
||||
$anon_distinct_id: anonId,
|
||||
client_source: "typescript",
|
||||
client_version: version,
|
||||
$lib: "posthog-node",
|
||||
},
|
||||
};
|
||||
|
||||
@@ -13,7 +13,6 @@ import {
|
||||
getOrCreateMem0UserId,
|
||||
isMem0Aliased,
|
||||
markMem0Aliased,
|
||||
markMem0OssUsed,
|
||||
readMem0AnonIds,
|
||||
} from "../config";
|
||||
import { TEST_API_KEY } from "./helpers";
|
||||
@@ -146,55 +145,6 @@ describe("config.ts — readMem0AnonIds / markMem0Aliased", () => {
|
||||
markMem0Aliased("oss-uuid", "user@example.com"),
|
||||
).resolves.toBeUndefined();
|
||||
});
|
||||
|
||||
test("markMem0OssUsed writes marker preserving other fields", async () => {
|
||||
fs.writeFileSync(
|
||||
path.join(tmpHome, "config.json"),
|
||||
JSON.stringify({
|
||||
user_id: "oss-uuid",
|
||||
telemetry: { anonymous_id: "cli-anon", aliased_pairs: ["pair-marker"] },
|
||||
}),
|
||||
);
|
||||
await markMem0OssUsed();
|
||||
const written = JSON.parse(
|
||||
fs.readFileSync(path.join(tmpHome, "config.json"), "utf8"),
|
||||
);
|
||||
expect(written.user_id).toBe("oss-uuid");
|
||||
expect(written.telemetry.anonymous_id).toBe("cli-anon");
|
||||
expect(written.telemetry.aliased_pairs).toEqual(["pair-marker"]);
|
||||
expect(written.telemetry.oss_used_at).toBeTruthy();
|
||||
});
|
||||
|
||||
test("markMem0OssUsed is idempotent", async () => {
|
||||
await markMem0OssUsed();
|
||||
const first = JSON.parse(
|
||||
fs.readFileSync(path.join(tmpHome, "config.json"), "utf8"),
|
||||
).telemetry.oss_used_at;
|
||||
await markMem0OssUsed();
|
||||
const second = JSON.parse(
|
||||
fs.readFileSync(path.join(tmpHome, "config.json"), "utf8"),
|
||||
).telemetry.oss_used_at;
|
||||
expect(second).toBe(first);
|
||||
});
|
||||
|
||||
test("readMem0AnonIds surfaces ossUsedAt", async () => {
|
||||
fs.writeFileSync(
|
||||
path.join(tmpHome, "config.json"),
|
||||
JSON.stringify({
|
||||
user_id: "oss-uuid",
|
||||
telemetry: { oss_used_at: "2026-01-01T00:00:00.000Z" },
|
||||
}),
|
||||
);
|
||||
const ids = await readMem0AnonIds();
|
||||
expect(ids?.oss).toBe("oss-uuid");
|
||||
expect(ids?.ossUsedAt).toBe("2026-01-01T00:00:00.000Z");
|
||||
});
|
||||
|
||||
test("markMem0OssUsed does not throw when target dir is unwritable", async () => {
|
||||
fs.writeFileSync(path.join(tmpHome, "blocker"), "x");
|
||||
process.env.MEM0_DIR = path.join(tmpHome, "blocker"); // file used as dir
|
||||
await expect(markMem0OssUsed()).resolves.toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
// ─── telemetry.captureIdentify ───────────────────────────────
|
||||
@@ -216,7 +166,6 @@ describe("telemetry.captureIdentify", () => {
|
||||
expect(payload.event).toBe("$identify");
|
||||
expect(payload.distinct_id).toBe("user@example.com");
|
||||
expect(payload.properties.$anon_distinct_id).toBe("anon-uuid");
|
||||
expect(payload.properties.client_version).toBeTruthy();
|
||||
expect(payload.properties.$process_person_profile).toBeUndefined();
|
||||
});
|
||||
|
||||
@@ -271,10 +220,7 @@ describe("MemoryClient — _maybeAliasAnonToEmail", () => {
|
||||
test("fires $identify on first init and persists pair marker", async () => {
|
||||
fs.writeFileSync(
|
||||
path.join(tmpHome, "config.json"),
|
||||
JSON.stringify({
|
||||
user_id: "oss-uuid",
|
||||
telemetry: { oss_used_at: "2026-01-01T00:00:00.000Z" },
|
||||
}),
|
||||
JSON.stringify({ user_id: "oss-uuid" }),
|
||||
);
|
||||
const fetchMock = setupMockFetchWithPostHog();
|
||||
|
||||
@@ -298,38 +244,17 @@ describe("MemoryClient — _maybeAliasAnonToEmail", () => {
|
||||
expect(written.telemetry.aliased_pairs).toHaveLength(1);
|
||||
});
|
||||
|
||||
test("platform-only init mints nothing and fires no $identify", async () => {
|
||||
// Regression: the client used to create the shared anon id itself and
|
||||
// immediately stitch it, merging an event-less anon person into every
|
||||
// platform user. The platform path must now be read-only.
|
||||
test("platform-first init creates shared anon ID and identifies it", async () => {
|
||||
const fetchMock = setupMockFetchWithPostHog();
|
||||
|
||||
const client = makeStubClient("test@example.com");
|
||||
await (client as any)._maybeAliasAnonToEmail();
|
||||
|
||||
expect(fs.existsSync(path.join(tmpHome, "config.json"))).toBe(false);
|
||||
|
||||
const identifyCalls = (fetchMock.mock.calls as any[]).filter(
|
||||
([, init]: [string, RequestInit]) => {
|
||||
if (!init?.body) return false;
|
||||
return JSON.parse(init.body as string).event === "$identify";
|
||||
},
|
||||
const written = JSON.parse(
|
||||
fs.readFileSync(path.join(tmpHome, "config.json"), "utf8"),
|
||||
);
|
||||
expect(identifyCalls.length).toBe(0);
|
||||
});
|
||||
|
||||
test("oss id without oss_used_at marker is not stitched; cli id still is", async () => {
|
||||
fs.writeFileSync(
|
||||
path.join(tmpHome, "config.json"),
|
||||
JSON.stringify({
|
||||
user_id: "oss-uuid",
|
||||
telemetry: { anonymous_id: "cli-anon" },
|
||||
}),
|
||||
);
|
||||
const fetchMock = setupMockFetchWithPostHog();
|
||||
|
||||
const client = makeStubClient("test@example.com");
|
||||
await (client as any)._maybeAliasAnonToEmail();
|
||||
expect(written.user_id).toBeTruthy();
|
||||
expect(written.telemetry.aliased_pairs).toHaveLength(1);
|
||||
|
||||
const identifyCalls = (fetchMock.mock.calls as any[]).filter(
|
||||
([, init]: [string, RequestInit]) => {
|
||||
@@ -339,32 +264,8 @@ describe("MemoryClient — _maybeAliasAnonToEmail", () => {
|
||||
);
|
||||
expect(identifyCalls.length).toBe(1);
|
||||
const body = JSON.parse(identifyCalls[0][1].body);
|
||||
expect(body.properties.$anon_distinct_id).toBe("cli-anon");
|
||||
});
|
||||
|
||||
test("stitches config written by the Python SDK (cross-SDK key compat)", async () => {
|
||||
// Python writes datetime.now(timezone.utc).isoformat(): +00:00 offset.
|
||||
fs.writeFileSync(
|
||||
path.join(tmpHome, "config.json"),
|
||||
JSON.stringify({
|
||||
user_id: "oss-uuid",
|
||||
telemetry: { oss_used_at: "2026-01-01T00:00:00+00:00" },
|
||||
}),
|
||||
);
|
||||
const fetchMock = setupMockFetchWithPostHog();
|
||||
|
||||
const client = makeStubClient("test@example.com");
|
||||
await (client as any)._maybeAliasAnonToEmail();
|
||||
|
||||
const identifyCalls = (fetchMock.mock.calls as any[]).filter(
|
||||
([, init]: [string, RequestInit]) => {
|
||||
if (!init?.body) return false;
|
||||
return JSON.parse(init.body as string).event === "$identify";
|
||||
},
|
||||
);
|
||||
expect(identifyCalls.length).toBe(1);
|
||||
const body = JSON.parse(identifyCalls[0][1].body);
|
||||
expect(body.properties.$anon_distinct_id).toBe("oss-uuid");
|
||||
expect(body.distinct_id).toBe("test@example.com");
|
||||
expect(body.properties.$anon_distinct_id).toBe(written.user_id);
|
||||
});
|
||||
|
||||
test("second init does not refire $identify", async () => {
|
||||
@@ -372,7 +273,7 @@ describe("MemoryClient — _maybeAliasAnonToEmail", () => {
|
||||
path.join(tmpHome, "config.json"),
|
||||
JSON.stringify({
|
||||
user_id: "oss-uuid",
|
||||
telemetry: { oss_used_at: "2026-01-01T00:00:00.000Z" },
|
||||
telemetry: {},
|
||||
}),
|
||||
);
|
||||
await markMem0Aliased("oss-uuid", "test@example.com");
|
||||
@@ -395,10 +296,7 @@ describe("MemoryClient — _maybeAliasAnonToEmail", () => {
|
||||
path.join(tmpHome, "config.json"),
|
||||
JSON.stringify({
|
||||
user_id: "oss-uuid",
|
||||
telemetry: {
|
||||
anonymous_id: "cli-anon",
|
||||
oss_used_at: "2026-01-01T00:00:00.000Z",
|
||||
},
|
||||
telemetry: { anonymous_id: "cli-anon" },
|
||||
}),
|
||||
);
|
||||
const fetchMock = setupMockFetchWithPostHog();
|
||||
@@ -509,18 +407,4 @@ describe("config.ts in browser-like environment", () => {
|
||||
jest.resetModules();
|
||||
}
|
||||
});
|
||||
|
||||
test("markMem0OssUsed is a no-op when not Node", async () => {
|
||||
const originalProcess = global.process;
|
||||
// @ts-expect-error force-undefining global to simulate a browser
|
||||
delete global.process;
|
||||
try {
|
||||
jest.resetModules();
|
||||
const { markMem0OssUsed: browserMark } = await import("../config");
|
||||
await expect(browserMark()).resolves.toBeUndefined();
|
||||
} finally {
|
||||
global.process = originalProcess;
|
||||
jest.resetModules();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -112,6 +112,13 @@ export class ConfigManager {
|
||||
| undefined) ??
|
||||
userConf?.url ??
|
||||
defaultConf.baseURL;
|
||||
const llmRaw = userConf as Record<string, unknown> | undefined;
|
||||
const temperature =
|
||||
userConf?.temperature ??
|
||||
(llmRaw?.temperature as number | undefined);
|
||||
const topP = userConf?.topP ?? (llmRaw?.top_p as number | undefined);
|
||||
const maxTokens =
|
||||
userConf?.maxTokens ?? (llmRaw?.max_tokens as number | undefined);
|
||||
|
||||
return {
|
||||
baseURL: llmBaseURL,
|
||||
@@ -125,6 +132,9 @@ export class ConfigManager {
|
||||
userConf?.modelProperties !== undefined
|
||||
? userConf.modelProperties
|
||||
: defaultConf.modelProperties,
|
||||
temperature,
|
||||
topP,
|
||||
maxTokens,
|
||||
};
|
||||
})(),
|
||||
},
|
||||
|
||||
@@ -5,6 +5,9 @@ import { LLMConfig, Message } from "../types";
|
||||
export class AnthropicLLM implements LLM {
|
||||
private client: Anthropic;
|
||||
private model: string;
|
||||
private maxTokens: number;
|
||||
private temperature?: number;
|
||||
private topP?: number;
|
||||
|
||||
constructor(config: LLMConfig) {
|
||||
const apiKey = config.apiKey || process.env.ANTHROPIC_API_KEY;
|
||||
@@ -12,18 +15,24 @@ export class AnthropicLLM implements LLM {
|
||||
throw new Error("Anthropic API key is required");
|
||||
}
|
||||
this.client = new Anthropic({ apiKey });
|
||||
this.model = config.model || "claude-3-sonnet-20240229";
|
||||
this.model = config.model || "claude-sonnet-4-6";
|
||||
// Defaults mirror the Python provider's AnthropicConfig
|
||||
// (max_tokens=2000, temperature=0.1, top_p omitted).
|
||||
this.maxTokens = config.maxTokens ?? 2000;
|
||||
this.temperature = config.temperature ?? 0.1;
|
||||
this.topP = config.topP;
|
||||
}
|
||||
|
||||
async generateResponse(
|
||||
messages: Message[],
|
||||
responseFormat?: { type: string },
|
||||
): Promise<string> {
|
||||
tools?: any[],
|
||||
): Promise<string | LLMResponse> {
|
||||
// Extract system message if present
|
||||
const systemMessage = messages.find((msg) => msg.role === "system");
|
||||
const otherMessages = messages.filter((msg) => msg.role !== "system");
|
||||
|
||||
const response = await this.client.messages.create({
|
||||
const params: Anthropic.MessageCreateParamsNonStreaming = {
|
||||
model: this.model,
|
||||
messages: otherMessages.map((msg) => ({
|
||||
role: msg.role as "user" | "assistant",
|
||||
@@ -36,8 +45,41 @@ export class AnthropicLLM implements LLM {
|
||||
typeof systemMessage?.content === "string"
|
||||
? systemMessage.content
|
||||
: undefined,
|
||||
max_tokens: 4096,
|
||||
});
|
||||
max_tokens: this.maxTokens,
|
||||
};
|
||||
|
||||
// Anthropic rejects requests that include both temperature and top_p;
|
||||
// prefer temperature, matching the Python provider's _get_common_params.
|
||||
if (this.temperature !== undefined) {
|
||||
params.temperature = this.temperature;
|
||||
} else if (this.topP !== undefined) {
|
||||
params.top_p = this.topP;
|
||||
}
|
||||
|
||||
if (tools) {
|
||||
params.tools = tools;
|
||||
params.tool_choice = { type: "auto" };
|
||||
}
|
||||
|
||||
const response = await this.client.messages.create(params);
|
||||
|
||||
if (tools) {
|
||||
let content = "";
|
||||
const toolCalls: Array<{ name: string; arguments: string }> = [];
|
||||
|
||||
for (const block of response.content) {
|
||||
if (block.type === "text") {
|
||||
content = block.text;
|
||||
} else if (block.type === "tool_use") {
|
||||
toolCalls.push({
|
||||
name: block.name,
|
||||
arguments: JSON.stringify(block.input),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return { content, role: "assistant", toolCalls };
|
||||
}
|
||||
|
||||
const firstBlock = response.content[0];
|
||||
if (firstBlock.type === "text") {
|
||||
@@ -49,9 +91,9 @@ export class AnthropicLLM implements LLM {
|
||||
|
||||
async generateChat(messages: Message[]): Promise<LLMResponse> {
|
||||
const response = await this.generateResponse(messages);
|
||||
return {
|
||||
content: response,
|
||||
role: "assistant",
|
||||
};
|
||||
if (typeof response === "string") {
|
||||
return { content: response, role: "assistant" };
|
||||
}
|
||||
return response;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@ import {
|
||||
} from "./memory.types";
|
||||
import { parse_vision_messages } from "../utils/memory";
|
||||
import { HistoryManager } from "../storage/base";
|
||||
import { captureClientEvent, isTelemetryEnabled } from "../utils/telemetry";
|
||||
import { captureClientEvent } from "../utils/telemetry";
|
||||
import {
|
||||
detectScaleThresholdFromAddResult,
|
||||
detectScaleThresholdFromTopK,
|
||||
@@ -72,7 +72,7 @@ import {
|
||||
ScoredResult,
|
||||
} from "../utils/scoring";
|
||||
import { getDefaultVectorStoreDbPath } from "../utils/sqlite";
|
||||
import { getOrCreateMem0UserId, markMem0OssUsed } from "../../../client/config";
|
||||
import { getOrCreateMem0UserId } from "../../../client/config";
|
||||
|
||||
// Entity params that must be passed via filters - check both snake_case and camelCase
|
||||
const ENTITY_PARAMS = [
|
||||
@@ -84,6 +84,58 @@ const ENTITY_PARAMS = [
|
||||
"runId",
|
||||
];
|
||||
|
||||
const ADD_CONTEXT_SEARCH_MAX_CHARS = 15000;
|
||||
const ADD_MAX_EXTRACTED_MEMORIES = 20;
|
||||
const ADD_MEMORY_EMBEDDING_MAX_CHARS = 15000;
|
||||
const ADD_MAX_ENTITY_LINKS_PER_EVENT = 100;
|
||||
const SEARCH_QUERY_MAX_CHARS = 15000;
|
||||
|
||||
function tailCapText(text: string, maxChars: number): string {
|
||||
if (text.length <= maxChars) return text;
|
||||
return text.slice(-maxChars);
|
||||
}
|
||||
|
||||
function capExtractedMemories<T>(memories: T[]): T[] {
|
||||
if (memories.length <= ADD_MAX_EXTRACTED_MEMORIES) return memories;
|
||||
console.warn(
|
||||
`Extracted memory cap applied: extracted=${memories.length} processing=${ADD_MAX_EXTRACTED_MEMORIES}`,
|
||||
);
|
||||
return memories.slice(-ADD_MAX_EXTRACTED_MEMORIES);
|
||||
}
|
||||
|
||||
function capMemoryEmbeddingTexts(texts: string[]): string[] {
|
||||
const capped = texts.map((text) =>
|
||||
tailCapText(text, ADD_MEMORY_EMBEDDING_MAX_CHARS),
|
||||
);
|
||||
const cappedCount = texts.filter(
|
||||
(text, index) => text !== capped[index],
|
||||
).length;
|
||||
if (cappedCount > 0) {
|
||||
console.warn(
|
||||
`Memory embedding input cap applied: capped_count=${cappedCount} max_chars=${ADD_MEMORY_EMBEDDING_MAX_CHARS}`,
|
||||
);
|
||||
}
|
||||
return capped;
|
||||
}
|
||||
|
||||
function capSearchQuery(query: string): string {
|
||||
const capped = tailCapText(query, SEARCH_QUERY_MAX_CHARS);
|
||||
if (capped.length !== query.length) {
|
||||
console.warn(
|
||||
`Search query cap applied: original_chars=${query.length} searched_chars=${capped.length}`,
|
||||
);
|
||||
}
|
||||
return capped;
|
||||
}
|
||||
|
||||
function capEntityKeys(keys: string[]): string[] {
|
||||
if (keys.length <= ADD_MAX_ENTITY_LINKS_PER_EVENT) return keys;
|
||||
console.warn(
|
||||
`ADD entity-linking cap applied: extracted=${keys.length} processing=${ADD_MAX_ENTITY_LINKS_PER_EVENT}`,
|
||||
);
|
||||
return keys.slice(0, ADD_MAX_ENTITY_LINKS_PER_EVENT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates that no top-level entity parameters are passed in config.
|
||||
* @throws Error if entity params are found at top level
|
||||
@@ -470,12 +522,6 @@ export class Memory {
|
||||
try {
|
||||
await this._getTelemetryId();
|
||||
|
||||
// Record genuine OSS usage so the platform client may stitch this
|
||||
// machine's anon id to a platform email later.
|
||||
if (isTelemetryEnabled()) {
|
||||
await markMem0OssUsed();
|
||||
}
|
||||
|
||||
// Capture initialization event
|
||||
await captureClientEvent("init", this, {
|
||||
api_version: this.apiVersion,
|
||||
@@ -740,7 +786,16 @@ export class Memory {
|
||||
const parsedMessages = messages.map((m) => m.content).join("\n");
|
||||
|
||||
// Phase 1: Existing memory retrieval
|
||||
const queryEmbedding = await this.embedder.embed(parsedMessages);
|
||||
const searchMessages = tailCapText(
|
||||
parsedMessages,
|
||||
ADD_CONTEXT_SEARCH_MAX_CHARS,
|
||||
);
|
||||
if (searchMessages.length !== parsedMessages.length) {
|
||||
console.warn(
|
||||
`ADD context-search embedding capped: original_chars=${parsedMessages.length} embedded_chars=${searchMessages.length}`,
|
||||
);
|
||||
}
|
||||
const queryEmbedding = await this.embedder.embed(searchMessages);
|
||||
const existingResults = await this.vectorStore.search(
|
||||
queryEmbedding,
|
||||
10,
|
||||
@@ -811,6 +866,7 @@ export class Memory {
|
||||
console.error("Error parsing extraction response:", e);
|
||||
extractedMemories = [];
|
||||
}
|
||||
extractedMemories = capExtractedMemories(extractedMemories);
|
||||
|
||||
if (extractedMemories.length === 0) {
|
||||
// Save messages even if nothing extracted
|
||||
@@ -832,17 +888,21 @@ export class Memory {
|
||||
const memTexts = extractedMemories
|
||||
.map((m) => m.text ?? "")
|
||||
.filter((t) => t.length > 0);
|
||||
const memEmbeddingTexts = capMemoryEmbeddingTexts(memTexts);
|
||||
let embedMap: Record<string, number[]> = {};
|
||||
try {
|
||||
const memEmbeddingsList = await this.embedder.embedBatch(memTexts);
|
||||
const memEmbeddingsList =
|
||||
await this.embedder.embedBatch(memEmbeddingTexts);
|
||||
for (let i = 0; i < memTexts.length; i++) {
|
||||
embedMap[memTexts[i]] = memEmbeddingsList[i];
|
||||
}
|
||||
} catch {
|
||||
// Fallback: embed individually
|
||||
for (const text of memTexts) {
|
||||
for (let i = 0; i < memTexts.length; i++) {
|
||||
const text = memTexts[i];
|
||||
const embeddingText = memEmbeddingTexts[i];
|
||||
try {
|
||||
embedMap[text] = await this.embedder.embed(text);
|
||||
embedMap[text] = await this.embedder.embed(embeddingText);
|
||||
} catch (e) {
|
||||
console.warn(`Failed to embed memory text: ${e}`);
|
||||
}
|
||||
@@ -1013,9 +1073,8 @@ export class Memory {
|
||||
|
||||
const orderedKeys = Object.keys(globalEntities);
|
||||
if (orderedKeys.length > 0) {
|
||||
const entityTexts = orderedKeys.map(
|
||||
(k) => globalEntities[k].entityText,
|
||||
);
|
||||
const entityKeys = capEntityKeys(orderedKeys);
|
||||
const entityTexts = entityKeys.map((k) => globalEntities[k].entityText);
|
||||
|
||||
// 7b: Single batch embed for all unique entities
|
||||
let entityEmbeddings: (number[] | null)[];
|
||||
@@ -1035,9 +1094,9 @@ export class Memory {
|
||||
|
||||
// Filter out entities with failed embeddings
|
||||
const valid: Array<{ index: number; key: string }> = [];
|
||||
for (let i = 0; i < orderedKeys.length; i++) {
|
||||
for (let i = 0; i < entityKeys.length; i++) {
|
||||
if (entityEmbeddings[i] !== null) {
|
||||
valid.push({ index: i, key: orderedKeys[i] });
|
||||
valid.push({ index: i, key: entityKeys[i] });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1262,6 +1321,7 @@ export class Memory {
|
||||
}
|
||||
|
||||
const searchStartMs = Date.now();
|
||||
query = capSearchQuery(query);
|
||||
|
||||
// Step 1: Preprocess query
|
||||
const queryLemmatized = lemmatizeForBm25(query);
|
||||
@@ -1728,20 +1788,13 @@ export class Memory {
|
||||
existingEmbeddings[data] || (await this.embedder.embed(data));
|
||||
|
||||
const newMetadata = {
|
||||
...existingMemory.payload,
|
||||
...metadata,
|
||||
data,
|
||||
hash: createHash("md5").update(data).digest("hex"),
|
||||
textLemmatized: lemmatizeForBm25(data),
|
||||
createdAt: existingMemory.payload.createdAt,
|
||||
updatedAt: new Date().toISOString(),
|
||||
...(existingMemory.payload.user_id && {
|
||||
user_id: existingMemory.payload.user_id,
|
||||
}),
|
||||
...(existingMemory.payload.agent_id && {
|
||||
agent_id: existingMemory.payload.agent_id,
|
||||
}),
|
||||
...(existingMemory.payload.run_id && {
|
||||
run_id: existingMemory.payload.run_id,
|
||||
}),
|
||||
};
|
||||
|
||||
await this.vectorStore.update(memoryId, embedding, newMetadata);
|
||||
|
||||
@@ -49,6 +49,9 @@ export interface LLMConfig {
|
||||
model?: string | any;
|
||||
modelProperties?: Record<string, any>;
|
||||
timeout?: number;
|
||||
temperature?: number;
|
||||
topP?: number;
|
||||
maxTokens?: number;
|
||||
}
|
||||
|
||||
export interface MemoryConfig {
|
||||
@@ -131,6 +134,9 @@ export const MemoryConfigSchema = z.object({
|
||||
baseURL: z.string().optional(),
|
||||
url: z.string().optional(),
|
||||
timeout: z.number().optional(),
|
||||
temperature: z.number().optional(),
|
||||
topP: z.number().optional(),
|
||||
maxTokens: z.number().optional(),
|
||||
}),
|
||||
}),
|
||||
historyDbPath: z.string().optional(),
|
||||
|
||||
@@ -0,0 +1,263 @@
|
||||
/// <reference types="jest" />
|
||||
/**
|
||||
* Anthropic LLM — unit tests (mocked @anthropic-ai/sdk).
|
||||
*/
|
||||
|
||||
const mockCreate = jest.fn();
|
||||
|
||||
jest.mock("@anthropic-ai/sdk", () => {
|
||||
return jest.fn().mockImplementation(() => ({
|
||||
messages: { create: mockCreate },
|
||||
}));
|
||||
});
|
||||
|
||||
import { AnthropicLLM } from "../src/llms/anthropic";
|
||||
|
||||
describe("AnthropicLLM (unit)", () => {
|
||||
beforeEach(() => mockCreate.mockClear());
|
||||
|
||||
it("returns text when no tools are provided and model returns a text block", async () => {
|
||||
mockCreate.mockResolvedValueOnce({
|
||||
content: [{ type: "text", text: '{"facts": ["fact1"]}' }],
|
||||
});
|
||||
|
||||
const llm = new AnthropicLLM({ apiKey: "test-key" });
|
||||
const result = await llm.generateResponse([
|
||||
{ role: "user", content: "Hello" },
|
||||
]);
|
||||
|
||||
expect(mockCreate).toHaveBeenCalledTimes(1);
|
||||
expect(result).toBe('{"facts": ["fact1"]}');
|
||||
|
||||
// No tools → tool_choice must NOT be forwarded
|
||||
const callArgs = mockCreate.mock.calls[0][0];
|
||||
expect(callArgs.tool_choice).toBeUndefined();
|
||||
});
|
||||
|
||||
// Bug #1 regression: bare string "auto" must NOT be sent; object form required
|
||||
it("forwards tool_choice as { type: 'auto' } (not bare string) when tools are provided", async () => {
|
||||
mockCreate.mockResolvedValueOnce({
|
||||
content: [
|
||||
{
|
||||
type: "tool_use",
|
||||
id: "toolu_1",
|
||||
name: "add_graph_memory",
|
||||
input: { source: "Alice", destination: "Bob" },
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const tools = [
|
||||
{
|
||||
name: "add_graph_memory",
|
||||
description: "Add a graph memory",
|
||||
input_schema: { type: "object", properties: {} },
|
||||
},
|
||||
];
|
||||
|
||||
const llm = new AnthropicLLM({ apiKey: "test-key" });
|
||||
await llm.generateResponse(
|
||||
[{ role: "user", content: "Alice knows Bob" }],
|
||||
undefined,
|
||||
tools,
|
||||
);
|
||||
|
||||
const callArgs = mockCreate.mock.calls[0][0];
|
||||
// Must be object form, not a bare string
|
||||
expect(callArgs.tool_choice).toEqual({ type: "auto" });
|
||||
expect(callArgs.tool_choice).not.toBe("auto");
|
||||
});
|
||||
|
||||
// Bug #2 regression: must NOT throw on a tool_use block
|
||||
it("does NOT throw when the model returns a tool_use block", async () => {
|
||||
mockCreate.mockResolvedValueOnce({
|
||||
content: [
|
||||
{
|
||||
type: "tool_use",
|
||||
id: "toolu_1",
|
||||
name: "add_graph_memory",
|
||||
input: { source: "Alice", destination: "Bob" },
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const tools = [
|
||||
{
|
||||
name: "add_graph_memory",
|
||||
description: "Add a graph memory",
|
||||
input_schema: { type: "object", properties: {} },
|
||||
},
|
||||
];
|
||||
|
||||
const llm = new AnthropicLLM({ apiKey: "test-key" });
|
||||
await expect(
|
||||
llm.generateResponse(
|
||||
[{ role: "user", content: "Alice knows Bob" }],
|
||||
undefined,
|
||||
tools,
|
||||
),
|
||||
).resolves.not.toThrow();
|
||||
});
|
||||
|
||||
it("parses tool_use blocks into toolCalls with JSON-stringified arguments", async () => {
|
||||
const inputObj = { source: "Alice", destination: "Bob" };
|
||||
mockCreate.mockResolvedValueOnce({
|
||||
content: [
|
||||
{
|
||||
type: "tool_use",
|
||||
id: "toolu_1",
|
||||
name: "add_graph_memory",
|
||||
input: inputObj,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const tools = [
|
||||
{
|
||||
name: "add_graph_memory",
|
||||
description: "Add a graph memory",
|
||||
input_schema: { type: "object", properties: {} },
|
||||
},
|
||||
];
|
||||
|
||||
const llm = new AnthropicLLM({ apiKey: "test-key" });
|
||||
const result = await llm.generateResponse(
|
||||
[{ role: "user", content: "Alice knows Bob" }],
|
||||
undefined,
|
||||
tools,
|
||||
);
|
||||
|
||||
expect(result).toHaveProperty("toolCalls");
|
||||
const response = result as {
|
||||
content: string;
|
||||
role: string;
|
||||
toolCalls: Array<{ name: string; arguments: string }>;
|
||||
};
|
||||
expect(response.toolCalls).toHaveLength(1);
|
||||
expect(response.toolCalls[0].name).toBe("add_graph_memory");
|
||||
expect(JSON.parse(response.toolCalls[0].arguments)).toEqual(inputObj);
|
||||
});
|
||||
|
||||
it("handles a mixed text + tool_use response", async () => {
|
||||
const inputObj = { source: "Alice", destination: "Bob" };
|
||||
mockCreate.mockResolvedValueOnce({
|
||||
content: [
|
||||
{ type: "text", text: "Calling the tool now." },
|
||||
{
|
||||
type: "tool_use",
|
||||
id: "toolu_2",
|
||||
name: "add_graph_memory",
|
||||
input: inputObj,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const tools = [
|
||||
{
|
||||
name: "add_graph_memory",
|
||||
description: "Add a graph memory",
|
||||
input_schema: { type: "object", properties: {} },
|
||||
},
|
||||
];
|
||||
|
||||
const llm = new AnthropicLLM({ apiKey: "test-key" });
|
||||
const result = await llm.generateResponse(
|
||||
[{ role: "user", content: "Alice knows Bob" }],
|
||||
undefined,
|
||||
tools,
|
||||
);
|
||||
|
||||
expect(result).toHaveProperty("toolCalls");
|
||||
const response = result as {
|
||||
content: string;
|
||||
role: string;
|
||||
toolCalls: Array<{ name: string; arguments: string }>;
|
||||
};
|
||||
expect(response.content).toBe("Calling the tool now.");
|
||||
expect(response.role).toBe("assistant");
|
||||
expect(response.toolCalls).toHaveLength(1);
|
||||
expect(response.toolCalls[0].name).toBe("add_graph_memory");
|
||||
expect(JSON.parse(response.toolCalls[0].arguments)).toEqual(inputObj);
|
||||
});
|
||||
|
||||
it("returns a structured response when tools are provided but the model returns only a text block", async () => {
|
||||
mockCreate.mockResolvedValueOnce({
|
||||
content: [{ type: "text", text: "Just a text response" }],
|
||||
});
|
||||
|
||||
const tools = [
|
||||
{
|
||||
name: "noop",
|
||||
description: "No operation",
|
||||
input_schema: { type: "object", properties: {} },
|
||||
},
|
||||
];
|
||||
|
||||
const llm = new AnthropicLLM({ apiKey: "test-key" });
|
||||
const result = await llm.generateResponse(
|
||||
[{ role: "user", content: "Hello" }],
|
||||
undefined,
|
||||
tools,
|
||||
);
|
||||
|
||||
expect(result).toEqual({
|
||||
content: "Just a text response",
|
||||
role: "assistant",
|
||||
toolCalls: [],
|
||||
});
|
||||
});
|
||||
|
||||
// Parity with the Python provider's AnthropicConfig defaults:
|
||||
// model claude-sonnet-4-6, max_tokens 2000, temperature 0.1, top_p omitted.
|
||||
it("sends Python-parity defaults (model, max_tokens, temperature)", async () => {
|
||||
mockCreate.mockResolvedValueOnce({
|
||||
content: [{ type: "text", text: "ok" }],
|
||||
});
|
||||
|
||||
const llm = new AnthropicLLM({ apiKey: "test-key" });
|
||||
await llm.generateResponse([{ role: "user", content: "Hi" }]);
|
||||
|
||||
const callArgs = mockCreate.mock.calls[0][0];
|
||||
expect(callArgs.model).toBe("claude-sonnet-4-6");
|
||||
expect(callArgs.max_tokens).toBe(2000);
|
||||
expect(callArgs.temperature).toBe(0.1);
|
||||
expect(callArgs.top_p).toBeUndefined();
|
||||
});
|
||||
|
||||
it("forwards maxTokens, temperature, and model from config", async () => {
|
||||
mockCreate.mockResolvedValueOnce({
|
||||
content: [{ type: "text", text: "ok" }],
|
||||
});
|
||||
|
||||
const llm = new AnthropicLLM({
|
||||
apiKey: "test-key",
|
||||
model: "claude-opus-4-8",
|
||||
maxTokens: 1024,
|
||||
temperature: 0.7,
|
||||
});
|
||||
await llm.generateResponse([{ role: "user", content: "Hi" }]);
|
||||
|
||||
const callArgs = mockCreate.mock.calls[0][0];
|
||||
expect(callArgs.model).toBe("claude-opus-4-8");
|
||||
expect(callArgs.max_tokens).toBe(1024);
|
||||
expect(callArgs.temperature).toBe(0.7);
|
||||
});
|
||||
|
||||
// Anthropic rejects requests with both temperature and top_p set.
|
||||
it("never sends both temperature and top_p (prefers temperature)", async () => {
|
||||
mockCreate.mockResolvedValueOnce({
|
||||
content: [{ type: "text", text: "ok" }],
|
||||
});
|
||||
|
||||
const llm = new AnthropicLLM({
|
||||
apiKey: "test-key",
|
||||
temperature: 0.5,
|
||||
topP: 0.9,
|
||||
});
|
||||
await llm.generateResponse([{ role: "user", content: "Hi" }]);
|
||||
|
||||
const callArgs = mockCreate.mock.calls[0][0];
|
||||
expect(callArgs.temperature).toBe(0.5);
|
||||
expect(callArgs.top_p).toBeUndefined();
|
||||
});
|
||||
});
|
||||
@@ -176,3 +176,79 @@ describe("Memory - add()", () => {
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe("Memory - ingestion caps", () => {
|
||||
test("caps add context-search embedding to the recent tail", async () => {
|
||||
const memory = createMemory({
|
||||
vectorStore: {
|
||||
provider: "memory",
|
||||
config: {
|
||||
collectionName: `test-add-context-cap-${Date.now()}`,
|
||||
dimension: 1536,
|
||||
dbPath: ":memory:",
|
||||
},
|
||||
},
|
||||
});
|
||||
const embedSpy = jest.spyOn((memory as any).embedder, "embed");
|
||||
const longText = `old-${"x".repeat(15000)}`;
|
||||
|
||||
await memory.add(longText, { userId: `cap_user_${Date.now()}` });
|
||||
|
||||
expect(embedSpy.mock.calls[0][0]).toBe(longText.slice(-15000));
|
||||
await memory.reset();
|
||||
});
|
||||
|
||||
test("caps extracted memories to the latest 20 before embedding", async () => {
|
||||
const memory = createMemory({
|
||||
vectorStore: {
|
||||
provider: "memory",
|
||||
config: {
|
||||
collectionName: `test-add-memory-cap-${Date.now()}`,
|
||||
dimension: 1536,
|
||||
dbPath: ":memory:",
|
||||
},
|
||||
},
|
||||
});
|
||||
(memory as any).llm.generateResponse = jest.fn().mockResolvedValue(
|
||||
JSON.stringify({
|
||||
memory: Array.from({ length: 25 }, (_, i) => ({
|
||||
id: String(i),
|
||||
text: `memory-${i}`,
|
||||
})),
|
||||
}),
|
||||
);
|
||||
const embedBatchSpy = jest.spyOn((memory as any).embedder, "embedBatch");
|
||||
|
||||
const result: SearchResult = await memory.add("remember these", {
|
||||
userId: `cap_user_${Date.now()}`,
|
||||
});
|
||||
|
||||
expect(result.results).toHaveLength(20);
|
||||
expect(embedBatchSpy.mock.calls[0][0]).toEqual(
|
||||
Array.from({ length: 20 }, (_, i) => `memory-${i + 5}`),
|
||||
);
|
||||
await memory.reset();
|
||||
});
|
||||
|
||||
test("caps search query before embedding", async () => {
|
||||
const memory = createMemory({
|
||||
vectorStore: {
|
||||
provider: "memory",
|
||||
config: {
|
||||
collectionName: `test-search-cap-${Date.now()}`,
|
||||
dimension: 1536,
|
||||
dbPath: ":memory:",
|
||||
},
|
||||
},
|
||||
});
|
||||
const embedSpy = jest.spyOn((memory as any).embedder, "embed");
|
||||
const longQuery = `old-${"q".repeat(15000)}`;
|
||||
|
||||
await memory.search(longQuery, {
|
||||
filters: { user_id: `cap_user_${Date.now()}` },
|
||||
});
|
||||
|
||||
expect(embedSpy.mock.calls[0][0]).toBe(longQuery.slice(-15000));
|
||||
await memory.reset();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -191,6 +191,21 @@ describe("Memory - update()", () => {
|
||||
const after: MemoryItem | null = await memory.get(id);
|
||||
expect(after!.hash).not.toBe(before!.hash);
|
||||
});
|
||||
|
||||
test("preserves custom metadata fields after update", async () => {
|
||||
const addResult: SearchResult = await memory.add("Original text", {
|
||||
userId,
|
||||
metadata: { category: "hobbies", priority: "high" },
|
||||
infer: false,
|
||||
});
|
||||
const id = addResult.results[0].id;
|
||||
await memory.update(id, "Updated text");
|
||||
const after: MemoryItem | null = await memory.get(id);
|
||||
expect(after!.memory).toBe("Updated text");
|
||||
expect(after!.metadata).toEqual(
|
||||
expect.objectContaining({ category: "hobbies", priority: "high" }),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
// ─── delete() ────────────────────────────────────────────
|
||||
|
||||
+5
-7
@@ -19,13 +19,16 @@ from mem0.client.types import (
|
||||
from mem0.client.utils import api_error_handler
|
||||
|
||||
# Exception classes are referenced in docstrings only
|
||||
from mem0.memory.setup import get_user_id, is_aliased, is_oss_used, mark_aliased, read_anon_ids
|
||||
from mem0.memory.setup import get_user_id, is_aliased, mark_aliased, read_anon_ids, setup_config
|
||||
from mem0.memory.telemetry import capture_client_event, client_telemetry
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
warnings.filterwarnings("default", category=DeprecationWarning)
|
||||
|
||||
# Setup user config
|
||||
setup_config()
|
||||
|
||||
# Entity parameters that must be passed via filters, not top-level
|
||||
ENTITY_PARAMS = frozenset({"user_id", "agent_id", "app_id", "run_id"})
|
||||
|
||||
@@ -42,10 +45,6 @@ def _validate_and_trim_search_query(query: str) -> str:
|
||||
def _maybe_alias_anon_to_email(user_email):
|
||||
"""Fire $identify per prior anon ID so PostHog merges them into email.
|
||||
|
||||
The OSS user_id is only a stitch candidate when telemetry.oss_used_at
|
||||
proves OSS Memory actually ran here; bare user_id values were historically
|
||||
minted at import time by platform-only clients and must not be stitched.
|
||||
The CLI anon id keeps presence-based stitching (only the CLIs write it).
|
||||
Idempotent via telemetry.aliased_pairs: only writes markers when
|
||||
telemetry is actually enabled, so disabling/re-enabling MEM0_TELEMETRY still works.
|
||||
Best-effort: never raises.
|
||||
@@ -56,9 +55,8 @@ def _maybe_alias_anon_to_email(user_email):
|
||||
return
|
||||
try:
|
||||
anon_ids = read_anon_ids()
|
||||
oss_id = anon_ids.get("oss") if is_oss_used() else None
|
||||
seen = set()
|
||||
for anon_id in (oss_id, anon_ids.get("cli")):
|
||||
for anon_id in (anon_ids.get("oss"), anon_ids.get("cli")):
|
||||
if not anon_id or anon_id == user_email or anon_id in seen:
|
||||
continue
|
||||
seen.add(anon_id)
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
import os
|
||||
from typing import Optional
|
||||
|
||||
from mem0.configs.llms.base import BaseLlmConfig
|
||||
|
||||
|
||||
class GeminiConfig(BaseLlmConfig):
|
||||
"""
|
||||
Configuration class for Google Gemini LLM.
|
||||
|
||||
Supports both the Gemini Developer API (via API key) and Vertex AI (via GCP credentials).
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
# Base parameters
|
||||
model: Optional[str] = None,
|
||||
temperature: float = 0.1,
|
||||
api_key: Optional[str] = None,
|
||||
max_tokens: int = 2000,
|
||||
top_p: float = 0.1,
|
||||
top_k: int = 1,
|
||||
enable_vision: bool = False,
|
||||
vision_details: Optional[str] = "auto",
|
||||
http_client_proxies: Optional[dict] = None,
|
||||
# Gemini-specific parameters
|
||||
vertexai: Optional[bool] = None,
|
||||
project: Optional[str] = None,
|
||||
location: Optional[str] = None,
|
||||
):
|
||||
"""
|
||||
Initialize Gemini configuration.
|
||||
|
||||
Args:
|
||||
model: Gemini model to use (e.g., "gemini-2.0-flash"), defaults to None
|
||||
temperature: Controls randomness, defaults to 0.1
|
||||
api_key: Google API key for the Gemini Developer API, defaults to None
|
||||
max_tokens: Maximum tokens to generate, defaults to 2000
|
||||
top_p: Nucleus sampling parameter, defaults to 0.1
|
||||
top_k: Top-k sampling parameter, defaults to 1
|
||||
enable_vision: Enable vision capabilities, defaults to False
|
||||
vision_details: Vision detail level, defaults to "auto"
|
||||
http_client_proxies: HTTP client proxy settings, defaults to None
|
||||
vertexai: Whether to use Vertex AI backend. If None, checks GOOGLE_GENAI_USE_VERTEXAI env var.
|
||||
project: GCP project ID for Vertex AI. If None, checks GOOGLE_CLOUD_PROJECT env var.
|
||||
location: GCP location for Vertex AI. If None, checks GOOGLE_CLOUD_LOCATION env var.
|
||||
"""
|
||||
super().__init__(
|
||||
model=model,
|
||||
temperature=temperature,
|
||||
api_key=api_key,
|
||||
max_tokens=max_tokens,
|
||||
top_p=top_p,
|
||||
top_k=top_k,
|
||||
enable_vision=enable_vision,
|
||||
vision_details=vision_details,
|
||||
http_client_proxies=http_client_proxies,
|
||||
)
|
||||
|
||||
if vertexai is None:
|
||||
vertexai = os.getenv("GOOGLE_GENAI_USE_VERTEXAI", "").lower() in ("true", "1", "yes")
|
||||
self.vertexai = vertexai
|
||||
self.project = project or os.getenv("GOOGLE_CLOUD_PROJECT")
|
||||
self.location = location or os.getenv("GOOGLE_CLOUD_LOCATION", "us-central1")
|
||||
@@ -16,8 +16,8 @@ class HuggingFaceEmbedding(EmbeddingBase):
|
||||
def __init__(self, config: Optional[BaseEmbedderConfig] = None):
|
||||
super().__init__(config)
|
||||
|
||||
if config.huggingface_base_url:
|
||||
self.client = OpenAI(base_url=config.huggingface_base_url)
|
||||
if self.config.huggingface_base_url:
|
||||
self.client = OpenAI(base_url=self.config.huggingface_base_url)
|
||||
self.config.model = self.config.model or "tei"
|
||||
else:
|
||||
self.config.model = self.config.model or "multi-qa-MiniLM-L6-cos-v1"
|
||||
|
||||
+15
-2
@@ -35,7 +35,7 @@ class AnthropicLLM(LLMBase):
|
||||
super().__init__(config)
|
||||
|
||||
if not self.config.model:
|
||||
self.config.model = "claude-3-5-sonnet-20240620"
|
||||
self.config.model = "claude-sonnet-4-6"
|
||||
|
||||
api_key = self.config.api_key or os.getenv("ANTHROPIC_API_KEY")
|
||||
self.client = anthropic.Anthropic(api_key=api_key)
|
||||
@@ -106,7 +106,20 @@ class AnthropicLLM(LLMBase):
|
||||
|
||||
if tools: # TODO: Remove tools if no issues found with new memory addition logic
|
||||
params["tools"] = tools
|
||||
params["tool_choice"] = tool_choice
|
||||
params["tool_choice"] = {"type": tool_choice}
|
||||
|
||||
response = self.client.messages.create(**params)
|
||||
return self._parse_response(response, tools)
|
||||
|
||||
def _parse_response(self, response, tools):
|
||||
if tools:
|
||||
result = {"content": None, "tool_calls": []}
|
||||
for block in response.content:
|
||||
if block.type == "text":
|
||||
result["content"] = block.text
|
||||
elif block.type == "tool_use":
|
||||
result["tool_calls"].append(
|
||||
{"name": block.name, "arguments": block.input}
|
||||
)
|
||||
return result
|
||||
return response.content[0].text
|
||||
|
||||
@@ -409,7 +409,7 @@ class AWSBedrockLLM(LLMBase):
|
||||
elif self.provider == "cohere":
|
||||
return response_json.get("generations", [{"text": ""}])[0].get("text", "")
|
||||
elif self.provider == "ai21":
|
||||
return response_json.get("completions", [{"data", {"text": ""}}])[0].get("data", {}).get("text", "")
|
||||
return response_json.get("completions", [{"data": {"text": ""}}])[0].get("data", {}).get("text", "")
|
||||
else:
|
||||
# Generic parsing - try common response fields
|
||||
for field in ["content", "text", "completion", "generation"]:
|
||||
|
||||
@@ -72,13 +72,26 @@ class AzureOpenAIStructuredLLM(LLMBase):
|
||||
|
||||
messages[-1]["content"] = user_prompt
|
||||
|
||||
is_reasoning = self._is_reasoning_model(self.config.model)
|
||||
params = {
|
||||
"model": self.config.model,
|
||||
"messages": messages,
|
||||
"temperature": self.config.temperature,
|
||||
"max_tokens": self.config.max_tokens,
|
||||
"top_p": self.config.top_p,
|
||||
}
|
||||
# Reasoning models (o1/o3/GPT-5 series) reject temperature/top_p; only
|
||||
# forward the sampling params for non-reasoning models. Mirrors the
|
||||
# reasoning-aware handling of OpenAIStructuredLLM (#5458).
|
||||
if not is_reasoning:
|
||||
params["temperature"] = self.config.temperature
|
||||
params["top_p"] = self.config.top_p
|
||||
# Reasoning models require max_completion_tokens rather than max_tokens.
|
||||
if is_reasoning or self._uses_max_completion_tokens(self.config.model):
|
||||
params["max_completion_tokens"] = self.config.max_tokens
|
||||
else:
|
||||
params["max_tokens"] = self.config.max_tokens
|
||||
if is_reasoning:
|
||||
reasoning_effort = getattr(self.config, "reasoning_effort", None)
|
||||
if reasoning_effort:
|
||||
params["reasoning_effort"] = reasoning_effort
|
||||
if response_format:
|
||||
params["response_format"] = response_format
|
||||
if tools:
|
||||
|
||||
+25
-1
@@ -79,6 +79,25 @@ class LLMBase(ABC):
|
||||
|
||||
return False
|
||||
|
||||
def _uses_max_completion_tokens(self, model: str) -> bool:
|
||||
"""
|
||||
Check if the model expects ``max_completion_tokens`` instead of ``max_tokens``.
|
||||
|
||||
The whole GPT-5 family (gpt-5.4-mini, gpt-5.4-nano, gpt-5.5, ...) rejects the
|
||||
legacy ``max_tokens`` parameter on the Chat Completions API and requires
|
||||
``max_completion_tokens``. Older models (gpt-4.x, gpt-3.5, etc.) still accept
|
||||
``max_tokens``.
|
||||
|
||||
Args:
|
||||
model: The model name to check
|
||||
|
||||
Returns:
|
||||
bool: True if the model requires ``max_completion_tokens``
|
||||
"""
|
||||
# Strip provider prefixes (e.g. "openai/gpt-5.4-mini" -> "gpt-5.4-mini")
|
||||
base_model = (model or "").lower().rsplit("/", 1)[-1]
|
||||
return base_model.startswith("gpt-5")
|
||||
|
||||
def _get_supported_params(self, **kwargs) -> Dict:
|
||||
"""
|
||||
Get parameters that are supported by the current model.
|
||||
@@ -141,10 +160,15 @@ class LLMBase(ABC):
|
||||
"""
|
||||
params = {
|
||||
"temperature": self.config.temperature,
|
||||
"max_tokens": self.config.max_tokens,
|
||||
"top_p": self.config.top_p,
|
||||
}
|
||||
|
||||
model = getattr(self.config, "model", "")
|
||||
if self._uses_max_completion_tokens(model):
|
||||
params["max_completion_tokens"] = self.config.max_tokens
|
||||
else:
|
||||
params["max_tokens"] = self.config.max_tokens
|
||||
|
||||
# Add provider-specific parameters from kwargs
|
||||
params.update(kwargs)
|
||||
|
||||
|
||||
+34
-10
@@ -1,5 +1,5 @@
|
||||
import os
|
||||
from typing import Dict, List, Optional
|
||||
from typing import Dict, List, Optional, Union
|
||||
|
||||
try:
|
||||
from google import genai
|
||||
@@ -8,18 +8,39 @@ except ImportError:
|
||||
raise ImportError("The 'google-genai' library is required. Please install it using 'pip install google-genai'.")
|
||||
|
||||
from mem0.configs.llms.base import BaseLlmConfig
|
||||
from mem0.configs.llms.gemini import GeminiConfig
|
||||
from mem0.llms.base import LLMBase
|
||||
|
||||
|
||||
class GeminiLLM(LLMBase):
|
||||
def __init__(self, config: Optional[BaseLlmConfig] = None):
|
||||
def __init__(self, config: Optional[Union[BaseLlmConfig, GeminiConfig, Dict]] = None):
|
||||
# Convert to GeminiConfig if needed
|
||||
if config is None:
|
||||
config = GeminiConfig()
|
||||
elif isinstance(config, dict):
|
||||
config = GeminiConfig(**config)
|
||||
elif isinstance(config, BaseLlmConfig) and not isinstance(config, GeminiConfig):
|
||||
config = GeminiConfig(
|
||||
model=config.model,
|
||||
temperature=config.temperature,
|
||||
api_key=config.api_key,
|
||||
max_tokens=config.max_tokens,
|
||||
top_p=config.top_p,
|
||||
top_k=config.top_k,
|
||||
enable_vision=config.enable_vision,
|
||||
vision_details=config.vision_details,
|
||||
)
|
||||
|
||||
super().__init__(config)
|
||||
|
||||
if not self.config.model:
|
||||
self.config.model = "gemini-2.0-flash"
|
||||
|
||||
api_key = self.config.api_key or os.getenv("GOOGLE_API_KEY")
|
||||
self.client = genai.Client(api_key=api_key)
|
||||
if self.config.vertexai:
|
||||
self.client = genai.Client(vertexai=True, project=self.config.project, location=self.config.location)
|
||||
else:
|
||||
api_key = self.config.api_key or os.getenv("GOOGLE_API_KEY")
|
||||
self.client = genai.Client(api_key=api_key)
|
||||
|
||||
def _parse_response(self, response, tools):
|
||||
"""
|
||||
@@ -157,12 +178,15 @@ class GeminiLLM(LLMBase):
|
||||
# Extract system instruction and reformat messages
|
||||
system_instruction, contents = self._reformat_messages(messages)
|
||||
|
||||
# Prepare generation config
|
||||
config_params = {
|
||||
"temperature": self.config.temperature,
|
||||
"max_output_tokens": self.config.max_tokens,
|
||||
"top_p": self.config.top_p,
|
||||
}
|
||||
# Prepare generation config — only include non-None values so the
|
||||
# Gemini SDK uses its own defaults instead of rejecting None.
|
||||
config_params = {}
|
||||
if self.config.temperature is not None:
|
||||
config_params["temperature"] = self.config.temperature
|
||||
if self.config.max_tokens is not None:
|
||||
config_params["max_output_tokens"] = self.config.max_tokens
|
||||
if self.config.top_p is not None:
|
||||
config_params["top_p"] = self.config.top_p
|
||||
|
||||
# Add system instruction to config if present
|
||||
if system_instruction:
|
||||
|
||||
@@ -57,6 +57,7 @@ class LangchainLLM(LLMBase):
|
||||
response_format=None,
|
||||
tools: Optional[List[Dict]] = None,
|
||||
tool_choice: str = "auto",
|
||||
**kwargs,
|
||||
):
|
||||
"""
|
||||
Generate a response based on the given messages using langchain_community.
|
||||
@@ -66,6 +67,8 @@ class LangchainLLM(LLMBase):
|
||||
response_format (str or object, optional): Format of the response. Not used in Langchain.
|
||||
tools (list, optional): List of tools that the model can call.
|
||||
tool_choice (str, optional): Tool choice method.
|
||||
**kwargs: Additional model parameters forwarded to the underlying LangChain
|
||||
model's ``invoke`` (matches the ``LLMBase.generate_response`` contract).
|
||||
|
||||
Returns:
|
||||
str: The generated response.
|
||||
@@ -90,5 +93,5 @@ class LangchainLLM(LLMBase):
|
||||
if tools:
|
||||
langchain_model = langchain_model.bind_tools(tools=tools, tool_choice=tool_choice)
|
||||
|
||||
response: AIMessage = langchain_model.invoke(langchain_messages)
|
||||
response: AIMessage = langchain_model.invoke(langchain_messages, **kwargs)
|
||||
return self._parse_response(response, tools)
|
||||
|
||||
@@ -67,16 +67,19 @@ class LiteLLM(LLMBase):
|
||||
Returns:
|
||||
str: The generated response.
|
||||
"""
|
||||
if not litellm.supports_function_calling(self.config.model):
|
||||
if tools and not litellm.supports_function_calling(self.config.model):
|
||||
raise ValueError(f"Model '{self.config.model}' in litellm does not support function calling.")
|
||||
|
||||
params = {
|
||||
"model": self.config.model,
|
||||
"messages": messages,
|
||||
"temperature": self.config.temperature,
|
||||
"max_tokens": self.config.max_tokens,
|
||||
"top_p": self.config.top_p,
|
||||
}
|
||||
if self._uses_max_completion_tokens(self.config.model):
|
||||
params["max_completion_tokens"] = self.config.max_tokens
|
||||
else:
|
||||
params["max_tokens"] = self.config.max_tokens
|
||||
if response_format:
|
||||
params["response_format"] = response_format
|
||||
if tools: # TODO: Remove tools if no issues found with new memory addition logic
|
||||
|
||||
+2
-1
@@ -119,11 +119,12 @@ class OllamaLLM(LLMBase):
|
||||
# Handle JSON response format by using Ollama's native format parameter
|
||||
if response_format and response_format.get("type") == "json_object":
|
||||
params["format"] = "json"
|
||||
# Also add JSON format instruction to the last message as a fallback
|
||||
messages = [dict(m) for m in messages]
|
||||
if messages and messages[-1]["role"] == "user":
|
||||
messages[-1]["content"] += "\n\nPlease respond with valid JSON only."
|
||||
else:
|
||||
messages.append({"role": "user", "content": "Please respond with valid JSON only."})
|
||||
params["messages"] = messages
|
||||
|
||||
# Add options for Ollama (temperature, num_predict, top_p)
|
||||
options = {
|
||||
|
||||
@@ -36,11 +36,8 @@ class OpenAIStructuredLLM(LLMBase):
|
||||
Returns:
|
||||
str: The generated response.
|
||||
"""
|
||||
params = {
|
||||
"model": self.config.model,
|
||||
"messages": messages,
|
||||
"temperature": self.config.temperature,
|
||||
}
|
||||
params = self._get_supported_params(messages=messages)
|
||||
params["model"] = self.config.model
|
||||
|
||||
if response_format:
|
||||
params["response_format"] = response_format
|
||||
|
||||
+6
-1
@@ -28,7 +28,7 @@ class SarvamLLM(LLMBase):
|
||||
getattr(self.config, "sarvam_base_url", None) or os.getenv("SARVAM_API_BASE") or "https://api.sarvam.ai/v1"
|
||||
)
|
||||
|
||||
def generate_response(self, messages: List[Dict[str, str]], response_format=None) -> str:
|
||||
def generate_response(self, messages: List[Dict[str, str]], response_format=None, **kwargs) -> str:
|
||||
"""
|
||||
Generate a response based on the given messages using Sarvam-M.
|
||||
|
||||
@@ -36,6 +36,8 @@ class SarvamLLM(LLMBase):
|
||||
messages (list): List of message dicts containing 'role' and 'content'.
|
||||
response_format (str or object, optional): Format of the response.
|
||||
Currently not used by Sarvam API.
|
||||
**kwargs: Additional provider-specific parameters forwarded to the Sarvam
|
||||
request payload (matches the ``LLMBase.generate_response`` contract).
|
||||
|
||||
Returns:
|
||||
str: The generated response.
|
||||
@@ -72,6 +74,9 @@ class SarvamLLM(LLMBase):
|
||||
if param in self.config.model:
|
||||
params[param] = self.config.model[param]
|
||||
|
||||
# Forward any per-call provider-specific parameters (LLMBase contract).
|
||||
params.update(kwargs)
|
||||
|
||||
try:
|
||||
response = requests.post(url, headers=headers, json=params, timeout=30)
|
||||
response.raise_for_status()
|
||||
|
||||
@@ -58,6 +58,7 @@ class TogetherLLM(LLMBase):
|
||||
response_format=None,
|
||||
tools: Optional[List[Dict]] = None,
|
||||
tool_choice: str = "auto",
|
||||
**kwargs,
|
||||
):
|
||||
"""
|
||||
Generate a response based on the given messages using TogetherAI.
|
||||
@@ -67,6 +68,8 @@ class TogetherLLM(LLMBase):
|
||||
response_format (str or object, optional): Format of the response. Defaults to "text".
|
||||
tools (list, optional): List of tools that the model can call. Defaults to None.
|
||||
tool_choice (str, optional): Tool choice method. Defaults to "auto".
|
||||
**kwargs: Additional provider-specific parameters forwarded to the Together
|
||||
client (matches the ``LLMBase.generate_response`` contract).
|
||||
|
||||
Returns:
|
||||
str: The generated response.
|
||||
@@ -78,6 +81,7 @@ class TogetherLLM(LLMBase):
|
||||
"max_tokens": self.config.max_tokens,
|
||||
"top_p": self.config.top_p,
|
||||
}
|
||||
params.update(kwargs)
|
||||
if response_format:
|
||||
params["response_format"] = response_format
|
||||
if tools: # TODO: Remove tools if no issues found with new memory addition logic
|
||||
|
||||
+114
-46
@@ -24,7 +24,7 @@ from mem0.configs.prompts import (
|
||||
)
|
||||
from mem0.exceptions import ValidationError as Mem0ValidationError
|
||||
from mem0.memory.base import MemoryBase
|
||||
from mem0.memory.setup import mark_oss_used, mem0_dir, setup_config
|
||||
from mem0.memory.setup import mem0_dir, setup_config
|
||||
from mem0.memory.storage import SQLiteManager
|
||||
from mem0.memory.telemetry import MEM0_TELEMETRY, capture_event
|
||||
from mem0.memory.notices import (
|
||||
@@ -80,6 +80,63 @@ warnings.filterwarnings("ignore", category=DeprecationWarning, message=".*swigva
|
||||
# Initialize logger early for util functions
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
ADD_CONTEXT_SEARCH_MAX_CHARS = 15000
|
||||
ADD_MAX_EXTRACTED_MEMORIES = 20
|
||||
ADD_MEMORY_EMBEDDING_MAX_CHARS = 15000
|
||||
ADD_MAX_ENTITY_LINKS_PER_EVENT = 100
|
||||
SEARCH_QUERY_MAX_CHARS = 15000
|
||||
|
||||
|
||||
def _tail_cap_text(text: str, max_chars: int) -> str:
|
||||
if len(text) <= max_chars:
|
||||
return text
|
||||
return text[-max_chars:]
|
||||
|
||||
|
||||
def _cap_extracted_memories(extracted_memories: list) -> list:
|
||||
if len(extracted_memories) <= ADD_MAX_EXTRACTED_MEMORIES:
|
||||
return extracted_memories
|
||||
logger.warning(
|
||||
"Extracted memory cap applied: extracted=%d processing=%d",
|
||||
len(extracted_memories),
|
||||
ADD_MAX_EXTRACTED_MEMORIES,
|
||||
)
|
||||
return extracted_memories[-ADD_MAX_EXTRACTED_MEMORIES:]
|
||||
|
||||
|
||||
def _cap_memory_embedding_texts(mem_texts: list[str]) -> list[str]:
|
||||
capped = [_tail_cap_text(t, ADD_MEMORY_EMBEDDING_MAX_CHARS) for t in mem_texts]
|
||||
capped_count = sum(1 for original, capped_text in zip(mem_texts, capped) if len(original) != len(capped_text))
|
||||
if capped_count:
|
||||
logger.warning(
|
||||
"Memory embedding input cap applied: capped_count=%d max_chars=%d",
|
||||
capped_count,
|
||||
ADD_MEMORY_EMBEDDING_MAX_CHARS,
|
||||
)
|
||||
return capped
|
||||
|
||||
|
||||
def _cap_search_query(query: str) -> str:
|
||||
capped = _tail_cap_text(query, SEARCH_QUERY_MAX_CHARS)
|
||||
if len(capped) != len(query):
|
||||
logger.warning(
|
||||
"Search query cap applied: original_chars=%d searched_chars=%d",
|
||||
len(query),
|
||||
len(capped),
|
||||
)
|
||||
return capped
|
||||
|
||||
|
||||
def _cap_entity_keys(entity_keys: list[str]) -> list[str]:
|
||||
if len(entity_keys) <= ADD_MAX_ENTITY_LINKS_PER_EVENT:
|
||||
return entity_keys
|
||||
logger.warning(
|
||||
"ADD entity-linking cap applied: extracted=%d processing=%d",
|
||||
len(entity_keys),
|
||||
ADD_MAX_ENTITY_LINKS_PER_EVENT,
|
||||
)
|
||||
return entity_keys[:ADD_MAX_ENTITY_LINKS_PER_EVENT]
|
||||
|
||||
|
||||
# Fields that hold runtime auth/connection objects and must be preserved.
|
||||
# These are non-serializable objects (e.g. AWSV4SignerAuth, RequestsHttpConnection)
|
||||
@@ -370,6 +427,7 @@ def _entity_collection_name(provider: str, collection_name: str) -> str:
|
||||
return f"{collection_name}{separator}entities"
|
||||
|
||||
|
||||
setup_config()
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
_PROJECT_UPDATE_UNSUPPORTED_ERROR = "Project updates are not supported by the OSS Memory SDK."
|
||||
@@ -468,13 +526,6 @@ class Memory(MemoryBase):
|
||||
self.config.vector_store.provider,
|
||||
)
|
||||
|
||||
# Mint the OSS anon id (and record genuine OSS usage) only on real OSS
|
||||
# init, never at import time: platform-only clients must not create
|
||||
# stitch candidates. Must run before the first capture_event so the
|
||||
# telemetry singleton picks up the minted user_id.
|
||||
if MEM0_TELEMETRY:
|
||||
setup_config()
|
||||
mark_oss_used()
|
||||
capture_event("mem0.init", self, {"sync_type": "sync"})
|
||||
|
||||
@property
|
||||
@@ -810,9 +861,16 @@ class Memory(MemoryBase):
|
||||
|
||||
# Phase 1: Existing memory retrieval
|
||||
search_filters = {k: v for k, v in filters.items() if k in ("user_id", "agent_id", "run_id") and v}
|
||||
query_embedding = self.embedding_model.embed(parsed_messages, "search")
|
||||
search_messages = _tail_cap_text(parsed_messages, ADD_CONTEXT_SEARCH_MAX_CHARS)
|
||||
if len(search_messages) != len(parsed_messages):
|
||||
logger.warning(
|
||||
"ADD context-search embedding capped: original_chars=%d embedded_chars=%d",
|
||||
len(parsed_messages),
|
||||
len(search_messages),
|
||||
)
|
||||
query_embedding = self.embedding_model.embed(search_messages, "search")
|
||||
existing_results = self.vector_store.search(
|
||||
query=parsed_messages,
|
||||
query=search_messages,
|
||||
vectors=query_embedding,
|
||||
top_k=10,
|
||||
filters=search_filters,
|
||||
@@ -866,6 +924,7 @@ class Memory(MemoryBase):
|
||||
except Exception as e:
|
||||
logger.error(f"Error parsing extraction response: {e}")
|
||||
extracted_memories = []
|
||||
extracted_memories = _cap_extracted_memories(extracted_memories)
|
||||
|
||||
if not extracted_memories:
|
||||
# Save messages even if nothing extracted
|
||||
@@ -874,15 +933,16 @@ class Memory(MemoryBase):
|
||||
|
||||
# Phase 3: Batch embed all extracted memory texts
|
||||
mem_texts = [m.get("text", "") for m in extracted_memories if m.get("text")]
|
||||
mem_embedding_texts = _cap_memory_embedding_texts(mem_texts)
|
||||
try:
|
||||
mem_embeddings_list = self.embedding_model.embed_batch(mem_texts, "add")
|
||||
mem_embeddings_list = self.embedding_model.embed_batch(mem_embedding_texts, "add")
|
||||
embed_map = dict(zip(mem_texts, mem_embeddings_list))
|
||||
except Exception:
|
||||
# Fallback: embed individually
|
||||
embed_map = {}
|
||||
for text in mem_texts:
|
||||
for text, embedding_text in zip(mem_texts, mem_embedding_texts):
|
||||
try:
|
||||
embed_map[text] = self.embedding_model.embed(text, "add")
|
||||
embed_map[text] = self.embedding_model.embed(embedding_text, "add")
|
||||
except Exception as e:
|
||||
logger.warning(f"Failed to embed memory text: {e}")
|
||||
|
||||
@@ -984,7 +1044,7 @@ class Memory(MemoryBase):
|
||||
global_entities[key] = [entity_type, entity_text, {memory_id}]
|
||||
|
||||
if global_entities:
|
||||
ordered_keys = list(global_entities.keys())
|
||||
ordered_keys = _cap_entity_keys(list(global_entities.keys()))
|
||||
entity_texts = [global_entities[k][1] for k in ordered_keys]
|
||||
|
||||
# 7b: Single batch embed for all unique entities
|
||||
@@ -1484,6 +1544,7 @@ class Memory(MemoryBase):
|
||||
# Guard against None threshold (backward compat)
|
||||
if threshold is None:
|
||||
threshold = 0.1
|
||||
query = _cap_search_query(query)
|
||||
|
||||
# Step 1: Preprocess query
|
||||
query_lemmatized = lemmatize_for_bm25(query)
|
||||
@@ -1845,7 +1906,9 @@ class Memory(MemoryBase):
|
||||
|
||||
prev_value = existing_memory.payload.get("data")
|
||||
|
||||
new_metadata = deepcopy(metadata) if metadata is not None else {}
|
||||
new_metadata = deepcopy(existing_memory.payload)
|
||||
if metadata is not None:
|
||||
new_metadata.update(metadata)
|
||||
|
||||
new_metadata["data"] = data
|
||||
new_metadata["hash"] = hashlib.md5(data.encode()).hexdigest()
|
||||
@@ -1853,17 +1916,9 @@ class Memory(MemoryBase):
|
||||
new_metadata["created_at"] = existing_memory.payload.get("created_at")
|
||||
new_metadata["updated_at"] = datetime.now(timezone.utc).isoformat()
|
||||
|
||||
# Preserve session identifiers from existing memory only if not provided in new metadata
|
||||
if "user_id" not in new_metadata and "user_id" in existing_memory.payload:
|
||||
new_metadata["user_id"] = existing_memory.payload["user_id"]
|
||||
if "agent_id" not in new_metadata and "agent_id" in existing_memory.payload:
|
||||
new_metadata["agent_id"] = existing_memory.payload["agent_id"]
|
||||
if "run_id" not in new_metadata and "run_id" in existing_memory.payload:
|
||||
new_metadata["run_id"] = existing_memory.payload["run_id"]
|
||||
# actor_id is immutable after creation (issue #4490)
|
||||
if "actor_id" in existing_memory.payload:
|
||||
new_metadata["actor_id"] = existing_memory.payload["actor_id"]
|
||||
if "role" not in new_metadata and "role" in existing_memory.payload:
|
||||
new_metadata["role"] = existing_memory.payload["role"]
|
||||
|
||||
if data in existing_embeddings:
|
||||
embeddings = existing_embeddings[data]
|
||||
@@ -2015,9 +2070,6 @@ class AsyncMemory(MemoryBase):
|
||||
self.config.vector_store.provider,
|
||||
)
|
||||
|
||||
if MEM0_TELEMETRY:
|
||||
setup_config()
|
||||
mark_oss_used()
|
||||
capture_event("mem0.init", self, {"sync_type": "async"})
|
||||
|
||||
@property
|
||||
@@ -2325,10 +2377,17 @@ class AsyncMemory(MemoryBase):
|
||||
|
||||
# Phase 1: Existing memory retrieval
|
||||
search_filters = {k: v for k, v in effective_filters.items() if k in ("user_id", "agent_id", "run_id") and v}
|
||||
query_embedding = await asyncio.to_thread(self.embedding_model.embed, parsed_messages, "search")
|
||||
search_messages = _tail_cap_text(parsed_messages, ADD_CONTEXT_SEARCH_MAX_CHARS)
|
||||
if len(search_messages) != len(parsed_messages):
|
||||
logger.warning(
|
||||
"ADD context-search embedding capped: original_chars=%d embedded_chars=%d",
|
||||
len(parsed_messages),
|
||||
len(search_messages),
|
||||
)
|
||||
query_embedding = await asyncio.to_thread(self.embedding_model.embed, search_messages, "search")
|
||||
existing_results = await asyncio.to_thread(
|
||||
self.vector_store.search,
|
||||
query=parsed_messages,
|
||||
query=search_messages,
|
||||
vectors=query_embedding,
|
||||
top_k=10,
|
||||
filters=search_filters,
|
||||
@@ -2383,6 +2442,7 @@ class AsyncMemory(MemoryBase):
|
||||
except Exception as e:
|
||||
logger.error(f"Error parsing extraction response (async): {e}")
|
||||
extracted_memories = []
|
||||
extracted_memories = _cap_extracted_memories(extracted_memories)
|
||||
|
||||
if not extracted_memories:
|
||||
await asyncio.to_thread(self.db.save_messages, messages, session_scope)
|
||||
@@ -2390,14 +2450,15 @@ class AsyncMemory(MemoryBase):
|
||||
|
||||
# Phase 3: Batch embed all extracted memory texts
|
||||
mem_texts = [m.get("text", "") for m in extracted_memories if m.get("text")]
|
||||
mem_embedding_texts = _cap_memory_embedding_texts(mem_texts)
|
||||
try:
|
||||
mem_embeddings_list = await asyncio.to_thread(self.embedding_model.embed_batch, mem_texts, "add")
|
||||
mem_embeddings_list = await asyncio.to_thread(self.embedding_model.embed_batch, mem_embedding_texts, "add")
|
||||
embed_map = dict(zip(mem_texts, mem_embeddings_list))
|
||||
except Exception:
|
||||
embed_map = {}
|
||||
for text in mem_texts:
|
||||
for text, embedding_text in zip(mem_texts, mem_embedding_texts):
|
||||
try:
|
||||
embed_map[text] = await asyncio.to_thread(self.embedding_model.embed, text, "add")
|
||||
embed_map[text] = await asyncio.to_thread(self.embedding_model.embed, embedding_text, "add")
|
||||
except Exception as e:
|
||||
logger.warning(f"Failed to embed memory text (async): {e}")
|
||||
|
||||
@@ -2500,7 +2561,7 @@ class AsyncMemory(MemoryBase):
|
||||
global_entities[key] = [entity_type, entity_text, {memory_id}]
|
||||
|
||||
if global_entities:
|
||||
ordered_keys = list(global_entities.keys())
|
||||
ordered_keys = _cap_entity_keys(list(global_entities.keys()))
|
||||
entity_texts = [global_entities[k][1] for k in ordered_keys]
|
||||
|
||||
# 7b: Batch embed entities
|
||||
@@ -3005,6 +3066,7 @@ class AsyncMemory(MemoryBase):
|
||||
async def _search_vector_store(self, query, filters, limit, threshold=0.1, explain=False):
|
||||
if threshold is None:
|
||||
threshold = 0.1
|
||||
query = _cap_search_query(query)
|
||||
|
||||
# Step 1: Preprocess query (CPU-bound)
|
||||
query_lemmatized = await asyncio.to_thread(lemmatize_for_bm25, query)
|
||||
@@ -3250,9 +3312,15 @@ class AsyncMemory(MemoryBase):
|
||||
for memory in memories[0]:
|
||||
delete_tasks.append(self._delete_memory(memory.id))
|
||||
|
||||
await asyncio.gather(*delete_tasks)
|
||||
results = await asyncio.gather(*delete_tasks, return_exceptions=True)
|
||||
|
||||
logger.info(f"Deleted {len(memories[0])} memories")
|
||||
errors = [r for r in results if isinstance(r, BaseException)]
|
||||
if errors:
|
||||
logger.warning("Failed to delete %d out of %d memories", len(errors), len(results))
|
||||
for err in errors:
|
||||
logger.warning("Delete error: %s", err)
|
||||
|
||||
logger.info(f"Deleted {len(results) - len(errors)} memories")
|
||||
|
||||
decay_usage_notice = detect_decay_usage_from_delete_all(len(memories[0]))
|
||||
if decay_usage_notice:
|
||||
@@ -3380,7 +3448,9 @@ class AsyncMemory(MemoryBase):
|
||||
|
||||
prev_value = existing_memory.payload.get("data")
|
||||
|
||||
new_metadata = deepcopy(metadata) if metadata is not None else {}
|
||||
new_metadata = deepcopy(existing_memory.payload)
|
||||
if metadata is not None:
|
||||
new_metadata.update(metadata)
|
||||
|
||||
new_metadata["data"] = data
|
||||
new_metadata["hash"] = hashlib.md5(data.encode()).hexdigest()
|
||||
@@ -3388,18 +3458,9 @@ class AsyncMemory(MemoryBase):
|
||||
new_metadata["created_at"] = existing_memory.payload.get("created_at")
|
||||
new_metadata["updated_at"] = datetime.now(timezone.utc).isoformat()
|
||||
|
||||
# Preserve session identifiers from existing memory only if not provided in new metadata
|
||||
if "user_id" not in new_metadata and "user_id" in existing_memory.payload:
|
||||
new_metadata["user_id"] = existing_memory.payload["user_id"]
|
||||
if "agent_id" not in new_metadata and "agent_id" in existing_memory.payload:
|
||||
new_metadata["agent_id"] = existing_memory.payload["agent_id"]
|
||||
if "run_id" not in new_metadata and "run_id" in existing_memory.payload:
|
||||
new_metadata["run_id"] = existing_memory.payload["run_id"]
|
||||
|
||||
# actor_id is immutable after creation (issue #4490)
|
||||
if "actor_id" in existing_memory.payload:
|
||||
new_metadata["actor_id"] = existing_memory.payload["actor_id"]
|
||||
if "role" not in new_metadata and "role" in existing_memory.payload:
|
||||
new_metadata["role"] = existing_memory.payload["role"]
|
||||
|
||||
if data in existing_embeddings:
|
||||
embeddings = existing_embeddings[data]
|
||||
@@ -3491,6 +3552,13 @@ class AsyncMemory(MemoryBase):
|
||||
self.config.vector_store.provider, self.config.vector_store.config
|
||||
)
|
||||
|
||||
if self._entity_store is not None:
|
||||
try:
|
||||
await asyncio.to_thread(self._entity_store.reset)
|
||||
except Exception as e:
|
||||
logger.warning(f"Failed to reset entity store: {e}")
|
||||
self._entity_store = None
|
||||
|
||||
capture_event("mem0.reset", self, {"sync_type": "async"})
|
||||
await display_first_run_notice_async(self, "async", "reset")
|
||||
|
||||
|
||||
+4
-32
@@ -3,7 +3,6 @@ import logging
|
||||
import os
|
||||
import tempfile
|
||||
import uuid
|
||||
from datetime import datetime, timezone
|
||||
from hashlib import sha256
|
||||
|
||||
# Set up the directory path
|
||||
@@ -57,12 +56,10 @@ def _write_config(config):
|
||||
def setup_config():
|
||||
"""Ensure ~/.mem0/config.json exists with a top-level user_id.
|
||||
|
||||
Called lazily from OSS Memory/AsyncMemory init (never at import time, so
|
||||
platform-only MemoryClient usage mints no anon id). Idempotent: backfills
|
||||
user_id for users whose config was written by the CLI (which writes
|
||||
telemetry.anonymous_id but no top-level user_id). Without this, OSS Python
|
||||
telemetry is silently dropped because get_user_id() returns None when
|
||||
user_id is missing.
|
||||
Idempotent: backfills user_id for users whose config was written by the
|
||||
CLI (which writes telemetry.anonymous_id but no top-level user_id).
|
||||
Without this, OSS Python telemetry is silently dropped because
|
||||
get_user_id() returns None when user_id is missing.
|
||||
"""
|
||||
config = _load_config()
|
||||
if config.get("user_id"):
|
||||
@@ -134,31 +131,6 @@ def mark_aliased(anon_id, email):
|
||||
_write_config(config)
|
||||
|
||||
|
||||
def is_oss_used():
|
||||
"""Return whether OSS Memory has genuinely initialized on this machine.
|
||||
|
||||
Gates identity stitching: the top-level user_id is only a stitch candidate
|
||||
when telemetry.oss_used_at is present, because bare user_id values were
|
||||
historically minted at import time by platform-only clients.
|
||||
"""
|
||||
config = _load_config()
|
||||
telemetry = config.get("telemetry") if isinstance(config.get("telemetry"), dict) else {}
|
||||
return bool(telemetry.get("oss_used_at"))
|
||||
|
||||
|
||||
def mark_oss_used():
|
||||
"""Persist telemetry.oss_used_at on first genuine OSS Memory init. Never raises."""
|
||||
config = _load_config()
|
||||
telemetry = config.get("telemetry")
|
||||
if not isinstance(telemetry, dict):
|
||||
telemetry = {}
|
||||
if telemetry.get("oss_used_at"):
|
||||
return
|
||||
telemetry["oss_used_at"] = datetime.now(timezone.utc).isoformat()
|
||||
config["telemetry"] = telemetry
|
||||
_write_config(config)
|
||||
|
||||
|
||||
def get_or_create_user_id(vector_store=None):
|
||||
"""Store user_id in vector store and return it.
|
||||
|
||||
|
||||
@@ -129,11 +129,7 @@ class AnonymousTelemetry:
|
||||
self.posthog.capture(
|
||||
distinct_id=email,
|
||||
event="$identify",
|
||||
properties={
|
||||
"$anon_distinct_id": anon_id,
|
||||
"client_source": "python",
|
||||
"client_version": mem0.__version__,
|
||||
},
|
||||
properties={"$anon_distinct_id": anon_id, "client_source": "python"},
|
||||
)
|
||||
return True
|
||||
except Exception as e:
|
||||
|
||||
+26
-13
@@ -61,12 +61,18 @@ def ensure_json_instruction(system_prompt, user_prompt):
|
||||
def parse_messages(messages):
|
||||
response = ""
|
||||
for msg in messages:
|
||||
if msg["role"] == "system":
|
||||
response += f"system: {msg['content']}\n"
|
||||
if msg["role"] == "user":
|
||||
response += f"user: {msg['content']}\n"
|
||||
if msg["role"] == "assistant":
|
||||
response += f"assistant: {msg['content']}\n"
|
||||
role = msg.get("role")
|
||||
content = msg.get("content")
|
||||
# Skip messages without textual content (e.g. assistant tool-call
|
||||
# messages that carry `tool_calls` but no `content` key).
|
||||
if content is None:
|
||||
continue
|
||||
if role == "system":
|
||||
response += f"system: {content}\n"
|
||||
elif role == "user":
|
||||
response += f"user: {content}\n"
|
||||
elif role == "assistant":
|
||||
response += f"assistant: {content}\n"
|
||||
return response
|
||||
|
||||
|
||||
@@ -173,12 +179,19 @@ def parse_vision_messages(messages, llm=None, vision_details="auto"):
|
||||
"""
|
||||
returned_messages = []
|
||||
for msg in messages:
|
||||
if msg["role"] == "system":
|
||||
role = msg.get("role")
|
||||
content = msg.get("content")
|
||||
if role == "system":
|
||||
returned_messages.append(msg)
|
||||
continue
|
||||
|
||||
# Skip messages without content (e.g. assistant tool-call messages
|
||||
# that carry `tool_calls` but no `content` key).
|
||||
if content is None:
|
||||
continue
|
||||
|
||||
# Handle message content
|
||||
if isinstance(msg["content"], list):
|
||||
if isinstance(content, list):
|
||||
if llm is None:
|
||||
text_parts = [
|
||||
part["text"] for part in msg["content"]
|
||||
@@ -186,17 +199,17 @@ def parse_vision_messages(messages, llm=None, vision_details="auto"):
|
||||
]
|
||||
if not text_parts:
|
||||
continue
|
||||
returned_messages.append({"role": msg["role"], "content": " ".join(text_parts)})
|
||||
returned_messages.append({"role": role, "content": " ".join(text_parts)})
|
||||
else:
|
||||
description = get_image_description(msg, llm, vision_details)
|
||||
returned_messages.append({"role": msg["role"], "content": description})
|
||||
elif isinstance(msg["content"], dict) and msg["content"].get("type") == "image_url":
|
||||
returned_messages.append({"role": role, "content": description})
|
||||
elif isinstance(content, dict) and content.get("type") == "image_url":
|
||||
if llm is None:
|
||||
continue
|
||||
image_url = msg["content"]["image_url"]["url"]
|
||||
image_url = content["image_url"]["url"]
|
||||
try:
|
||||
description = get_image_description(image_url, llm, vision_details)
|
||||
returned_messages.append({"role": msg["role"], "content": description})
|
||||
returned_messages.append({"role": role, "content": description})
|
||||
except Exception:
|
||||
raise Exception(f"Error while downloading {image_url}.")
|
||||
else:
|
||||
|
||||
@@ -82,4 +82,5 @@ class CohereReranker(BaseReranker):
|
||||
# Fallback to original order if reranking fails
|
||||
for doc in documents:
|
||||
doc['rerank_score'] = 0.0
|
||||
return documents[:top_k] if top_k else documents
|
||||
final_top_k = top_k or self.config.top_k
|
||||
return documents[:final_top_k] if final_top_k else documents
|
||||
@@ -93,4 +93,5 @@ class ZeroEntropyReranker(BaseReranker):
|
||||
# Fallback to original order if reranking fails
|
||||
for doc in documents:
|
||||
doc['rerank_score'] = 0.0
|
||||
return documents[:top_k] if top_k else documents
|
||||
final_top_k = top_k or self.config.top_k
|
||||
return documents[:final_top_k] if final_top_k else documents
|
||||
@@ -7,6 +7,7 @@ from mem0.configs.llms.aws_bedrock import AWSBedrockConfig
|
||||
from mem0.configs.llms.azure import AzureOpenAIConfig
|
||||
from mem0.configs.llms.base import BaseLlmConfig
|
||||
from mem0.configs.llms.deepseek import DeepSeekConfig
|
||||
from mem0.configs.llms.gemini import GeminiConfig
|
||||
from mem0.configs.llms.lmstudio import LMStudioConfig
|
||||
from mem0.configs.llms.minimax import MinimaxConfig
|
||||
from mem0.configs.llms.ollama import OllamaConfig
|
||||
@@ -46,7 +47,7 @@ class LlmFactory:
|
||||
"openai_structured": ("mem0.llms.openai_structured.OpenAIStructuredLLM", OpenAIConfig),
|
||||
"anthropic": ("mem0.llms.anthropic.AnthropicLLM", AnthropicConfig),
|
||||
"azure_openai_structured": ("mem0.llms.azure_openai_structured.AzureOpenAIStructuredLLM", AzureOpenAIConfig),
|
||||
"gemini": ("mem0.llms.gemini.GeminiLLM", BaseLlmConfig),
|
||||
"gemini": ("mem0.llms.gemini.GeminiLLM", GeminiConfig),
|
||||
"deepseek": ("mem0.llms.deepseek.DeepSeekLLM", DeepSeekConfig),
|
||||
"minimax": ("mem0.llms.minimax.MiniMaxLLM", MinimaxConfig),
|
||||
"xai": ("mem0.llms.xai.XAILLM", XAIConfig),
|
||||
|
||||
@@ -187,7 +187,7 @@ class ChromaDB(VectorStoreBase):
|
||||
"""
|
||||
self.collection.update(ids=vector_id, embeddings=vector, metadatas=payload)
|
||||
|
||||
def get(self, vector_id: str) -> OutputData:
|
||||
def get(self, vector_id: str) -> Optional[OutputData]:
|
||||
"""
|
||||
Retrieve a vector by ID.
|
||||
|
||||
@@ -195,10 +195,11 @@ class ChromaDB(VectorStoreBase):
|
||||
vector_id (str): ID of the vector to retrieve.
|
||||
|
||||
Returns:
|
||||
OutputData: Retrieved vector.
|
||||
Optional[OutputData]: Retrieved vector, or None if the ID is not found.
|
||||
"""
|
||||
result = self.collection.get(ids=[vector_id])
|
||||
return self._parse_output(result)[0]
|
||||
parsed = self._parse_output(result)
|
||||
return parsed[0] if parsed else None
|
||||
|
||||
def list_cols(self) -> List[chromadb.Collection]:
|
||||
"""
|
||||
|
||||
@@ -290,7 +290,7 @@ class MilvusDB(VectorStoreBase):
|
||||
schema = {"id": vector_id, "vectors": vector, "metadata": payload, "text": text}
|
||||
self.client.upsert(collection_name=self.collection_name, data=schema)
|
||||
|
||||
def get(self, vector_id):
|
||||
def get(self, vector_id) -> Optional[OutputData]:
|
||||
"""
|
||||
Retrieve a vector by ID.
|
||||
|
||||
@@ -298,9 +298,11 @@ class MilvusDB(VectorStoreBase):
|
||||
vector_id (str): ID of the vector to retrieve.
|
||||
|
||||
Returns:
|
||||
OutputData: Retrieved vector.
|
||||
Optional[OutputData]: Retrieved vector, or None if the ID is not found.
|
||||
"""
|
||||
result = self.client.get(collection_name=self.collection_name, ids=vector_id)
|
||||
if not result:
|
||||
return None
|
||||
output = OutputData(
|
||||
id=result[0].get("id", None),
|
||||
score=None,
|
||||
|
||||
@@ -391,7 +391,7 @@ class MongoDB(VectorStoreBase):
|
||||
"""Reset the index by deleting and recreating it."""
|
||||
logger.warning(f"Resetting index {self.collection_name}...")
|
||||
self.delete_col()
|
||||
self.collection = self.create_col(self.collection_name)
|
||||
self.collection = self.create_col()
|
||||
|
||||
def __del__(self) -> None:
|
||||
"""Close the database connection when the object is deleted."""
|
||||
|
||||
@@ -230,7 +230,7 @@ class PineconeDB(VectorStoreBase):
|
||||
if filter_dict:
|
||||
query_params["filter"] = filter_dict
|
||||
|
||||
if self.hybrid_search and self.sparse_encoder and "text" in filters:
|
||||
if self.hybrid_search and self.sparse_encoder and filters and "text" in filters:
|
||||
query_text = filters.get("text")
|
||||
if query_text:
|
||||
sparse_vector = self.sparse_encoder.encode_queries(query_text)
|
||||
|
||||
@@ -142,8 +142,11 @@ class RedisDB(VectorStoreBase):
|
||||
self.index.load(data, id_field="memory_id")
|
||||
|
||||
def search(self, query: str, vectors: list, top_k: int = 5, filters: dict = None):
|
||||
conditions = [Tag(key) == value for key, value in filters.items() if value is not None]
|
||||
filter = reduce(lambda x, y: x & y, conditions)
|
||||
filter = None
|
||||
if filters:
|
||||
conditions = [Tag(key) == value for key, value in filters.items() if value is not None]
|
||||
if conditions:
|
||||
filter = reduce(lambda x, y: x & y, conditions)
|
||||
|
||||
v = VectorQuery(
|
||||
vector=np.array(vectors, dtype=np.float32).tobytes(),
|
||||
@@ -312,11 +315,14 @@ class RedisDB(VectorStoreBase):
|
||||
"""
|
||||
List all recent created memories from the vector store.
|
||||
"""
|
||||
conditions = [Tag(key) == value for key, value in filters.items() if value is not None]
|
||||
filter = reduce(lambda x, y: x & y, conditions)
|
||||
query = Query(str(filter)).sort_by("created_at", asc=False)
|
||||
filter = None
|
||||
if filters:
|
||||
conditions = [Tag(key) == value for key, value in filters.items() if value is not None]
|
||||
if conditions:
|
||||
filter = reduce(lambda x, y: x & y, conditions)
|
||||
query = Query(str(filter) if filter is not None else "*").sort_by("created_at", asc=False)
|
||||
if top_k is not None:
|
||||
query = Query(str(filter)).sort_by("created_at", asc=False).paging(0, top_k)
|
||||
query = query.paging(0, top_k)
|
||||
|
||||
results = self.index.search(query)
|
||||
return [
|
||||
|
||||
@@ -176,7 +176,7 @@ class Supabase(VectorStoreBase):
|
||||
"""
|
||||
result = self.collection.fetch([(vector_id,)])
|
||||
if not result:
|
||||
return []
|
||||
return None
|
||||
|
||||
record = result[0]
|
||||
return OutputData(id=str(record.id), score=None, payload=record.metadata)
|
||||
|
||||
@@ -305,7 +305,7 @@ class Weaviate(VectorStoreBase):
|
||||
existing_payload: Mapping[str, str] = existing_data
|
||||
collection.data.update(uuid=vector_id, properties=existing_payload, vector=vector)
|
||||
|
||||
def get(self, vector_id):
|
||||
def get(self, vector_id) -> Optional[OutputData]:
|
||||
"""
|
||||
Retrieve a vector by ID.
|
||||
|
||||
@@ -313,7 +313,7 @@ class Weaviate(VectorStoreBase):
|
||||
vector_id: ID of the vector to retrieve.
|
||||
|
||||
Returns:
|
||||
dict: Retrieved vector and metadata.
|
||||
Optional[OutputData]: Retrieved vector, or None if the ID is not found.
|
||||
"""
|
||||
vector_id = get_valid_uuid(vector_id)
|
||||
collection = self.client.collections.get(str(self.collection_name))
|
||||
@@ -322,9 +322,8 @@ class Weaviate(VectorStoreBase):
|
||||
uuid=vector_id,
|
||||
return_properties=["hash", "created_at", "updated_at", "user_id", "agent_id", "run_id", "data", "category"],
|
||||
)
|
||||
# results = {}
|
||||
# print("reponse",response)
|
||||
# for obj in response.objects:
|
||||
if response is None:
|
||||
return None
|
||||
payload = response.properties.copy()
|
||||
payload["id"] = str(response.uuid).split("'")[0]
|
||||
results = OutputData(
|
||||
@@ -389,4 +388,4 @@ class Weaviate(VectorStoreBase):
|
||||
"""Reset the index by deleting and recreating it."""
|
||||
logger.warning(f"Resetting index {self.collection_name}...")
|
||||
self.delete_col()
|
||||
self.create_col()
|
||||
self.create_col(self.embedding_model_dims)
|
||||
|
||||
+4
-4
@@ -27,7 +27,7 @@ dependencies = [
|
||||
nlp = [
|
||||
"spacy>=3.7.0",
|
||||
]
|
||||
vector_stores = [
|
||||
vector-stores = [
|
||||
"vecs>=0.4.0",
|
||||
"chromadb>=0.4.24",
|
||||
"cassandra-driver>=3.29.0",
|
||||
@@ -103,7 +103,7 @@ only-include = ["mem0"]
|
||||
python = "3.10"
|
||||
features = [
|
||||
"test",
|
||||
"vector_stores",
|
||||
"vector-stores",
|
||||
"llms",
|
||||
"extras",
|
||||
]
|
||||
@@ -112,7 +112,7 @@ features = [
|
||||
python = "3.11"
|
||||
features = [
|
||||
"test",
|
||||
"vector_stores",
|
||||
"vector-stores",
|
||||
"llms",
|
||||
"extras",
|
||||
]
|
||||
@@ -121,7 +121,7 @@ features = [
|
||||
python = "3.12"
|
||||
features = [
|
||||
"test",
|
||||
"vector_stores",
|
||||
"vector-stores",
|
||||
"llms",
|
||||
"extras",
|
||||
]
|
||||
|
||||
@@ -424,3 +424,31 @@ class TestMiniMaxProvider:
|
||||
assert msg["role"] != "system"
|
||||
# user message must be present
|
||||
assert kwargs["messages"][0]["role"] == "user"
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# _parse_response — legacy InvokeModel provider-specific parsing
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
class TestParseResponseLegacy:
|
||||
def test_ai21_missing_completions_returns_empty(self, mock_boto3):
|
||||
"""When AI21 response lacks 'completions', the fallback default must
|
||||
be a valid dict (not a set literal), returning empty string."""
|
||||
llm = _make_llm("ai21.j2-mid-v1", mock_boto3)
|
||||
import io
|
||||
import json
|
||||
body = io.BytesIO(json.dumps({"not_completions": True}).encode())
|
||||
response = {"body": body}
|
||||
result = llm._parse_response(response, tools=None)
|
||||
assert result == ""
|
||||
|
||||
def test_ai21_normal_response(self, mock_boto3):
|
||||
llm = _make_llm("ai21.j2-mid-v1", mock_boto3)
|
||||
import io
|
||||
import json
|
||||
body = io.BytesIO(json.dumps({
|
||||
"completions": [{"data": {"text": "hello from ai21"}}]
|
||||
}).encode())
|
||||
response = {"body": body}
|
||||
result = llm._parse_response(response, tools=None)
|
||||
assert result == "hello from ai21"
|
||||
|
||||
@@ -29,6 +29,7 @@ class DummyConfig:
|
||||
max_tokens=256,
|
||||
top_p=1.0,
|
||||
http_client=None,
|
||||
reasoning_effort=None,
|
||||
):
|
||||
self.model = model
|
||||
self.azure_kwargs = azure_kwargs or DummyAzureKwargs()
|
||||
@@ -36,6 +37,7 @@ class DummyConfig:
|
||||
self.max_tokens = max_tokens
|
||||
self.top_p = top_p
|
||||
self.http_client = http_client
|
||||
self.reasoning_effort = reasoning_effort
|
||||
|
||||
|
||||
@mock.patch("mem0.llms.azure_openai_structured.AzureOpenAI")
|
||||
@@ -119,6 +121,44 @@ def test_generate_response_without_tools(mock_azure_openai):
|
||||
assert response == "Hello there!"
|
||||
|
||||
|
||||
@mock.patch("mem0.llms.azure_openai_structured.AzureOpenAI")
|
||||
def test_generate_response_gpt5_uses_max_completion_tokens(mock_azure_openai):
|
||||
mock_client = Mock()
|
||||
mock_azure_openai.return_value = mock_client
|
||||
|
||||
config = DummyConfig(model="gpt-5.4-mini", azure_kwargs=DummyAzureKwargs(api_key="real-key"))
|
||||
llm = AzureOpenAIStructuredLLM(config)
|
||||
|
||||
mock_response = Mock()
|
||||
mock_response.choices = [Mock(message=Mock(content="Hi"))]
|
||||
mock_client.chat.completions.create.return_value = mock_response
|
||||
|
||||
llm.generate_response([{"role": "user", "content": "Hi"}])
|
||||
|
||||
_, kwargs = mock_client.chat.completions.create.call_args
|
||||
assert kwargs["max_completion_tokens"] == 256
|
||||
assert "max_tokens" not in kwargs
|
||||
|
||||
|
||||
@mock.patch("mem0.llms.azure_openai_structured.AzureOpenAI")
|
||||
def test_generate_response_legacy_model_uses_max_tokens(mock_azure_openai):
|
||||
mock_client = Mock()
|
||||
mock_azure_openai.return_value = mock_client
|
||||
|
||||
config = DummyConfig(model="gpt-4.1", azure_kwargs=DummyAzureKwargs(api_key="real-key"))
|
||||
llm = AzureOpenAIStructuredLLM(config)
|
||||
|
||||
mock_response = Mock()
|
||||
mock_response.choices = [Mock(message=Mock(content="Hi"))]
|
||||
mock_client.chat.completions.create.return_value = mock_response
|
||||
|
||||
llm.generate_response([{"role": "user", "content": "Hi"}])
|
||||
|
||||
_, kwargs = mock_client.chat.completions.create.call_args
|
||||
assert kwargs["max_tokens"] == 256
|
||||
assert "max_completion_tokens" not in kwargs
|
||||
|
||||
|
||||
@mock.patch("mem0.llms.azure_openai_structured.AzureOpenAI")
|
||||
def test_generate_response_with_tools(mock_azure_openai):
|
||||
mock_client = Mock()
|
||||
@@ -171,3 +211,56 @@ def test_generate_response_with_tools_no_tool_calls(mock_azure_openai):
|
||||
|
||||
assert response["content"] == "No tools needed."
|
||||
assert response["tool_calls"] == []
|
||||
|
||||
|
||||
@mock.patch("mem0.llms.azure_openai_structured.AzureOpenAI")
|
||||
def test_reasoning_model_drops_sampling_params(mock_azure_openai):
|
||||
"""Reasoning models (o1/o3/GPT-5) reject temperature/max_tokens/top_p."""
|
||||
mock_client = Mock()
|
||||
mock_azure_openai.return_value = mock_client
|
||||
|
||||
config = DummyConfig(
|
||||
model="o3-mini",
|
||||
azure_kwargs=DummyAzureKwargs(api_key="real-key"),
|
||||
reasoning_effort="low",
|
||||
)
|
||||
llm = AzureOpenAIStructuredLLM(config)
|
||||
|
||||
mock_response = Mock()
|
||||
mock_response.choices = [Mock(message=Mock(content="ok"))]
|
||||
mock_client.chat.completions.create.return_value = mock_response
|
||||
|
||||
llm.generate_response([{"role": "user", "content": "Hi"}])
|
||||
|
||||
call_kwargs = mock_client.chat.completions.create.call_args[1]
|
||||
assert "temperature" not in call_kwargs # reasoning models reject these
|
||||
assert "max_tokens" not in call_kwargs
|
||||
assert "top_p" not in call_kwargs
|
||||
assert call_kwargs["reasoning_effort"] == "low"
|
||||
assert call_kwargs["model"] == "o3-mini"
|
||||
|
||||
|
||||
@mock.patch("mem0.llms.azure_openai_structured.AzureOpenAI")
|
||||
def test_regular_model_sends_sampling_params(mock_azure_openai):
|
||||
"""Regular models still receive the standard sampling params."""
|
||||
mock_client = Mock()
|
||||
mock_azure_openai.return_value = mock_client
|
||||
|
||||
config = DummyConfig(
|
||||
model="gpt-4o",
|
||||
azure_kwargs=DummyAzureKwargs(api_key="real-key"),
|
||||
temperature=0.3,
|
||||
)
|
||||
llm = AzureOpenAIStructuredLLM(config)
|
||||
|
||||
mock_response = Mock()
|
||||
mock_response.choices = [Mock(message=Mock(content="ok"))]
|
||||
mock_client.chat.completions.create.return_value = mock_response
|
||||
|
||||
llm.generate_response([{"role": "user", "content": "Hi"}])
|
||||
|
||||
call_kwargs = mock_client.chat.completions.create.call_args[1]
|
||||
assert call_kwargs["temperature"] == 0.3
|
||||
assert "max_tokens" in call_kwargs # standard sampling params still forwarded
|
||||
assert "top_p" in call_kwargs
|
||||
assert call_kwargs["model"] == "gpt-4o"
|
||||
|
||||
@@ -4,6 +4,7 @@ import pytest
|
||||
from google.genai import types
|
||||
|
||||
from mem0.configs.llms.base import BaseLlmConfig
|
||||
from mem0.configs.llms.gemini import GeminiConfig
|
||||
from mem0.llms.gemini import GeminiLLM
|
||||
|
||||
|
||||
@@ -187,3 +188,113 @@ def test_parse_response_empty_parts_with_tools(mock_gemini_client: Mock):
|
||||
|
||||
result = llm._parse_response(mock_response, tools=[{"function": {"name": "test"}}])
|
||||
assert result == {"content": None, "tool_calls": []}
|
||||
|
||||
|
||||
def test_none_config_values_omitted_from_generation_config(mock_gemini_client: Mock):
|
||||
"""When temperature/max_tokens/top_p are None, they must not be passed
|
||||
to GenerateContentConfig (verified via model_fields_set)."""
|
||||
config = BaseLlmConfig(model="gemini-2.0-flash", temperature=None, max_tokens=None, top_p=None)
|
||||
llm = GeminiLLM(config)
|
||||
|
||||
mock_part = Mock(text="ok")
|
||||
mock_content = Mock(parts=[mock_part])
|
||||
mock_candidate = Mock(content=mock_content)
|
||||
mock_response = Mock(candidates=[mock_candidate])
|
||||
mock_gemini_client.models.generate_content.return_value = mock_response
|
||||
|
||||
llm.generate_response([{"role": "user", "content": "hi"}])
|
||||
|
||||
config_arg = mock_gemini_client.models.generate_content.call_args.kwargs["config"]
|
||||
assert "temperature" not in config_arg.model_fields_set
|
||||
assert "max_output_tokens" not in config_arg.model_fields_set
|
||||
assert "top_p" not in config_arg.model_fields_set
|
||||
|
||||
|
||||
def test_explicit_config_values_passed_to_generation_config(mock_gemini_client: Mock):
|
||||
"""When temperature/max_tokens/top_p are explicitly set, they must appear."""
|
||||
config = BaseLlmConfig(model="gemini-2.0-flash", temperature=0.5, max_tokens=200, top_p=0.9)
|
||||
llm = GeminiLLM(config)
|
||||
|
||||
mock_part = Mock(text="ok")
|
||||
mock_content = Mock(parts=[mock_part])
|
||||
mock_candidate = Mock(content=mock_content)
|
||||
mock_response = Mock(candidates=[mock_candidate])
|
||||
mock_gemini_client.models.generate_content.return_value = mock_response
|
||||
|
||||
llm.generate_response([{"role": "user", "content": "hi"}])
|
||||
|
||||
config_arg = mock_gemini_client.models.generate_content.call_args.kwargs["config"]
|
||||
assert "temperature" in config_arg.model_fields_set
|
||||
assert config_arg.temperature == 0.5
|
||||
assert "max_output_tokens" in config_arg.model_fields_set
|
||||
assert config_arg.max_output_tokens == 200
|
||||
assert "top_p" in config_arg.model_fields_set
|
||||
assert config_arg.top_p == 0.9
|
||||
|
||||
|
||||
# --- Vertex AI backend initialization (issue #3990, PR #4030) ---
|
||||
|
||||
|
||||
def test_init_default_path_uses_api_key(monkeypatch):
|
||||
"""Default (non-Vertex) path stays backward compatible: client built with api_key, never vertexai."""
|
||||
monkeypatch.delenv("GOOGLE_GENAI_USE_VERTEXAI", raising=False)
|
||||
monkeypatch.setenv("GOOGLE_API_KEY", "test-key")
|
||||
with patch("mem0.llms.gemini.genai.Client") as mock_client_class:
|
||||
GeminiLLM(GeminiConfig(model="gemini-2.0-flash"))
|
||||
mock_client_class.assert_called_once_with(api_key="test-key")
|
||||
|
||||
|
||||
def test_init_backward_compat_with_base_config(monkeypatch):
|
||||
"""A legacy BaseLlmConfig still works and uses the API-key path (no missing-attr error)."""
|
||||
monkeypatch.delenv("GOOGLE_GENAI_USE_VERTEXAI", raising=False)
|
||||
monkeypatch.setenv("GOOGLE_API_KEY", "legacy-key")
|
||||
with patch("mem0.llms.gemini.genai.Client") as mock_client_class:
|
||||
GeminiLLM(BaseLlmConfig(model="gemini-2.0-flash"))
|
||||
mock_client_class.assert_called_once_with(api_key="legacy-key")
|
||||
|
||||
|
||||
def test_init_vertexai_via_explicit_config(monkeypatch):
|
||||
"""vertexai=True in GeminiConfig routes to the Vertex AI client with project/location, no api_key."""
|
||||
monkeypatch.delenv("GOOGLE_GENAI_USE_VERTEXAI", raising=False)
|
||||
with patch("mem0.llms.gemini.genai.Client") as mock_client_class:
|
||||
GeminiLLM(GeminiConfig(vertexai=True, project="my-project", location="europe-west1"))
|
||||
mock_client_class.assert_called_once_with(vertexai=True, project="my-project", location="europe-west1")
|
||||
|
||||
|
||||
def test_init_vertexai_via_dict_config(monkeypatch):
|
||||
"""The factory hands GeminiLLM a dict; the vertexai key still routes to the Vertex client."""
|
||||
monkeypatch.delenv("GOOGLE_GENAI_USE_VERTEXAI", raising=False)
|
||||
with patch("mem0.llms.gemini.genai.Client") as mock_client_class:
|
||||
GeminiLLM({"vertexai": True, "project": "p", "location": "us-central1"})
|
||||
mock_client_class.assert_called_once_with(vertexai=True, project="p", location="us-central1")
|
||||
|
||||
|
||||
def test_init_vertexai_via_env_vars(monkeypatch):
|
||||
"""GOOGLE_GENAI_USE_VERTEXAI + project/location env vars enable Vertex (the exact ask in issue #3990)."""
|
||||
monkeypatch.setenv("GOOGLE_GENAI_USE_VERTEXAI", "true")
|
||||
monkeypatch.setenv("GOOGLE_CLOUD_PROJECT", "env-project")
|
||||
monkeypatch.setenv("GOOGLE_CLOUD_LOCATION", "asia-south1")
|
||||
with patch("mem0.llms.gemini.genai.Client") as mock_client_class:
|
||||
GeminiLLM(GeminiConfig())
|
||||
mock_client_class.assert_called_once_with(vertexai=True, project="env-project", location="asia-south1")
|
||||
|
||||
|
||||
def test_init_vertexai_location_defaults_to_us_central1(monkeypatch):
|
||||
"""When Vertex is on but no location is supplied, it defaults to us-central1."""
|
||||
monkeypatch.delenv("GOOGLE_CLOUD_LOCATION", raising=False)
|
||||
monkeypatch.setenv("GOOGLE_GENAI_USE_VERTEXAI", "true")
|
||||
with patch("mem0.llms.gemini.genai.Client") as mock_client_class:
|
||||
GeminiLLM(GeminiConfig(project="p"))
|
||||
mock_client_class.assert_called_once_with(vertexai=True, project="p", location="us-central1")
|
||||
|
||||
|
||||
def test_init_base_config_respects_vertexai_env(monkeypatch):
|
||||
"""GOOGLE_GENAI_USE_VERTEXAI is the authoritative global switch (Google's own
|
||||
convention): a legacy BaseLlmConfig is routed to Vertex when the env var is set,
|
||||
even if it carries an api_key. This pins the precedence as intentional."""
|
||||
monkeypatch.setenv("GOOGLE_GENAI_USE_VERTEXAI", "true")
|
||||
monkeypatch.setenv("GOOGLE_CLOUD_PROJECT", "env-project")
|
||||
monkeypatch.setenv("GOOGLE_CLOUD_LOCATION", "us-west1")
|
||||
with patch("mem0.llms.gemini.genai.Client") as mock_client_class:
|
||||
GeminiLLM(BaseLlmConfig(model="gemini-2.0-flash", api_key="ignored-key"))
|
||||
mock_client_class.assert_called_once_with(vertexai=True, project="env-project", location="us-west1")
|
||||
|
||||
@@ -115,6 +115,20 @@ def test_generate_response_with_tools(mock_langchain_model):
|
||||
assert response["tool_calls"][0]["arguments"] == {"data": "Today is a sunny day."}
|
||||
|
||||
|
||||
def test_generate_response_forwards_extra_kwargs(mock_langchain_model):
|
||||
"""Per the LLMBase contract, extra model kwargs must be accepted and forwarded to
|
||||
the underlying LangChain model's ``invoke``."""
|
||||
config = BaseLlmConfig(model=mock_langchain_model, temperature=0.7, max_tokens=100, api_key="test-api-key")
|
||||
llm = LangchainLLM(config)
|
||||
messages = [{"role": "user", "content": "Hello"}]
|
||||
|
||||
response = llm.generate_response(messages, frequency_penalty=0.5)
|
||||
|
||||
mock_langchain_model.invoke.assert_called_once()
|
||||
assert mock_langchain_model.invoke.call_args.kwargs["frequency_penalty"] == 0.5
|
||||
assert response == "This is a test response"
|
||||
|
||||
|
||||
def test_invalid_model():
|
||||
"""Test that LangchainLLM raises an error with an invalid model."""
|
||||
config = BaseLlmConfig(model="not-a-valid-model-instance", temperature=0.7, max_tokens=100, api_key="test-api-key")
|
||||
|
||||
@@ -19,8 +19,26 @@ def test_generate_response_with_unsupported_model(mock_litellm):
|
||||
|
||||
mock_litellm.supports_function_calling.return_value = False
|
||||
|
||||
tools = [{"type": "function", "function": {"name": "test", "parameters": {}}}]
|
||||
|
||||
with pytest.raises(ValueError, match="Model 'unsupported-model' in litellm does not support function calling."):
|
||||
llm.generate_response(messages)
|
||||
llm.generate_response(messages, tools=tools)
|
||||
|
||||
|
||||
def test_generate_response_with_unsupported_model_no_tools(mock_litellm):
|
||||
config = BaseLlmConfig(model="unsupported-model", temperature=0.7, max_tokens=100, top_p=1)
|
||||
llm = litellm.LiteLLM(config)
|
||||
messages = [{"role": "user", "content": "Hello"}]
|
||||
|
||||
mock_response = Mock()
|
||||
mock_response.choices = [Mock(message=Mock(content="hi"))]
|
||||
mock_litellm.completion.return_value = mock_response
|
||||
mock_litellm.supports_function_calling.return_value = False
|
||||
|
||||
response = llm.generate_response(messages)
|
||||
|
||||
assert response == "hi"
|
||||
mock_litellm.supports_function_calling.assert_not_called()
|
||||
|
||||
|
||||
def test_generate_response_without_tools(mock_litellm):
|
||||
@@ -44,6 +62,40 @@ def test_generate_response_without_tools(mock_litellm):
|
||||
assert response == "I'm doing well, thank you for asking!"
|
||||
|
||||
|
||||
def test_generate_response_gpt5_uses_max_completion_tokens(mock_litellm):
|
||||
config = BaseLlmConfig(model="gpt-5.4-mini", temperature=0.7, max_tokens=100, top_p=1)
|
||||
llm = litellm.LiteLLM(config)
|
||||
messages = [{"role": "user", "content": "Hello"}]
|
||||
|
||||
mock_response = Mock()
|
||||
mock_response.choices = [Mock(message=Mock(content="Hi"))]
|
||||
mock_litellm.completion.return_value = mock_response
|
||||
mock_litellm.supports_function_calling.return_value = True
|
||||
|
||||
llm.generate_response(messages)
|
||||
|
||||
_, kwargs = mock_litellm.completion.call_args
|
||||
assert kwargs["max_completion_tokens"] == 100
|
||||
assert "max_tokens" not in kwargs
|
||||
|
||||
|
||||
def test_generate_response_legacy_model_uses_max_tokens(mock_litellm):
|
||||
config = BaseLlmConfig(model="gpt-4.1", temperature=0.7, max_tokens=100, top_p=1)
|
||||
llm = litellm.LiteLLM(config)
|
||||
messages = [{"role": "user", "content": "Hello"}]
|
||||
|
||||
mock_response = Mock()
|
||||
mock_response.choices = [Mock(message=Mock(content="Hi"))]
|
||||
mock_litellm.completion.return_value = mock_response
|
||||
mock_litellm.supports_function_calling.return_value = True
|
||||
|
||||
llm.generate_response(messages)
|
||||
|
||||
_, kwargs = mock_litellm.completion.call_args
|
||||
assert kwargs["max_tokens"] == 100
|
||||
assert "max_completion_tokens" not in kwargs
|
||||
|
||||
|
||||
def test_generate_response_with_tools(mock_litellm):
|
||||
config = BaseLlmConfig(model="gpt-4.1-nano-2025-04-14", temperature=0.7, max_tokens=100, top_p=1)
|
||||
llm = litellm.LiteLLM(config)
|
||||
|
||||
@@ -375,6 +375,45 @@ def test_is_reasoning_model_override_generates_correct_params(mock_openai_client
|
||||
assert "temperature" not in call_kwargs
|
||||
|
||||
|
||||
def test_gpt5_uses_max_completion_tokens(mock_openai_client):
|
||||
"""gpt-5.x (non-reasoning) must send max_completion_tokens, not max_tokens.
|
||||
|
||||
The GPT-5 family rejects the legacy max_tokens param on Chat Completions and
|
||||
requires max_completion_tokens. Regression test for
|
||||
https://github.com/mem0ai/mem0/issues/5054
|
||||
"""
|
||||
config = OpenAIConfig(model="gpt-5.4-mini", temperature=0.7, max_tokens=100, top_p=1.0)
|
||||
llm = OpenAILLM(config)
|
||||
messages = [{"role": "user", "content": "Hello"}]
|
||||
|
||||
mock_response = Mock()
|
||||
mock_response.choices = [Mock(message=Mock(content="ok"))]
|
||||
mock_openai_client.chat.completions.create.return_value = mock_response
|
||||
|
||||
llm.generate_response(messages)
|
||||
|
||||
call_kwargs = mock_openai_client.chat.completions.create.call_args[1]
|
||||
assert call_kwargs.get("max_completion_tokens") == 100
|
||||
assert "max_tokens" not in call_kwargs
|
||||
|
||||
|
||||
def test_gpt4_uses_max_tokens(mock_openai_client):
|
||||
"""Older models (gpt-4.x) keep using max_tokens — guards against regressions."""
|
||||
config = OpenAIConfig(model="gpt-4.1-nano-2025-04-14", temperature=0.7, max_tokens=100, top_p=1.0)
|
||||
llm = OpenAILLM(config)
|
||||
messages = [{"role": "user", "content": "Hello"}]
|
||||
|
||||
mock_response = Mock()
|
||||
mock_response.choices = [Mock(message=Mock(content="ok"))]
|
||||
mock_openai_client.chat.completions.create.return_value = mock_response
|
||||
|
||||
llm.generate_response(messages)
|
||||
|
||||
call_kwargs = mock_openai_client.chat.completions.create.call_args[1]
|
||||
assert call_kwargs.get("max_tokens") == 100
|
||||
assert "max_completion_tokens" not in call_kwargs
|
||||
|
||||
|
||||
def test_callback_with_tools(mock_openai_client):
|
||||
mock_callback = Mock()
|
||||
config = OpenAIConfig(model="gpt-4.1-nano-2025-04-14", response_callback=mock_callback)
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
from unittest.mock import Mock, patch
|
||||
|
||||
import pytest
|
||||
|
||||
from mem0.configs.llms.openai import OpenAIConfig
|
||||
from mem0.llms.openai_structured import OpenAIStructuredLLM
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def mock_openai_client():
|
||||
with patch("mem0.llms.openai_structured.OpenAI") as mock_openai:
|
||||
mock_client = Mock()
|
||||
mock_openai.return_value = mock_client
|
||||
yield mock_client
|
||||
|
||||
|
||||
def _mock_parse(mock_client, content="ok"):
|
||||
mock_response = Mock()
|
||||
mock_response.choices = [Mock(message=Mock(content=content))]
|
||||
mock_client.beta.chat.completions.parse.return_value = mock_response
|
||||
|
||||
|
||||
def test_reasoning_model_drops_temperature(mock_openai_client):
|
||||
"""Reasoning models reject `temperature`; structured output must not send it."""
|
||||
config = OpenAIConfig(model="o3-mini", reasoning_effort="low")
|
||||
llm = OpenAIStructuredLLM(config)
|
||||
_mock_parse(mock_openai_client)
|
||||
|
||||
llm.generate_response([{"role": "user", "content": "Hello"}])
|
||||
|
||||
call_kwargs = mock_openai_client.beta.chat.completions.parse.call_args[1]
|
||||
assert "temperature" not in call_kwargs # reasoning models don't accept temperature
|
||||
assert "max_tokens" not in call_kwargs # also dropped for reasoning models
|
||||
assert "top_p" not in call_kwargs # also dropped for reasoning models
|
||||
assert call_kwargs["reasoning_effort"] == "low"
|
||||
assert call_kwargs["model"] == "o3-mini"
|
||||
|
||||
|
||||
def test_regular_model_sends_sampling_params(mock_openai_client):
|
||||
"""Regular models still receive the standard sampling params."""
|
||||
config = OpenAIConfig(model="gpt-4o", temperature=0.3)
|
||||
llm = OpenAIStructuredLLM(config)
|
||||
_mock_parse(mock_openai_client)
|
||||
|
||||
llm.generate_response([{"role": "user", "content": "Hello"}])
|
||||
|
||||
call_kwargs = mock_openai_client.beta.chat.completions.parse.call_args[1]
|
||||
assert call_kwargs["temperature"] == 0.3
|
||||
assert "max_tokens" in call_kwargs # standard sampling params still forwarded
|
||||
assert "top_p" in call_kwargs
|
||||
assert call_kwargs["model"] == "gpt-4o"
|
||||
@@ -0,0 +1,46 @@
|
||||
from unittest.mock import Mock, patch
|
||||
|
||||
import pytest
|
||||
|
||||
from mem0.configs.llms.base import BaseLlmConfig
|
||||
from mem0.llms.sarvam import SarvamLLM
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def sarvam_llm():
|
||||
config = BaseLlmConfig(model="sarvam-m", temperature=0.7, max_tokens=100, top_p=1.0, api_key="test-api-key")
|
||||
return SarvamLLM(config)
|
||||
|
||||
|
||||
def _mock_post(content="Hello there!"):
|
||||
mock_response = Mock()
|
||||
mock_response.raise_for_status.return_value = None
|
||||
mock_response.json.return_value = {"choices": [{"message": {"content": content}}]}
|
||||
return mock_response
|
||||
|
||||
|
||||
def test_generate_response_returns_content(sarvam_llm):
|
||||
with patch("mem0.llms.sarvam.requests.post", return_value=_mock_post("Hi!")) as mock_post:
|
||||
messages = [
|
||||
{"role": "system", "content": "You are a helpful assistant."},
|
||||
{"role": "user", "content": "Hello, how are you?"},
|
||||
]
|
||||
response = sarvam_llm.generate_response(messages)
|
||||
|
||||
assert response == "Hi!"
|
||||
sent_payload = mock_post.call_args.kwargs["json"]
|
||||
assert sent_payload["model"] == "sarvam-m"
|
||||
assert sent_payload["messages"] == messages
|
||||
assert sent_payload["temperature"] == 0.7
|
||||
|
||||
|
||||
def test_generate_response_forwards_extra_kwargs(sarvam_llm):
|
||||
"""Per the LLMBase contract, extra provider-specific kwargs must be accepted and
|
||||
forwarded into the Sarvam request payload."""
|
||||
with patch("mem0.llms.sarvam.requests.post", return_value=_mock_post("Hi!")) as mock_post:
|
||||
messages = [{"role": "user", "content": "Hello"}]
|
||||
response = sarvam_llm.generate_response(messages, frequency_penalty=0.5)
|
||||
|
||||
assert response == "Hi!"
|
||||
sent_payload = mock_post.call_args.kwargs["json"]
|
||||
assert sent_payload["frequency_penalty"] == 0.5
|
||||
@@ -84,3 +84,21 @@ def test_generate_response_with_tools(mock_together_client):
|
||||
assert len(response["tool_calls"]) == 1
|
||||
assert response["tool_calls"][0]["name"] == "add_memory"
|
||||
assert response["tool_calls"][0]["arguments"] == {"data": "Today is a sunny day."}
|
||||
|
||||
|
||||
def test_generate_response_forwards_extra_kwargs(mock_together_client):
|
||||
"""Per the LLMBase contract, extra provider-specific kwargs must be accepted and
|
||||
forwarded to the Together client (matching openai/deepseek/vllm/xai behavior)."""
|
||||
config = BaseLlmConfig(model="mistralai/Mixtral-8x7B-Instruct-v0.1", temperature=0.7, max_tokens=100, top_p=1.0)
|
||||
llm = TogetherLLM(config)
|
||||
messages = [{"role": "user", "content": "Hello"}]
|
||||
|
||||
mock_response = Mock()
|
||||
mock_response.choices = [Mock(message=Mock(content="Hi"))]
|
||||
mock_together_client.chat.completions.create.return_value = mock_response
|
||||
|
||||
response = llm.generate_response(messages, frequency_penalty=0.5)
|
||||
|
||||
assert response == "Hi"
|
||||
call_kwargs = mock_together_client.chat.completions.create.call_args.kwargs
|
||||
assert call_kwargs["frequency_penalty"] == 0.5
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
import logging
|
||||
from unittest.mock import Mock
|
||||
|
||||
from mem0.memory.main import (
|
||||
ADD_CONTEXT_SEARCH_MAX_CHARS,
|
||||
ADD_MAX_ENTITY_LINKS_PER_EVENT,
|
||||
ADD_MAX_EXTRACTED_MEMORIES,
|
||||
ADD_MEMORY_EMBEDDING_MAX_CHARS,
|
||||
Memory,
|
||||
SEARCH_QUERY_MAX_CHARS,
|
||||
_cap_entity_keys,
|
||||
_cap_extracted_memories,
|
||||
_cap_memory_embedding_texts,
|
||||
_tail_cap_text,
|
||||
)
|
||||
|
||||
|
||||
def test_tail_cap_text_keeps_recent_suffix():
|
||||
text = "old-" + ("x" * ADD_CONTEXT_SEARCH_MAX_CHARS)
|
||||
|
||||
capped = _tail_cap_text(text, ADD_CONTEXT_SEARCH_MAX_CHARS)
|
||||
|
||||
assert capped == text[-ADD_CONTEXT_SEARCH_MAX_CHARS:]
|
||||
|
||||
|
||||
def test_cap_extracted_memories_keeps_last_memories(caplog):
|
||||
memories = [{"text": f"memory-{i}"} for i in range(ADD_MAX_EXTRACTED_MEMORIES + 3)]
|
||||
|
||||
with caplog.at_level(logging.WARNING):
|
||||
capped = _cap_extracted_memories(memories)
|
||||
|
||||
assert capped == memories[-ADD_MAX_EXTRACTED_MEMORIES:]
|
||||
assert any("Extracted memory cap applied" in record.message for record in caplog.records)
|
||||
|
||||
|
||||
def test_cap_memory_embedding_texts_keeps_original_text_untouched(caplog):
|
||||
original = "old-" + ("z" * ADD_MEMORY_EMBEDDING_MAX_CHARS)
|
||||
|
||||
with caplog.at_level(logging.WARNING):
|
||||
capped = _cap_memory_embedding_texts([original])
|
||||
|
||||
assert capped == [original[-ADD_MEMORY_EMBEDDING_MAX_CHARS:]]
|
||||
assert original.startswith("old-")
|
||||
assert any("Memory embedding input cap applied" in record.message for record in caplog.records)
|
||||
|
||||
|
||||
def test_cap_entity_keys_keeps_first_100_entities(caplog):
|
||||
keys = [f"entity-{i}" for i in range(ADD_MAX_ENTITY_LINKS_PER_EVENT + 3)]
|
||||
|
||||
with caplog.at_level(logging.WARNING):
|
||||
capped = _cap_entity_keys(keys)
|
||||
|
||||
assert capped == keys[:ADD_MAX_ENTITY_LINKS_PER_EVENT]
|
||||
assert any("ADD entity-linking cap applied" in record.message for record in caplog.records)
|
||||
|
||||
|
||||
def test_search_vector_store_caps_query_before_embedding():
|
||||
memory = object.__new__(Memory)
|
||||
memory.embedding_model = Mock()
|
||||
memory.embedding_model.embed.return_value = [0.1, 0.2, 0.3]
|
||||
memory.vector_store = Mock()
|
||||
memory.vector_store.search.return_value = []
|
||||
memory.vector_store.keyword_search.return_value = None
|
||||
memory._compute_entity_boosts = Mock(return_value={})
|
||||
query = "old-" + ("q" * SEARCH_QUERY_MAX_CHARS)
|
||||
|
||||
Memory._search_vector_store(memory, query, filters={}, limit=5)
|
||||
|
||||
memory.embedding_model.embed.assert_called_once_with(query[-SEARCH_QUERY_MAX_CHARS:], "search")
|
||||
@@ -1,10 +1,50 @@
|
||||
import pytest
|
||||
from unittest.mock import Mock
|
||||
|
||||
from mem0.memory.utils import parse_vision_messages, remove_spaces_from_entities, sanitize_relationship_for_cypher
|
||||
from mem0.memory.utils import (
|
||||
parse_messages,
|
||||
parse_vision_messages,
|
||||
remove_spaces_from_entities,
|
||||
sanitize_relationship_for_cypher,
|
||||
)
|
||||
|
||||
|
||||
class TestParseMessages:
|
||||
def test_skips_message_without_content_key(self):
|
||||
# Reproduces #5067: a FunctionCalling assistant message carries
|
||||
# `tool_calls` but no `content` key -> used to raise KeyError.
|
||||
messages = [
|
||||
{"role": "user", "content": "hi"},
|
||||
{"role": "assistant", "tool_calls": [{"id": "1", "function": {"name": "search"}}]},
|
||||
{"role": "assistant", "content": "done"},
|
||||
]
|
||||
result = parse_messages(messages)
|
||||
assert result == "user: hi\nassistant: done\n"
|
||||
|
||||
def test_skips_explicit_none_content(self):
|
||||
messages = [{"role": "assistant", "content": None}, {"role": "user", "content": "ok"}]
|
||||
assert parse_messages(messages) == "user: ok\n"
|
||||
|
||||
def test_plain_roles_pass_through(self):
|
||||
messages = [
|
||||
{"role": "system", "content": "sys"},
|
||||
{"role": "user", "content": "u"},
|
||||
{"role": "assistant", "content": "a"},
|
||||
]
|
||||
assert parse_messages(messages) == "system: sys\nuser: u\nassistant: a\n"
|
||||
|
||||
|
||||
class TestParseVisionMessages:
|
||||
def test_skips_message_without_content_key(self):
|
||||
# Reproduces #5067 for the vision parser path.
|
||||
messages = [
|
||||
{"role": "user", "content": "hi"},
|
||||
{"role": "assistant", "tool_calls": [{"id": "1", "function": {"name": "search"}}]},
|
||||
]
|
||||
result = parse_vision_messages(messages, llm=None)
|
||||
assert len(result) == 1
|
||||
assert result[0] == {"role": "user", "content": "hi"}
|
||||
|
||||
def test_multimodal_list_without_llm_extracts_text(self):
|
||||
messages = [
|
||||
{"role": "user", "content": [
|
||||
|
||||
@@ -0,0 +1,109 @@
|
||||
"""Regression tests for the reranker fallback path honoring ``config.top_k``.
|
||||
|
||||
When the underlying rerank call fails, the reranker falls back to returning the
|
||||
documents in their original order. That fallback must still respect the
|
||||
configured ``top_k`` limit, exactly like the success path does. The HuggingFace
|
||||
and SentenceTransformer rerankers already behave this way; these tests pin the
|
||||
same contract for the Cohere and ZeroEntropy rerankers.
|
||||
"""
|
||||
|
||||
import sys
|
||||
from types import ModuleType
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
import pytest
|
||||
|
||||
from mem0.configs.rerankers.cohere import CohereRerankerConfig
|
||||
from mem0.configs.rerankers.zero_entropy import ZeroEntropyRerankerConfig
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def mock_cohere(monkeypatch):
|
||||
"""Provide a fake ``cohere`` module so CohereReranker imports/constructs."""
|
||||
fake_cohere = ModuleType("cohere")
|
||||
fake_client = MagicMock()
|
||||
fake_cohere.Client = MagicMock(return_value=fake_client)
|
||||
monkeypatch.setitem(sys.modules, "cohere", fake_cohere)
|
||||
|
||||
import mem0.reranker.cohere_reranker as cohere_reranker
|
||||
|
||||
monkeypatch.setattr(cohere_reranker, "cohere", fake_cohere, raising=False)
|
||||
monkeypatch.setattr(cohere_reranker, "COHERE_AVAILABLE", True, raising=False)
|
||||
return cohere_reranker, fake_client
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def mock_zero_entropy(monkeypatch):
|
||||
"""Provide a fake ``zeroentropy`` module so ZeroEntropyReranker imports."""
|
||||
fake_module = ModuleType("zeroentropy")
|
||||
fake_client = MagicMock()
|
||||
fake_module.ZeroEntropy = MagicMock(return_value=fake_client)
|
||||
monkeypatch.setitem(sys.modules, "zeroentropy", fake_module)
|
||||
|
||||
import mem0.reranker.zero_entropy_reranker as zero_entropy_reranker
|
||||
|
||||
monkeypatch.setattr(zero_entropy_reranker, "ZeroEntropy", fake_module.ZeroEntropy, raising=False)
|
||||
monkeypatch.setattr(zero_entropy_reranker, "ZERO_ENTROPY_AVAILABLE", True, raising=False)
|
||||
return zero_entropy_reranker, fake_client
|
||||
|
||||
|
||||
def _docs(n):
|
||||
return [{"memory": f"doc{i}"} for i in range(n)]
|
||||
|
||||
|
||||
class TestCohereFallbackTopK:
|
||||
def test_fallback_respects_config_top_k(self, mock_cohere):
|
||||
module, fake_client = mock_cohere
|
||||
fake_client.rerank.side_effect = RuntimeError("API error")
|
||||
|
||||
reranker = module.CohereReranker(CohereRerankerConfig(api_key="test-key", top_k=2))
|
||||
result = reranker.rerank("query", _docs(5))
|
||||
|
||||
assert len(result) == 2
|
||||
|
||||
def test_fallback_per_call_top_k_overrides_config(self, mock_cohere):
|
||||
module, fake_client = mock_cohere
|
||||
fake_client.rerank.side_effect = RuntimeError("API error")
|
||||
|
||||
reranker = module.CohereReranker(CohereRerankerConfig(api_key="test-key", top_k=4))
|
||||
result = reranker.rerank("query", _docs(5), top_k=1)
|
||||
|
||||
assert len(result) == 1
|
||||
|
||||
def test_fallback_returns_all_when_no_top_k(self, mock_cohere):
|
||||
module, fake_client = mock_cohere
|
||||
fake_client.rerank.side_effect = RuntimeError("API error")
|
||||
|
||||
reranker = module.CohereReranker(CohereRerankerConfig(api_key="test-key"))
|
||||
result = reranker.rerank("query", _docs(5))
|
||||
|
||||
assert len(result) == 5
|
||||
|
||||
|
||||
class TestZeroEntropyFallbackTopK:
|
||||
def test_fallback_respects_config_top_k(self, mock_zero_entropy):
|
||||
module, fake_client = mock_zero_entropy
|
||||
fake_client.models.rerank.side_effect = RuntimeError("API error")
|
||||
|
||||
reranker = module.ZeroEntropyReranker(ZeroEntropyRerankerConfig(api_key="test-key", top_k=2))
|
||||
result = reranker.rerank("query", _docs(5))
|
||||
|
||||
assert len(result) == 2
|
||||
|
||||
def test_fallback_per_call_top_k_overrides_config(self, mock_zero_entropy):
|
||||
module, fake_client = mock_zero_entropy
|
||||
fake_client.models.rerank.side_effect = RuntimeError("API error")
|
||||
|
||||
reranker = module.ZeroEntropyReranker(ZeroEntropyRerankerConfig(api_key="test-key", top_k=4))
|
||||
result = reranker.rerank("query", _docs(5), top_k=1)
|
||||
|
||||
assert len(result) == 1
|
||||
|
||||
def test_fallback_returns_all_when_no_top_k(self, mock_zero_entropy):
|
||||
module, fake_client = mock_zero_entropy
|
||||
fake_client.models.rerank.side_effect = RuntimeError("API error")
|
||||
|
||||
reranker = module.ZeroEntropyReranker(ZeroEntropyRerankerConfig(api_key="test-key"))
|
||||
result = reranker.rerank("query", _docs(5))
|
||||
|
||||
assert len(result) == 5
|
||||
@@ -762,6 +762,55 @@ async def test_async_delete_memory_history_has_timestamps(mock_sqlite, mock_llm_
|
||||
datetime.fromisoformat(call_kwargs["updated_at"]) # verify valid ISO timestamp
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@patch('mem0.utils.factory.EmbedderFactory.create')
|
||||
@patch('mem0.utils.factory.VectorStoreFactory.create')
|
||||
@patch('mem0.utils.factory.LlmFactory.create')
|
||||
@patch('mem0.memory.main.SQLiteManager')
|
||||
async def test_async_delete_all_continues_on_partial_failure(mock_sqlite, mock_llm_factory, mock_vector_factory, mock_embedder_factory):
|
||||
"""async delete_all must not abort when a single memory fails to delete.
|
||||
|
||||
Without return_exceptions=True, asyncio.gather raises on the first error
|
||||
and cancels remaining tasks, leaving a partial deletion.
|
||||
"""
|
||||
mock_embedder_factory.return_value = MagicMock()
|
||||
mock_vector_store = MagicMock()
|
||||
mock_vector_factory.return_value = mock_vector_store
|
||||
mock_llm_factory.return_value = MagicMock()
|
||||
mock_sqlite.return_value = MagicMock()
|
||||
|
||||
from mem0.memory.main import AsyncMemory
|
||||
config = MemoryConfig()
|
||||
memory = AsyncMemory(config)
|
||||
|
||||
mem1 = MagicMock()
|
||||
mem1.id = "mem-1"
|
||||
mem1.payload = {"data": "one", "created_at": "2024-01-01T00:00:00+00:00", "actor_id": None, "role": None}
|
||||
mem2 = MagicMock()
|
||||
mem2.id = "mem-2"
|
||||
mem2.payload = {"data": "two", "created_at": "2024-01-01T00:00:00+00:00", "actor_id": None, "role": None}
|
||||
mem3 = MagicMock()
|
||||
mem3.id = "mem-3"
|
||||
mem3.payload = {"data": "three", "created_at": "2024-01-01T00:00:00+00:00", "actor_id": None, "role": None}
|
||||
|
||||
mock_vector_store.list.return_value = ([mem1, mem2, mem3],)
|
||||
|
||||
def _get_side_effect(vector_id):
|
||||
if vector_id == "mem-2":
|
||||
raise RuntimeError("simulated store failure")
|
||||
return {
|
||||
"mem-1": mem1,
|
||||
"mem-3": mem3,
|
||||
}.get(vector_id)
|
||||
|
||||
mock_vector_store.get.side_effect = _get_side_effect
|
||||
|
||||
result = await memory.delete_all(user_id="test-user")
|
||||
|
||||
assert result == {"message": "Memories deleted successfully!"}
|
||||
assert mock_vector_store.delete.call_count == 2
|
||||
|
||||
|
||||
@patch('mem0.utils.factory.EmbedderFactory.create')
|
||||
@patch('mem0.utils.factory.VectorStoreFactory.create')
|
||||
@patch('mem0.utils.factory.LlmFactory.create')
|
||||
@@ -1056,3 +1105,154 @@ class TestHybridSearchWarning:
|
||||
Memory(config)
|
||||
|
||||
assert not any("does not support keyword search" in r.message for r in caplog.records)
|
||||
|
||||
|
||||
class TestPreserveCustomMetadata:
|
||||
|
||||
@patch('mem0.utils.factory.EmbedderFactory.create')
|
||||
@patch('mem0.utils.factory.VectorStoreFactory.create')
|
||||
@patch('mem0.utils.factory.LlmFactory.create')
|
||||
@patch('mem0.memory.storage.SQLiteManager')
|
||||
def test_update_preserves_custom_metadata(self, mock_sqlite, mock_llm_factory, mock_vector_factory, mock_embedder_factory):
|
||||
mock_embedder_factory.return_value = MagicMock()
|
||||
mock_vector_store = MagicMock()
|
||||
mock_vector_factory.return_value = mock_vector_store
|
||||
mock_llm_factory.return_value = MagicMock()
|
||||
mock_sqlite.return_value = MagicMock()
|
||||
|
||||
existing_payload = {
|
||||
"data": "I love playing tennis",
|
||||
"hash": "abc123",
|
||||
"created_at": "2026-01-01T00:00:00+00:00",
|
||||
"updated_at": "2026-01-01T00:00:00+00:00",
|
||||
"user_id": "user_1",
|
||||
"category": "hobbies",
|
||||
"priority": "high",
|
||||
"source": "chat",
|
||||
}
|
||||
mock_vector_store.get.return_value = MockVectorMemory("mem-1", existing_payload)
|
||||
|
||||
embedder = MagicMock()
|
||||
embedder.embed.return_value = [0.1, 0.2, 0.3]
|
||||
mock_embedder_factory.return_value = embedder
|
||||
|
||||
config = MemoryConfig()
|
||||
memory = Memory(config)
|
||||
|
||||
memory._update_memory("mem-1", "I love playing tennis and swimming", {"I love playing tennis and swimming": [0.1, 0.2, 0.3]})
|
||||
|
||||
call_args = mock_vector_store.update.call_args
|
||||
payload = call_args.kwargs.get("payload") or call_args[1].get("payload")
|
||||
assert payload["category"] == "hobbies"
|
||||
assert payload["priority"] == "high"
|
||||
assert payload["source"] == "chat"
|
||||
assert payload["data"] == "I love playing tennis and swimming"
|
||||
assert payload["user_id"] == "user_1"
|
||||
|
||||
@patch('mem0.utils.factory.EmbedderFactory.create')
|
||||
@patch('mem0.utils.factory.VectorStoreFactory.create')
|
||||
@patch('mem0.utils.factory.LlmFactory.create')
|
||||
@patch('mem0.memory.storage.SQLiteManager')
|
||||
def test_update_with_new_metadata_overrides_existing(self, mock_sqlite, mock_llm_factory, mock_vector_factory, mock_embedder_factory):
|
||||
mock_embedder_factory.return_value = MagicMock()
|
||||
mock_vector_store = MagicMock()
|
||||
mock_vector_factory.return_value = mock_vector_store
|
||||
mock_llm_factory.return_value = MagicMock()
|
||||
mock_sqlite.return_value = MagicMock()
|
||||
|
||||
existing_payload = {
|
||||
"data": "I love playing tennis",
|
||||
"hash": "abc123",
|
||||
"created_at": "2026-01-01T00:00:00+00:00",
|
||||
"updated_at": "2026-01-01T00:00:00+00:00",
|
||||
"user_id": "user_1",
|
||||
"category": "hobbies",
|
||||
"priority": "high",
|
||||
}
|
||||
mock_vector_store.get.return_value = MockVectorMemory("mem-1", existing_payload)
|
||||
|
||||
config = MemoryConfig()
|
||||
memory = Memory(config)
|
||||
|
||||
memory._update_memory(
|
||||
"mem-1", "Updated text",
|
||||
{"Updated text": [0.1, 0.2, 0.3]},
|
||||
metadata={"priority": "low", "new_field": "value"},
|
||||
)
|
||||
|
||||
call_args = mock_vector_store.update.call_args
|
||||
payload = call_args.kwargs.get("payload") or call_args[1].get("payload")
|
||||
assert payload["category"] == "hobbies"
|
||||
assert payload["priority"] == "low"
|
||||
assert payload["new_field"] == "value"
|
||||
assert payload["data"] == "Updated text"
|
||||
|
||||
@patch('mem0.utils.factory.EmbedderFactory.create')
|
||||
@patch('mem0.utils.factory.VectorStoreFactory.create')
|
||||
@patch('mem0.utils.factory.LlmFactory.create')
|
||||
@patch('mem0.memory.storage.SQLiteManager')
|
||||
def test_update_preserves_actor_id_from_original(self, mock_sqlite, mock_llm_factory, mock_vector_factory, mock_embedder_factory):
|
||||
mock_embedder_factory.return_value = MagicMock()
|
||||
mock_vector_store = MagicMock()
|
||||
mock_vector_factory.return_value = mock_vector_store
|
||||
mock_llm_factory.return_value = MagicMock()
|
||||
mock_sqlite.return_value = MagicMock()
|
||||
|
||||
existing_payload = {
|
||||
"data": "I am player #1",
|
||||
"hash": "abc123",
|
||||
"created_at": "2026-01-01T00:00:00+00:00",
|
||||
"updated_at": "2026-01-01T00:00:00+00:00",
|
||||
"user_id": "team",
|
||||
"actor_id": "Alice",
|
||||
}
|
||||
mock_vector_store.get.return_value = MockVectorMemory("mem-1", existing_payload)
|
||||
|
||||
config = MemoryConfig()
|
||||
memory = Memory(config)
|
||||
|
||||
memory._update_memory(
|
||||
"mem-1", "Player #1 is great",
|
||||
{"Player #1 is great": [0.1, 0.2, 0.3]},
|
||||
metadata={"user_id": "team", "actor_id": "Bob"},
|
||||
)
|
||||
|
||||
call_args = mock_vector_store.update.call_args
|
||||
payload = call_args.kwargs.get("payload") or call_args[1].get("payload")
|
||||
assert payload["actor_id"] == "Alice"
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@patch('mem0.utils.factory.EmbedderFactory.create')
|
||||
@patch('mem0.utils.factory.VectorStoreFactory.create')
|
||||
@patch('mem0.utils.factory.LlmFactory.create')
|
||||
@patch('mem0.memory.storage.SQLiteManager')
|
||||
async def test_async_update_preserves_custom_metadata(self, mock_sqlite, mock_llm_factory, mock_vector_factory, mock_embedder_factory):
|
||||
mock_embedder_factory.return_value = MagicMock()
|
||||
mock_vector_store = MagicMock()
|
||||
mock_vector_factory.return_value = mock_vector_store
|
||||
mock_llm_factory.return_value = MagicMock()
|
||||
mock_sqlite.return_value = MagicMock()
|
||||
|
||||
existing_payload = {
|
||||
"data": "I love playing tennis",
|
||||
"hash": "abc123",
|
||||
"created_at": "2026-01-01T00:00:00+00:00",
|
||||
"updated_at": "2026-01-01T00:00:00+00:00",
|
||||
"user_id": "user_1",
|
||||
"category": "hobbies",
|
||||
"source": "chat",
|
||||
}
|
||||
mock_vector_store.get.return_value = MockVectorMemory("mem-1", existing_payload)
|
||||
|
||||
from mem0.memory.main import AsyncMemory
|
||||
config = MemoryConfig()
|
||||
memory = AsyncMemory(config)
|
||||
|
||||
await memory._update_memory("mem-1", "I love swimming", {"I love swimming": [0.1, 0.2, 0.3]})
|
||||
|
||||
call_args = mock_vector_store.update.call_args
|
||||
payload = call_args.kwargs.get("payload") or call_args[1].get("payload")
|
||||
assert payload["category"] == "hobbies"
|
||||
assert payload["source"] == "chat"
|
||||
assert payload["data"] == "I love swimming"
|
||||
assert payload["user_id"] == "user_1"
|
||||
|
||||
@@ -164,68 +164,11 @@ class TestMarkAliased:
|
||||
assert not setup_module.is_aliased("oss-uuid", "other@example.com")
|
||||
|
||||
|
||||
# ─── oss_used marker ─────────────────────────────────────────────────────────
|
||||
|
||||
|
||||
class TestOssUsedMarker:
|
||||
def test_mark_writes_marker_preserving_fields(self, tmp_mem0_dir):
|
||||
import mem0.memory.setup as setup_module
|
||||
|
||||
_write_config(
|
||||
tmp_mem0_dir,
|
||||
{
|
||||
"user_id": "oss-uuid",
|
||||
"telemetry": {"anonymous_id": "cli-anon", "aliased_pairs": ["pair-marker"]},
|
||||
},
|
||||
)
|
||||
setup_module.mark_oss_used()
|
||||
config = json.loads((tmp_mem0_dir / "config.json").read_text())
|
||||
assert config["user_id"] == "oss-uuid"
|
||||
assert config["telemetry"]["anonymous_id"] == "cli-anon"
|
||||
assert config["telemetry"]["aliased_pairs"] == ["pair-marker"]
|
||||
assert config["telemetry"]["oss_used_at"]
|
||||
assert setup_module.is_oss_used()
|
||||
|
||||
def test_mark_is_idempotent(self, tmp_mem0_dir):
|
||||
import mem0.memory.setup as setup_module
|
||||
|
||||
setup_module.mark_oss_used()
|
||||
first = json.loads((tmp_mem0_dir / "config.json").read_text())["telemetry"]["oss_used_at"]
|
||||
setup_module.mark_oss_used()
|
||||
second = json.loads((tmp_mem0_dir / "config.json").read_text())["telemetry"]["oss_used_at"]
|
||||
assert first == second
|
||||
|
||||
def test_is_oss_used_false_when_no_config(self, tmp_mem0_dir):
|
||||
import mem0.memory.setup as setup_module
|
||||
|
||||
assert not setup_module.is_oss_used()
|
||||
|
||||
def test_is_oss_used_false_without_marker(self, tmp_mem0_dir):
|
||||
import mem0.memory.setup as setup_module
|
||||
|
||||
_write_config(tmp_mem0_dir, {"user_id": "oss-uuid", "telemetry": {"anonymous_id": "cli-anon"}})
|
||||
assert not setup_module.is_oss_used()
|
||||
|
||||
def test_is_oss_used_false_on_malformed_json(self, tmp_mem0_dir):
|
||||
import mem0.memory.setup as setup_module
|
||||
|
||||
(tmp_mem0_dir / "config.json").write_text("{not json")
|
||||
assert not setup_module.is_oss_used()
|
||||
|
||||
def test_mark_does_not_raise_when_config_path_unwritable(self, tmp_mem0_dir):
|
||||
import mem0.memory.setup as setup_module
|
||||
|
||||
(tmp_mem0_dir / "config.json").mkdir() # open() on a directory fails
|
||||
setup_module.mark_oss_used() # must not raise
|
||||
assert not setup_module.is_oss_used()
|
||||
|
||||
|
||||
# ─── capture_identify ────────────────────────────────────────────────────────
|
||||
|
||||
|
||||
class TestCaptureIdentify:
|
||||
def test_fires_identify_with_anon_distinct_id(self):
|
||||
import mem0
|
||||
import mem0.memory.telemetry as telemetry_module
|
||||
|
||||
with patch.object(telemetry_module, "MEM0_TELEMETRY", True):
|
||||
@@ -238,7 +181,6 @@ class TestCaptureIdentify:
|
||||
assert kwargs["distinct_id"] == "user@example.com"
|
||||
assert kwargs["event"] == "$identify"
|
||||
assert kwargs["properties"]["$anon_distinct_id"] == "anon-123"
|
||||
assert kwargs["properties"]["client_version"] == mem0.__version__
|
||||
|
||||
def test_skips_when_anon_equals_email(self):
|
||||
import mem0.memory.telemetry as telemetry_module
|
||||
@@ -288,7 +230,8 @@ class TestCaptureIdentify:
|
||||
|
||||
class TestMaybeAliasAnonToEmail:
|
||||
"""Test the alias helper in isolation by mocking out the config readers
|
||||
and the telemetry client, so no real ~/.mem0/config.json is touched."""
|
||||
and the telemetry client, since module-level setup_config() side effects
|
||||
make end-to-end fixturing awkward."""
|
||||
|
||||
def test_fires_identify_for_oss_uuid(self):
|
||||
from mem0.client import main as client_main
|
||||
@@ -299,7 +242,6 @@ class TestMaybeAliasAnonToEmail:
|
||||
"read_anon_ids",
|
||||
return_value={"oss": "oss-uuid", "cli": None, "aliased_pairs": []},
|
||||
),
|
||||
patch.object(client_main, "is_oss_used", return_value=True),
|
||||
patch.object(client_main, "is_aliased", return_value=False),
|
||||
patch.object(client_main, "mark_aliased") as mark,
|
||||
patch.object(client_main, "client_telemetry") as telemetry,
|
||||
@@ -310,7 +252,6 @@ class TestMaybeAliasAnonToEmail:
|
||||
mark.assert_called_once_with("oss-uuid", "user@example.com")
|
||||
|
||||
def test_fires_identify_for_cli_anon(self):
|
||||
"""The CLI anon id is presence-based: it stitches even without the oss_used marker."""
|
||||
from mem0.client import main as client_main
|
||||
|
||||
with (
|
||||
@@ -319,7 +260,6 @@ class TestMaybeAliasAnonToEmail:
|
||||
"read_anon_ids",
|
||||
return_value={"oss": None, "cli": "cli-anon-xyz", "aliased_pairs": []},
|
||||
),
|
||||
patch.object(client_main, "is_oss_used", return_value=False),
|
||||
patch.object(client_main, "is_aliased", return_value=False),
|
||||
patch.object(client_main, "mark_aliased"),
|
||||
patch.object(client_main, "client_telemetry") as telemetry,
|
||||
@@ -337,7 +277,6 @@ class TestMaybeAliasAnonToEmail:
|
||||
"read_anon_ids",
|
||||
return_value={"oss": "oss-uuid", "cli": "cli-anon", "aliased_pairs": []},
|
||||
),
|
||||
patch.object(client_main, "is_oss_used", return_value=True),
|
||||
patch.object(client_main, "is_aliased", return_value=False),
|
||||
patch.object(client_main, "mark_aliased"),
|
||||
patch.object(client_main, "client_telemetry") as telemetry,
|
||||
@@ -349,26 +288,6 @@ class TestMaybeAliasAnonToEmail:
|
||||
assert ("oss-uuid", "user@example.com") in calls
|
||||
assert ("cli-anon", "user@example.com") in calls
|
||||
|
||||
def test_oss_id_requires_oss_used_marker(self):
|
||||
"""Without proof of real OSS usage, the oss user_id must never be
|
||||
stitched (it may have been minted by an old platform-only client)."""
|
||||
from mem0.client import main as client_main
|
||||
|
||||
with (
|
||||
patch.object(
|
||||
client_main,
|
||||
"read_anon_ids",
|
||||
return_value={"oss": "oss-uuid", "cli": "cli-anon", "aliased_pairs": []},
|
||||
),
|
||||
patch.object(client_main, "is_oss_used", return_value=False),
|
||||
patch.object(client_main, "is_aliased", return_value=False),
|
||||
patch.object(client_main, "mark_aliased"),
|
||||
patch.object(client_main, "client_telemetry") as telemetry,
|
||||
):
|
||||
telemetry.capture_identify.return_value = True
|
||||
client_main._maybe_alias_anon_to_email("user@example.com")
|
||||
telemetry.capture_identify.assert_called_once_with("cli-anon", "user@example.com")
|
||||
|
||||
def test_skips_when_pair_already_aliased(self):
|
||||
from mem0.client import main as client_main
|
||||
|
||||
@@ -378,7 +297,6 @@ class TestMaybeAliasAnonToEmail:
|
||||
"read_anon_ids",
|
||||
return_value={"oss": "oss-uuid", "cli": None, "aliased_pairs": ["pair-marker"]},
|
||||
),
|
||||
patch.object(client_main, "is_oss_used", return_value=True),
|
||||
patch.object(client_main, "is_aliased", return_value=True),
|
||||
patch.object(client_main, "mark_aliased") as mark,
|
||||
patch.object(client_main, "client_telemetry") as telemetry,
|
||||
@@ -424,7 +342,6 @@ class TestMaybeAliasAnonToEmail:
|
||||
"read_anon_ids",
|
||||
return_value={"oss": "oss-uuid", "cli": None, "aliased_pairs": []},
|
||||
),
|
||||
patch.object(client_main, "is_oss_used", return_value=True),
|
||||
patch.object(client_main, "is_aliased", return_value=False),
|
||||
patch.object(client_main, "mark_aliased") as mark,
|
||||
patch.object(client_main, "client_telemetry", mock_telemetry),
|
||||
@@ -442,7 +359,6 @@ class TestMaybeAliasAnonToEmail:
|
||||
"read_anon_ids",
|
||||
return_value={"oss": "user@example.com", "cli": None, "aliased_pairs": []},
|
||||
),
|
||||
patch.object(client_main, "is_oss_used", return_value=True),
|
||||
patch.object(client_main, "is_aliased", return_value=False),
|
||||
patch.object(client_main, "mark_aliased"),
|
||||
patch.object(client_main, "client_telemetry") as telemetry,
|
||||
@@ -470,12 +386,8 @@ class TestEndToEndIdempotency:
|
||||
calls fire $identify exactly once thanks to the persisted pair marker."""
|
||||
|
||||
def test_second_call_is_noop_after_pair_marker_persisted(self, tmp_mem0_dir):
|
||||
# Pre-populate config with an OSS user_id plus the oss_used_at marker
|
||||
# (without the marker the oss id is no longer a stitch candidate).
|
||||
_write_config(
|
||||
tmp_mem0_dir,
|
||||
{"user_id": "oss-uuid", "telemetry": {"oss_used_at": "2026-01-01T00:00:00+00:00"}},
|
||||
)
|
||||
# Pre-populate config with an OSS user_id only.
|
||||
_write_config(tmp_mem0_dir, {"user_id": "oss-uuid"})
|
||||
# Reload setup so it uses the tempdir, then reload client.main so it
|
||||
# picks up the freshly-loaded read_anon_ids/mark_aliased bindings.
|
||||
import mem0.memory.setup as setup_module
|
||||
@@ -497,112 +409,3 @@ class TestEndToEndIdempotency:
|
||||
|
||||
config = json.loads((tmp_mem0_dir / "config.json").read_text())
|
||||
assert len(config["telemetry"]["aliased_pairs"]) == 1
|
||||
|
||||
def test_oss_then_platform_stitches_exactly_once(self, tmp_mem0_dir):
|
||||
"""Genuine OSS usage (setup_config + mark_oss_used, as Memory.__init__
|
||||
does) followed by platform inits stitches the minted id exactly once."""
|
||||
import mem0.memory.setup as setup_module
|
||||
|
||||
setup_module.setup_config()
|
||||
setup_module.mark_oss_used()
|
||||
oss_id = json.loads((tmp_mem0_dir / "config.json").read_text())["user_id"]
|
||||
|
||||
from mem0.client import main as client_main
|
||||
|
||||
importlib.reload(client_main)
|
||||
|
||||
with patch.object(client_main, "client_telemetry") as telemetry:
|
||||
telemetry.capture_identify.return_value = True
|
||||
client_main._maybe_alias_anon_to_email("user@example.com")
|
||||
telemetry.capture_identify.assert_called_once_with(oss_id, "user@example.com")
|
||||
client_main._maybe_alias_anon_to_email("user@example.com")
|
||||
assert telemetry.capture_identify.call_count == 1
|
||||
|
||||
config = json.loads((tmp_mem0_dir / "config.json").read_text())
|
||||
assert len(config["telemetry"]["aliased_pairs"]) == 1
|
||||
assert config["telemetry"]["oss_used_at"]
|
||||
|
||||
|
||||
# ─── Platform-only init must not mint or stitch ──────────────────────────────
|
||||
|
||||
|
||||
class TestPlatformOnlyDoesNotMint:
|
||||
"""Regression for the bug where importing the client minted an anon id at
|
||||
import time and then stitched it on MemoryClient init, merging an
|
||||
event-less anon person into every platform user."""
|
||||
|
||||
def test_no_config_created_and_no_identify(self, tmp_mem0_dir):
|
||||
from mem0.client import main as client_main
|
||||
|
||||
# Re-execute the client module: it must not create config.json.
|
||||
importlib.reload(client_main)
|
||||
assert not (tmp_mem0_dir / "config.json").exists()
|
||||
|
||||
with patch.object(client_main, "client_telemetry") as telemetry:
|
||||
telemetry.capture_identify.return_value = True
|
||||
client_main._maybe_alias_anon_to_email("user@example.com")
|
||||
telemetry.capture_identify.assert_not_called()
|
||||
|
||||
assert not (tmp_mem0_dir / "config.json").exists()
|
||||
|
||||
|
||||
# ─── Lazy minting from OSS Memory init ───────────────────────────────────────
|
||||
|
||||
|
||||
class TestLazyOssMinting:
|
||||
"""OSS Memory/AsyncMemory init mints the anon id and records genuine OSS
|
||||
usage; nothing happens at import time or with telemetry disabled."""
|
||||
|
||||
def test_memory_init_mints_and_marks(self, tmp_path):
|
||||
import mem0.memory.main as memory_main
|
||||
|
||||
with (
|
||||
patch.object(memory_main, "EmbedderFactory"),
|
||||
patch.object(memory_main, "VectorStoreFactory"),
|
||||
patch.object(memory_main, "LlmFactory"),
|
||||
patch.object(memory_main, "SQLiteManager"),
|
||||
patch.object(memory_main, "capture_event"),
|
||||
patch.object(memory_main, "mem0_dir", str(tmp_path)),
|
||||
patch.object(memory_main, "setup_config") as setup,
|
||||
patch.object(memory_main, "mark_oss_used") as mark,
|
||||
patch.object(memory_main, "MEM0_TELEMETRY", True),
|
||||
):
|
||||
memory_main.Memory()
|
||||
setup.assert_called_once()
|
||||
mark.assert_called_once()
|
||||
|
||||
def test_memory_init_skips_minting_when_telemetry_disabled(self, tmp_path):
|
||||
import mem0.memory.main as memory_main
|
||||
|
||||
with (
|
||||
patch.object(memory_main, "EmbedderFactory"),
|
||||
patch.object(memory_main, "VectorStoreFactory"),
|
||||
patch.object(memory_main, "LlmFactory"),
|
||||
patch.object(memory_main, "SQLiteManager"),
|
||||
patch.object(memory_main, "capture_event"),
|
||||
patch.object(memory_main, "mem0_dir", str(tmp_path)),
|
||||
patch.object(memory_main, "setup_config") as setup,
|
||||
patch.object(memory_main, "mark_oss_used") as mark,
|
||||
patch.object(memory_main, "MEM0_TELEMETRY", False),
|
||||
):
|
||||
memory_main.Memory()
|
||||
setup.assert_not_called()
|
||||
mark.assert_not_called()
|
||||
|
||||
def test_async_memory_init_mints_and_marks(self, tmp_path):
|
||||
import mem0.memory.main as memory_main
|
||||
|
||||
with (
|
||||
patch.object(memory_main, "EmbedderFactory"),
|
||||
patch.object(memory_main, "VectorStoreFactory"),
|
||||
patch.object(memory_main, "LlmFactory"),
|
||||
patch.object(memory_main, "SQLiteManager"),
|
||||
patch.object(memory_main, "capture_event"),
|
||||
patch.object(memory_main, "mem0_dir", str(tmp_path)),
|
||||
patch.object(memory_main, "setup_config") as setup,
|
||||
patch.object(memory_main, "mark_oss_used") as mark,
|
||||
patch.object(memory_main, "MEM0_TELEMETRY", True),
|
||||
):
|
||||
memory_main.AsyncMemory()
|
||||
setup.assert_called_once()
|
||||
mark.assert_called_once()
|
||||
|
||||
@@ -154,6 +154,16 @@ def test_get_vector(chromadb_instance):
|
||||
assert result.payload == {"name": "vector1"}
|
||||
|
||||
|
||||
def test_get_missing_vector_returns_none(chromadb_instance):
|
||||
# Chroma returns empty lists for an unknown id; get() must return None
|
||||
# rather than raising IndexError (parity with qdrant/pgvector/faiss).
|
||||
chromadb_instance.collection.get.return_value = {"ids": [], "metadatas": []}
|
||||
|
||||
result = chromadb_instance.get(vector_id="does-not-exist")
|
||||
|
||||
assert result is None
|
||||
|
||||
|
||||
def test_list_vectors(chromadb_instance):
|
||||
mock_result = {
|
||||
"ids": [["id1", "id2"]],
|
||||
|
||||
@@ -189,11 +189,17 @@ class TestMilvusDB:
|
||||
]
|
||||
|
||||
result = milvus_db.get(vector_id)
|
||||
|
||||
|
||||
assert result.id == vector_id
|
||||
assert result.payload == {"user_id": "alice"}
|
||||
assert result.score is None
|
||||
|
||||
def test_get_missing_returns_none(self, milvus_db, mock_milvus_client):
|
||||
"""get() must return None (not raise IndexError) for an unknown id."""
|
||||
mock_milvus_client.get.return_value = []
|
||||
|
||||
assert milvus_db.get("missing") is None
|
||||
|
||||
def test_list_with_filters(self, milvus_db, mock_milvus_client):
|
||||
"""Test listing memories with filters."""
|
||||
mock_milvus_client.query.return_value = [
|
||||
|
||||
@@ -71,3 +71,45 @@ def test_update_with_vector_includes_embedding():
|
||||
)
|
||||
expected_bytes = np.array(vector, dtype=np.float32).tobytes()
|
||||
assert data_dict["embedding"] == expected_bytes
|
||||
|
||||
|
||||
def test_search_with_none_filters_does_not_crash():
|
||||
"""search() with the base-class default filters=None must run an unfiltered
|
||||
query, not raise. Regression: filters.items() on None raised AttributeError
|
||||
and reduce() over an empty list raised TypeError. keyword_search() in the
|
||||
same file already guards this; search() did not."""
|
||||
db, mock_index = _make_redis_db()
|
||||
mock_index.query.return_value = []
|
||||
|
||||
assert db.search("query", [0.1, 0.2, 0.3, 0.4], top_k=5, filters=None) == []
|
||||
mock_index.query.assert_called_once()
|
||||
|
||||
|
||||
def test_search_with_empty_or_all_none_filters_does_not_crash():
|
||||
db, mock_index = _make_redis_db()
|
||||
mock_index.query.return_value = []
|
||||
|
||||
assert db.search("query", [0.1, 0.2, 0.3, 0.4], filters={}) == []
|
||||
assert db.search("query", [0.1, 0.2, 0.3, 0.4], filters={"user_id": None}) == []
|
||||
|
||||
|
||||
def test_list_with_none_filters_matches_all():
|
||||
"""list() with no filters must issue a match-all ('*') query, not raise."""
|
||||
db, mock_index = _make_redis_db()
|
||||
mock_index.search.return_value = MagicMock(docs=[])
|
||||
|
||||
db.list(filters=None)
|
||||
|
||||
query = mock_index.search.call_args[0][0]
|
||||
assert query.query_string() == "*"
|
||||
|
||||
|
||||
def test_list_with_filter_builds_query():
|
||||
"""A real filter is still translated into a tag query (no regression)."""
|
||||
db, mock_index = _make_redis_db()
|
||||
mock_index.search.return_value = MagicMock(docs=[])
|
||||
|
||||
db.list(filters={"user_id": "alice"})
|
||||
|
||||
query = mock_index.search.call_args[0][0]
|
||||
assert query.query_string() == "@user_id:{alice}"
|
||||
|
||||
@@ -111,6 +111,13 @@ def test_get_vector(supabase_instance, mock_collection):
|
||||
assert result.payload == {"name": "vector1"}
|
||||
|
||||
|
||||
def test_get_missing_returns_none(supabase_instance, mock_collection):
|
||||
# An unknown id yields an empty fetch; get() must return None (not []).
|
||||
mock_collection.fetch.return_value = []
|
||||
|
||||
assert supabase_instance.get(vector_id="missing") is None
|
||||
|
||||
|
||||
def test_list_vectors(supabase_instance, mock_collection):
|
||||
mock_query_results = [("id1", 0.9, {}), ("id2", 0.8, {})]
|
||||
mock_fetch_results = [("id1", [0.1, 0.2, 0.3], {"name": "vector1"}), ("id2", [0.4, 0.5, 0.6], {"name": "vector2"})]
|
||||
|
||||
@@ -4,9 +4,7 @@ import uuid
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
import dotenv
|
||||
import httpx
|
||||
import weaviate
|
||||
from weaviate.exceptions import UnexpectedStatusCodeException
|
||||
|
||||
from mem0.vector_stores.weaviate import Weaviate
|
||||
|
||||
@@ -112,11 +110,13 @@ class TestWeaviateDB(unittest.TestCase):
|
||||
assert result.payload == expected_payload
|
||||
|
||||
def test_get_not_found(self):
|
||||
mock_response = httpx.Response(status_code=404, json={"error": "Not found"})
|
||||
# fetch_object_by_id returns None for an unknown id; get() must return
|
||||
# None rather than raising AttributeError on response.properties.
|
||||
self.client_mock.collections.get.return_value.query.fetch_object_by_id.return_value = None
|
||||
|
||||
self.client_mock.collections.get.return_value.data.get_by_id.side_effect = UnexpectedStatusCodeException(
|
||||
"Not found", mock_response
|
||||
)
|
||||
result = self.weaviate_db.get(vector_id=str(uuid.uuid4()))
|
||||
|
||||
assert result is None
|
||||
|
||||
def test_search(self):
|
||||
mock_objects = [{"uuid": "id1", "properties": {"key1": "value1"}, "metadata": {"distance": 0.2}}]
|
||||
|
||||
Reference in New Issue
Block a user