mirror of
https://github.com/supermemoryai/supermemory.git
synced 2026-08-22 06:53:57 +00:00
feat: openai js and python sdk utilities (#389)
Some checks are pending
Publish AI SDK / publish (push) Waiting to run
Some checks are pending
Publish AI SDK / publish (push) Waiting to run
needs testing
This commit is contained in:
parent
1d5298e05e
commit
3a0e264b7e
25 changed files with 4709 additions and 83 deletions
2
.github/workflows/publish-ai-sdk.yml
vendored
2
.github/workflows/publish-ai-sdk.yml
vendored
|
|
@ -2,6 +2,8 @@ name: Publish AI SDK
|
|||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
paths:
|
||||
- "packages/ai-sdk/package.json"
|
||||
|
||||
|
|
|
|||
3
.gitignore
vendored
3
.gitignore
vendored
|
|
@ -38,3 +38,6 @@ yarn-error.log*
|
|||
# Misc
|
||||
.DS_Store
|
||||
*.pem
|
||||
|
||||
.venv
|
||||
__pycache__
|
||||
103
bun.lock
103
bun.lock
|
|
@ -136,18 +136,18 @@
|
|||
},
|
||||
"packages/ai-sdk": {
|
||||
"name": "@supermemory/ai-sdk",
|
||||
"version": "0.0.1",
|
||||
"version": "1.0.5",
|
||||
"dependencies": {
|
||||
"@ai-sdk/openai": "^2.0.15",
|
||||
"@ai-sdk/openai": "^2.0.22",
|
||||
"@ai-sdk/provider": "^2.0.0",
|
||||
"ai": "^5.0.17",
|
||||
"supermemory": "^3.0.0-alpha.22",
|
||||
"zod": "^4.0.17",
|
||||
"ai": "^5.0.26",
|
||||
"supermemory": "^3.0.0-alpha.26",
|
||||
"zod": "^4.1.4",
|
||||
},
|
||||
"devDependencies": {
|
||||
"@total-typescript/tsconfig": "^1.0.4",
|
||||
"@types/bun": "^1.2.20",
|
||||
"tsdown": "^0.14.1",
|
||||
"@types/bun": "^1.2.21",
|
||||
"tsdown": "^0.14.2",
|
||||
"typescript": "^5.9.2",
|
||||
"vitest": "^3.2.4",
|
||||
},
|
||||
|
|
@ -166,6 +166,23 @@
|
|||
"ai-gateway-provider": "^0.0.11",
|
||||
},
|
||||
},
|
||||
"packages/openai-sdk-ts": {
|
||||
"name": "@supermemory/openai-sdk",
|
||||
"version": "1.0.0",
|
||||
"dependencies": {
|
||||
"openai": "^4.63.0",
|
||||
"supermemory": "^3.0.0-alpha.22",
|
||||
"zod": "^4.0.17",
|
||||
},
|
||||
"devDependencies": {
|
||||
"@total-typescript/tsconfig": "^1.0.4",
|
||||
"@types/bun": "^1.2.20",
|
||||
"dotenv": "^16.4.7",
|
||||
"tsdown": "^0.14.1",
|
||||
"typescript": "^5.9.2",
|
||||
"vitest": "^3.2.4",
|
||||
},
|
||||
},
|
||||
"packages/ui": {
|
||||
"name": "@repo/ui",
|
||||
"version": "0.0.0",
|
||||
|
|
@ -842,9 +859,9 @@
|
|||
|
||||
"@opentelemetry/sql-common": ["@opentelemetry/sql-common@0.41.0", "", { "dependencies": { "@opentelemetry/core": "^2.0.0" }, "peerDependencies": { "@opentelemetry/api": "^1.1.0" } }, "sha512-pmzXctVbEERbqSfiAgdes9Y63xjoOyXcD7B6IXBkVb+vbM7M9U98mn33nGXxPf4dfYR0M+vhcKRZmbSJ7HfqFA=="],
|
||||
|
||||
"@oxc-project/runtime": ["@oxc-project/runtime@0.82.2", "", {}, "sha512-cYxcj5CPn/vo5QSpCZcYzBiLidU5+GlFSqIeNaMgBDtcVRBsBJHZg3pHw999W6nHamFQ1EHuPPByB26tjaJiJw=="],
|
||||
"@oxc-project/runtime": ["@oxc-project/runtime@0.82.3", "", {}, "sha512-LNh5GlJvYHAnMurO+EyA8jJwN1rki7l3PSHuosDh2I7h00T6/u9rCkUjg/SvPmT1CZzvhuW0y+gf7jcqUy/Usg=="],
|
||||
|
||||
"@oxc-project/types": ["@oxc-project/types@0.82.2", "", {}, "sha512-WMGSwd9FsNBs/WfqIOH0h3k1LBdjZJQGYjGnC+vla/fh6HUsu5HzGPerRljiq1hgMQ6gs031YJR12VyP57b/hQ=="],
|
||||
"@oxc-project/types": ["@oxc-project/types@0.82.3", "", {}, "sha512-6nCUxBnGX0c6qfZW5MaF6/fmu5dHJDMiMPaioKHKs5mi5+8/FHQ7WGjgQIz1zxpmceMYfdIXkOaLYE+ejbuOtA=="],
|
||||
|
||||
"@peculiar/asn1-android": ["@peculiar/asn1-android@2.4.0", "", { "dependencies": { "@peculiar/asn1-schema": "^2.4.0", "asn1js": "^3.0.6", "tslib": "^2.8.1" } }, "sha512-YFueREq97CLslZZBI8dKzis7jMfEHSLxM+nr0Zdx1POiXFLjqqwoY5s0F1UimdBiEw/iKlHey2m56MRDv7Jtyg=="],
|
||||
|
||||
|
|
@ -986,35 +1003,35 @@
|
|||
|
||||
"@repo/web": ["@repo/web@workspace:apps/web"],
|
||||
|
||||
"@rolldown/binding-android-arm64": ["@rolldown/binding-android-arm64@1.0.0-beta.33", "", { "os": "android", "cpu": "arm64" }, "sha512-xhDQXKftRkEULIxCddrKMR8y0YO/Y+6BKk/XrQP2B29YjV2wr8DByoEz+AHX9BfLHb2srfpdN46UquBW2QXWpQ=="],
|
||||
"@rolldown/binding-android-arm64": ["@rolldown/binding-android-arm64@1.0.0-beta.34", "", { "os": "android", "cpu": "arm64" }, "sha512-jf5GNe5jP3Sr1Tih0WKvg2bzvh5T/1TA0fn1u32xSH7ca/p5t+/QRr4VRFCV/na5vjwKEhwWrChsL2AWlY+eoA=="],
|
||||
|
||||
"@rolldown/binding-darwin-arm64": ["@rolldown/binding-darwin-arm64@1.0.0-beta.33", "", { "os": "darwin", "cpu": "arm64" }, "sha512-7lhhY08v5ZtRq8JJQaJ49fnJombAPnqllKKCDLU/UvaqNAOEyTGC8J1WVOLC4EA4zbXO5U3CCRgVGyAFNH2VtQ=="],
|
||||
"@rolldown/binding-darwin-arm64": ["@rolldown/binding-darwin-arm64@1.0.0-beta.34", "", { "os": "darwin", "cpu": "arm64" }, "sha512-2F/TqH4QuJQ34tgWxqBjFL3XV1gMzeQgUO8YRtCPGBSP0GhxtoFzsp7KqmQEothsxztlv+KhhT9Dbg3HHwHViQ=="],
|
||||
|
||||
"@rolldown/binding-darwin-x64": ["@rolldown/binding-darwin-x64@1.0.0-beta.33", "", { "os": "darwin", "cpu": "x64" }, "sha512-U2iGjcDV7NWyYyhap8YuY0nwrLX6TvX/9i7gBtdEMPm9z3wIUVGNMVdGlA43uqg7xDpRGpEqGnxbeDgiEwYdnA=="],
|
||||
"@rolldown/binding-darwin-x64": ["@rolldown/binding-darwin-x64@1.0.0-beta.34", "", { "os": "darwin", "cpu": "x64" }, "sha512-E1QuFslgLWbHQ8Qli/AqUKdfg0pockQPwRxVbhNQ74SciZEZpzLaujkdmOLSccMlSXDfFCF8RPnMoRAzQ9JV8Q=="],
|
||||
|
||||
"@rolldown/binding-freebsd-x64": ["@rolldown/binding-freebsd-x64@1.0.0-beta.33", "", { "os": "freebsd", "cpu": "x64" }, "sha512-gd6ASromVHFLlzrjJWMG5CXHkS7/36DEZ8HhvGt2NN8eZALCIuyEx8HMMLqvKA7z4EAztVkdToVrdxpGMsKZxw=="],
|
||||
"@rolldown/binding-freebsd-x64": ["@rolldown/binding-freebsd-x64@1.0.0-beta.34", "", { "os": "freebsd", "cpu": "x64" }, "sha512-VS8VInNCwnkpI9WeQaWu3kVBq9ty6g7KrHdLxYMzeqz24+w9hg712TcWdqzdY6sn+24lUoMD9jTZrZ/qfVpk0g=="],
|
||||
|
||||
"@rolldown/binding-linux-arm-gnueabihf": ["@rolldown/binding-linux-arm-gnueabihf@1.0.0-beta.33", "", { "os": "linux", "cpu": "arm" }, "sha512-xmeLfkfGthuynO1EpCdyTVr0r4G+wqvnKCuyR6rXOet+hLrq5HNAC2XtP/jU2TB4Bc6aiLYxl868B8CGtFDhcw=="],
|
||||
"@rolldown/binding-linux-arm-gnueabihf": ["@rolldown/binding-linux-arm-gnueabihf@1.0.0-beta.34", "", { "os": "linux", "cpu": "arm" }, "sha512-4St4emjcnULnxJYb/5ZDrH/kK/j6PcUgc3eAqH5STmTrcF+I9m/X2xvSF2a2bWv1DOQhxBewThu0KkwGHdgu5w=="],
|
||||
|
||||
"@rolldown/binding-linux-arm64-gnu": ["@rolldown/binding-linux-arm64-gnu@1.0.0-beta.33", "", { "os": "linux", "cpu": "arm64" }, "sha512-cHGp8yfHL4pes6uaLbO5L58ceFkUK4efd8iE86jClD1QPPDLKiqEXJCFYeuK3OfODuF5EBOmf0SlcUZNEYGdmw=="],
|
||||
"@rolldown/binding-linux-arm64-gnu": ["@rolldown/binding-linux-arm64-gnu@1.0.0-beta.34", "", { "os": "linux", "cpu": "arm64" }, "sha512-a737FTqhFUoWfnebS2SnQ2BS50p0JdukdkUBwy2J06j4hZ6Eej0zEB8vTfAqoCjn8BQKkXBy+3Sx0IRkgwz1gA=="],
|
||||
|
||||
"@rolldown/binding-linux-arm64-musl": ["@rolldown/binding-linux-arm64-musl@1.0.0-beta.33", "", { "os": "linux", "cpu": "arm64" }, "sha512-wZ1t7JAvVeFgskH1L9y7c47ITitPytpL0s8FmAT8pVfXcaTmS58ZyoXT+y6cz8uCkQnETjrX3YezTGI18u3ecg=="],
|
||||
"@rolldown/binding-linux-arm64-musl": ["@rolldown/binding-linux-arm64-musl@1.0.0-beta.34", "", { "os": "linux", "cpu": "arm64" }, "sha512-NH+FeQWKyuw0k+PbXqpFWNfvD8RPvfJk766B/njdaWz4TmiEcSB0Nb6guNw1rBpM1FmltQYb3fFnTumtC6pRfA=="],
|
||||
|
||||
"@rolldown/binding-linux-x64-gnu": ["@rolldown/binding-linux-x64-gnu@1.0.0-beta.33", "", { "os": "linux", "cpu": "x64" }, "sha512-cDndWo3VEYbm7yeujOV6Ie2XHz0K8YX/R/vbNmMo03m1QwtBKKvbYNSyJb3B9+8igltDjd8zNM9mpiNNrq/ekQ=="],
|
||||
"@rolldown/binding-linux-x64-gnu": ["@rolldown/binding-linux-x64-gnu@1.0.0-beta.34", "", { "os": "linux", "cpu": "x64" }, "sha512-Q3RSCivp8pNadYK8ke3hLnQk08BkpZX9BmMjgwae2FWzdxhxxUiUzd9By7kneUL0vRQ4uRnhD9VkFQ+Haeqdvw=="],
|
||||
|
||||
"@rolldown/binding-linux-x64-musl": ["@rolldown/binding-linux-x64-musl@1.0.0-beta.33", "", { "os": "linux", "cpu": "x64" }, "sha512-bl7uzi6es/l6LT++NZcBpiX43ldLyKXCPwEZGY1rZJ99HQ7m1g3KxWwYCcGxtKjlb2ExVvDZicF6k+96vxOJKg=="],
|
||||
"@rolldown/binding-linux-x64-musl": ["@rolldown/binding-linux-x64-musl@1.0.0-beta.34", "", { "os": "linux", "cpu": "x64" }, "sha512-wDd/HrNcVoBhWWBUW3evJHoo7GJE/RofssBy3Dsiip05YUBmokQVrYAyrboOY4dzs/lJ7HYeBtWQ9hj8wlyF0A=="],
|
||||
|
||||
"@rolldown/binding-openharmony-arm64": ["@rolldown/binding-openharmony-arm64@1.0.0-beta.33", "", { "os": "none", "cpu": "arm64" }, "sha512-TrgzQanpLgcmmzolCbYA9BPZgF1gYxkIGZhU/HROnJPsq67gcyaYw/JBLioqQLjIwMipETkn25YY799D2OZzJA=="],
|
||||
"@rolldown/binding-openharmony-arm64": ["@rolldown/binding-openharmony-arm64@1.0.0-beta.34", "", { "os": "none", "cpu": "arm64" }, "sha512-dH3FTEV6KTNWpYSgjSXZzeX7vLty9oBYn6R3laEdhwZftQwq030LKL+5wyQdlbX5pnbh4h127hpv3Hl1+sj8dg=="],
|
||||
|
||||
"@rolldown/binding-wasm32-wasi": ["@rolldown/binding-wasm32-wasi@1.0.0-beta.33", "", { "dependencies": { "@napi-rs/wasm-runtime": "^1.0.3" }, "cpu": "none" }, "sha512-z0LltdUfvoKak9SuaLz/M9AVSg+RTOZjFksbZXzC6Svl1odyW4ai21VHhZy3m2Faeeb/rl/9efVLayj+qYEGxw=="],
|
||||
"@rolldown/binding-wasm32-wasi": ["@rolldown/binding-wasm32-wasi@1.0.0-beta.34", "", { "dependencies": { "@napi-rs/wasm-runtime": "^1.0.3" }, "cpu": "none" }, "sha512-y5BUf+QtO0JsIDKA51FcGwvhJmv89BYjUl8AmN7jqD6k/eU55mH6RJYnxwCsODq5m7KSSTigVb6O7/GqB8wbPw=="],
|
||||
|
||||
"@rolldown/binding-win32-arm64-msvc": ["@rolldown/binding-win32-arm64-msvc@1.0.0-beta.33", "", { "os": "win32", "cpu": "arm64" }, "sha512-CpvOHyqDNOYx9riD4giyXQDIu72bWRU2Dwt1xFSPlBudk6NumK0OJl6Ch+LPnkp5podQHcQg0mMauAXPVKct7g=="],
|
||||
"@rolldown/binding-win32-arm64-msvc": ["@rolldown/binding-win32-arm64-msvc@1.0.0-beta.34", "", { "os": "win32", "cpu": "arm64" }, "sha512-ga5hFhdTwpaNxEiuxZHWnD3ed0GBAzbgzS5tRHpe0ObptxM1a9Xrq6TVfNQirBLwb5Y7T/FJmJi3pmdLy95ljg=="],
|
||||
|
||||
"@rolldown/binding-win32-ia32-msvc": ["@rolldown/binding-win32-ia32-msvc@1.0.0-beta.33", "", { "os": "win32", "cpu": "ia32" }, "sha512-/tNTvZTWHz6HiVuwpR3zR0kGIyCNb+/tFhnJmti+Aw2fAXs3l7Aj0DcXd0646eFKMX8L2w5hOW9H08FXTUkN0g=="],
|
||||
"@rolldown/binding-win32-ia32-msvc": ["@rolldown/binding-win32-ia32-msvc@1.0.0-beta.34", "", { "os": "win32", "cpu": "ia32" }, "sha512-4/MBp9T9eRnZskxWr8EXD/xHvLhdjWaeX/qY9LPRG1JdCGV3DphkLTy5AWwIQ5jhAy2ZNJR5z2fYRlpWU0sIyQ=="],
|
||||
|
||||
"@rolldown/binding-win32-x64-msvc": ["@rolldown/binding-win32-x64-msvc@1.0.0-beta.33", "", { "os": "win32", "cpu": "x64" }, "sha512-Bb2qK3z7g2mf4zaKRvkohHzweaP1lLbaoBmXZFkY6jJWMm0Z8Pfnh8cOoRlH1IVM1Ufbo8ZZ1WXp1LbOpRMtXw=="],
|
||||
"@rolldown/binding-win32-x64-msvc": ["@rolldown/binding-win32-x64-msvc@1.0.0-beta.34", "", { "os": "win32", "cpu": "x64" }, "sha512-7O5iUBX6HSBKlQU4WykpUoEmb0wQmonb6ziKFr3dJTHud2kzDnWMqk344T0qm3uGv9Ddq6Re/94pInxo1G2d4w=="],
|
||||
|
||||
"@rolldown/pluginutils": ["@rolldown/pluginutils@1.0.0-beta.33", "", {}, "sha512-she25NCG6NoEPC/SEB4pHs5STcnfI4VBFOzjeI63maSPrWME5J2XC8ogrBgp8NaE/xzj28/kbpSaebiMvFRj+w=="],
|
||||
"@rolldown/pluginutils": ["@rolldown/pluginutils@1.0.0-beta.34", "", {}, "sha512-LyAREkZHP5pMom7c24meKmJCdhf2hEyvam2q0unr3or9ydwDL+DJ8chTF6Av/RFPb3rH8UFBdMzO5MxTZW97oA=="],
|
||||
|
||||
"@rollup/plugin-commonjs": ["@rollup/plugin-commonjs@28.0.1", "", { "dependencies": { "@rollup/pluginutils": "^5.0.1", "commondir": "^1.0.1", "estree-walker": "^2.0.2", "fdir": "^6.2.0", "is-reference": "1.2.1", "magic-string": "^0.30.3", "picomatch": "^4.0.2" }, "peerDependencies": { "rollup": "^2.68.0||^3.0.0||^4.0.0" }, "optionalPeers": ["rollup"] }, "sha512-+tNWdlWKbpB3WgBN7ijjYkq9X5uhjmcvyjEght4NmH5fAU++zfQzAJ6wumLS+dNcvwEZhKx2Z+skY8m7v0wGSA=="],
|
||||
|
||||
|
|
@ -1230,6 +1247,8 @@
|
|||
|
||||
"@supermemory/ai-sdk": ["@supermemory/ai-sdk@workspace:packages/ai-sdk"],
|
||||
|
||||
"@supermemory/openai-sdk": ["@supermemory/openai-sdk@workspace:packages/openai-sdk-ts"],
|
||||
|
||||
"@swc/core": ["@swc/core@1.13.4", "", { "dependencies": { "@swc/counter": "^0.1.3", "@swc/types": "^0.1.24" }, "optionalDependencies": { "@swc/core-darwin-arm64": "1.13.4", "@swc/core-darwin-x64": "1.13.4", "@swc/core-linux-arm-gnueabihf": "1.13.4", "@swc/core-linux-arm64-gnu": "1.13.4", "@swc/core-linux-arm64-musl": "1.13.4", "@swc/core-linux-x64-gnu": "1.13.4", "@swc/core-linux-x64-musl": "1.13.4", "@swc/core-win32-arm64-msvc": "1.13.4", "@swc/core-win32-ia32-msvc": "1.13.4", "@swc/core-win32-x64-msvc": "1.13.4" }, "peerDependencies": { "@swc/helpers": ">=0.5.17" }, "optionalPeers": ["@swc/helpers"] }, "sha512-bCq2GCuKV16DSOOEdaRqHMm1Ok4YEoLoNdgdzp8BS/Hxxr/0NVCHBUgRLLRy/TlJGv20Idx+djd5FIDvsnqMaw=="],
|
||||
|
||||
"@swc/core-darwin-arm64": ["@swc/core-darwin-arm64@1.13.4", "", { "os": "darwin", "cpu": "arm64" }, "sha512-CGbTu9dGBwgklUj+NAQAYyPjBuoHaNRWK4QXJRv1QNIkhtE27aY7QA9uEON14SODxsio3t8+Pjjl2Mzx1Pxf+g=="],
|
||||
|
|
@ -1328,7 +1347,7 @@
|
|||
|
||||
"@tybys/wasm-util": ["@tybys/wasm-util@0.10.0", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-VyyPYFlOMNylG45GoAe0xDoLwWuowvf92F9kySqzYh8vmYm7D2u4iUJKa1tOUpS70Ku13ASrOkS4ScXFsTaCNQ=="],
|
||||
|
||||
"@types/bun": ["@types/bun@1.2.20", "", { "dependencies": { "bun-types": "1.2.20" } }, "sha512-dX3RGzQ8+KgmMw7CsW4xT5ITBSCrSbfHc36SNT31EOUg/LA9JWq0VDdEXDRSe1InVWpd2yLUM1FUF/kEOyTzYA=="],
|
||||
"@types/bun": ["@types/bun@1.2.21", "", { "dependencies": { "bun-types": "1.2.21" } }, "sha512-NiDnvEqmbfQ6dmZ3EeUO577s4P5bf4HCTXtI6trMc6f6RzirY5IrF3aIookuSpyslFzrnvv2lmEWv5HyC1X79A=="],
|
||||
|
||||
"@types/chai": ["@types/chai@5.2.2", "", { "dependencies": { "@types/deep-eql": "*" } }, "sha512-8kB30R7Hwqf40JPiKhVzodJs2Qc1ZJ5zuT3uzw5Hq/dhNCl3G3l83jfpdI1e20BP348+fV7VIL/+FxaXkqBmWg=="],
|
||||
|
||||
|
|
@ -1774,7 +1793,7 @@
|
|||
|
||||
"drizzle-zod": ["drizzle-zod@0.7.1", "", { "peerDependencies": { "drizzle-orm": ">=0.36.0", "zod": ">=3.0.0" } }, "sha512-nZzALOdz44/AL2U005UlmMqaQ1qe5JfanvLujiTHiiT8+vZJTBFhj3pY4Vk+L6UWyKFfNmLhk602Hn4kCTynKQ=="],
|
||||
|
||||
"dts-resolver": ["dts-resolver@2.1.1", "", { "peerDependencies": { "oxc-resolver": ">=11.0.0" }, "optionalPeers": ["oxc-resolver"] }, "sha512-3BiGFhB6mj5Kv+W2vdJseQUYW+SKVzAFJL6YNP6ursbrwy1fXHRotfHi3xLNxe4wZl/K8qbAFeCDjZLjzqxxRw=="],
|
||||
"dts-resolver": ["dts-resolver@2.1.2", "", { "peerDependencies": { "oxc-resolver": ">=11.0.0" }, "optionalPeers": ["oxc-resolver"] }, "sha512-xeXHBQkn2ISSXxbJWD828PFjtyg+/UrMDo7W4Ffcs7+YWCquxU8YjV1KoxuiL+eJ5pg3ll+bC6flVv61L3LKZg=="],
|
||||
|
||||
"dunder-proto": ["dunder-proto@1.0.1", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.1", "es-errors": "^1.3.0", "gopd": "^1.2.0" } }, "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A=="],
|
||||
|
||||
|
|
@ -2372,6 +2391,8 @@
|
|||
|
||||
"open": ["open@10.2.0", "", { "dependencies": { "default-browser": "^5.2.1", "define-lazy-prop": "^3.0.0", "is-inside-container": "^1.0.0", "wsl-utils": "^0.1.0" } }, "sha512-YgBpdJHPyQ2UE5x+hlSXcnejzAvD0b22U2OuAP+8OnlJT+PjWPxtgmGqKKc+RgTM63U9gN0YzrYc71R2WT/hTA=="],
|
||||
|
||||
"openai": ["openai@4.104.0", "", { "dependencies": { "@types/node": "^18.11.18", "@types/node-fetch": "^2.6.4", "abort-controller": "^3.0.0", "agentkeepalive": "^4.2.1", "form-data-encoder": "1.7.2", "formdata-node": "^4.3.2", "node-fetch": "^2.6.7" }, "peerDependencies": { "ws": "^8.18.0", "zod": "^3.23.8" }, "optionalPeers": ["ws", "zod"], "bin": { "openai": "bin/cli" } }, "sha512-p99EFNsA/yX6UhVO93f5kJsDRLAg+CTA2RBqdHK4RtK8u5IJw32Hyb2dTGKbnnFmnuoBv5r7Z2CURI9sGZpSuA=="],
|
||||
|
||||
"openapi-types": ["openapi-types@12.1.3", "", {}, "sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw=="],
|
||||
|
||||
"os-paths": ["os-paths@7.4.0", "", { "optionalDependencies": { "fsevents": "*" } }, "sha512-Ux1J4NUqC6tZayBqLN1kUlDAEvLiQlli/53sSddU4IN+h+3xxnv2HmRSMpVSvr1hvJzotfMs3ERvETGK+f4OwA=="],
|
||||
|
|
@ -2560,9 +2581,9 @@
|
|||
|
||||
"retry": ["retry@0.12.0", "", {}, "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow=="],
|
||||
|
||||
"rolldown": ["rolldown@1.0.0-beta.33", "", { "dependencies": { "@oxc-project/runtime": "=0.82.2", "@oxc-project/types": "=0.82.2", "@rolldown/pluginutils": "1.0.0-beta.33", "ansis": "^4.0.0" }, "optionalDependencies": { "@rolldown/binding-android-arm64": "1.0.0-beta.33", "@rolldown/binding-darwin-arm64": "1.0.0-beta.33", "@rolldown/binding-darwin-x64": "1.0.0-beta.33", "@rolldown/binding-freebsd-x64": "1.0.0-beta.33", "@rolldown/binding-linux-arm-gnueabihf": "1.0.0-beta.33", "@rolldown/binding-linux-arm64-gnu": "1.0.0-beta.33", "@rolldown/binding-linux-arm64-musl": "1.0.0-beta.33", "@rolldown/binding-linux-x64-gnu": "1.0.0-beta.33", "@rolldown/binding-linux-x64-musl": "1.0.0-beta.33", "@rolldown/binding-openharmony-arm64": "1.0.0-beta.33", "@rolldown/binding-wasm32-wasi": "1.0.0-beta.33", "@rolldown/binding-win32-arm64-msvc": "1.0.0-beta.33", "@rolldown/binding-win32-ia32-msvc": "1.0.0-beta.33", "@rolldown/binding-win32-x64-msvc": "1.0.0-beta.33" }, "bin": { "rolldown": "bin/cli.mjs" } }, "sha512-mgu118ZuRguC8unhPCbdZbyRbjQfEMiWqlojBA5aRIncBelRaBomnHNpGKYkYWeK7twRz5Cql30xgqqrA3Xelw=="],
|
||||
"rolldown": ["rolldown@1.0.0-beta.34", "", { "dependencies": { "@oxc-project/runtime": "=0.82.3", "@oxc-project/types": "=0.82.3", "@rolldown/pluginutils": "1.0.0-beta.34", "ansis": "^4.0.0" }, "optionalDependencies": { "@rolldown/binding-android-arm64": "1.0.0-beta.34", "@rolldown/binding-darwin-arm64": "1.0.0-beta.34", "@rolldown/binding-darwin-x64": "1.0.0-beta.34", "@rolldown/binding-freebsd-x64": "1.0.0-beta.34", "@rolldown/binding-linux-arm-gnueabihf": "1.0.0-beta.34", "@rolldown/binding-linux-arm64-gnu": "1.0.0-beta.34", "@rolldown/binding-linux-arm64-musl": "1.0.0-beta.34", "@rolldown/binding-linux-x64-gnu": "1.0.0-beta.34", "@rolldown/binding-linux-x64-musl": "1.0.0-beta.34", "@rolldown/binding-openharmony-arm64": "1.0.0-beta.34", "@rolldown/binding-wasm32-wasi": "1.0.0-beta.34", "@rolldown/binding-win32-arm64-msvc": "1.0.0-beta.34", "@rolldown/binding-win32-ia32-msvc": "1.0.0-beta.34", "@rolldown/binding-win32-x64-msvc": "1.0.0-beta.34" }, "bin": { "rolldown": "bin/cli.mjs" } }, "sha512-Wwh7EwalMzzX3Yy3VN58VEajeR2Si8+HDNMf706jPLIqU7CxneRW+dQVfznf5O0TWTnJyu4npelwg2bzTXB1Nw=="],
|
||||
|
||||
"rolldown-plugin-dts": ["rolldown-plugin-dts@0.15.7", "", { "dependencies": { "@babel/generator": "^7.28.3", "@babel/parser": "^7.28.3", "@babel/types": "^7.28.2", "ast-kit": "^2.1.2", "birpc": "^2.5.0", "debug": "^4.4.1", "dts-resolver": "^2.1.1", "get-tsconfig": "^4.10.1" }, "peerDependencies": { "@typescript/native-preview": ">=7.0.0-dev.20250601.1", "rolldown": "^1.0.0-beta.9", "typescript": "^5.0.0", "vue-tsc": "~3.0.3" }, "optionalPeers": ["@typescript/native-preview", "typescript", "vue-tsc"] }, "sha512-BpdrnLaa+uyw0rPT47+4FUC7hQFazBFppeFT0ioW5Ybg0XCLeRohc3HHPlnCxI6LtzgSWT7Ot8ahn6ji10IQBg=="],
|
||||
"rolldown-plugin-dts": ["rolldown-plugin-dts@0.15.10", "", { "dependencies": { "@babel/generator": "^7.28.3", "@babel/parser": "^7.28.3", "@babel/types": "^7.28.2", "ast-kit": "^2.1.2", "birpc": "^2.5.0", "debug": "^4.4.1", "dts-resolver": "^2.1.2", "get-tsconfig": "^4.10.1" }, "peerDependencies": { "@typescript/native-preview": ">=7.0.0-dev.20250601.1", "rolldown": "^1.0.0-beta.9", "typescript": "^5.0.0", "vue-tsc": "~3.0.3" }, "optionalPeers": ["@typescript/native-preview", "typescript", "vue-tsc"] }, "sha512-8cPVAVQUo9tYAoEpc3jFV9RxSil13hrRRg8cHC9gLXxRMNtWPc1LNMSDXzjyD+5Vny49sDZH77JlXp/vlc4I3g=="],
|
||||
|
||||
"rollup": ["rollup@4.48.0", "", { "dependencies": { "@types/estree": "1.0.8" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.48.0", "@rollup/rollup-android-arm64": "4.48.0", "@rollup/rollup-darwin-arm64": "4.48.0", "@rollup/rollup-darwin-x64": "4.48.0", "@rollup/rollup-freebsd-arm64": "4.48.0", "@rollup/rollup-freebsd-x64": "4.48.0", "@rollup/rollup-linux-arm-gnueabihf": "4.48.0", "@rollup/rollup-linux-arm-musleabihf": "4.48.0", "@rollup/rollup-linux-arm64-gnu": "4.48.0", "@rollup/rollup-linux-arm64-musl": "4.48.0", "@rollup/rollup-linux-loongarch64-gnu": "4.48.0", "@rollup/rollup-linux-ppc64-gnu": "4.48.0", "@rollup/rollup-linux-riscv64-gnu": "4.48.0", "@rollup/rollup-linux-riscv64-musl": "4.48.0", "@rollup/rollup-linux-s390x-gnu": "4.48.0", "@rollup/rollup-linux-x64-gnu": "4.48.0", "@rollup/rollup-linux-x64-musl": "4.48.0", "@rollup/rollup-win32-arm64-msvc": "4.48.0", "@rollup/rollup-win32-ia32-msvc": "4.48.0", "@rollup/rollup-win32-x64-msvc": "4.48.0", "fsevents": "~2.3.2" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-BXHRqK1vyt9XVSEHZ9y7xdYtuYbwVod2mLwOMFP7t/Eqoc1pHRlG/WdV2qNeNvZHRQdLedaFycljaYYM96RqJQ=="],
|
||||
|
||||
|
|
@ -2702,7 +2723,7 @@
|
|||
|
||||
"suffix-thumb": ["suffix-thumb@5.0.2", "", {}, "sha512-I5PWXAFKx3FYnI9a+dQMWNqTxoRt6vdBdb0O+BJ1sxXCWtSoQCusc13E58f+9p4MYx/qCnEMkD5jac6K2j3dgA=="],
|
||||
|
||||
"supermemory": ["supermemory@3.0.0-alpha.23", "", {}, "sha512-bMOfQnEu+m/Me1qDaF9gE9Jr01vZxhS2n9t9kqPYOs2SLQB7vsONG1Iq+dvx2vA+FJubn/KGyl1EkPd2o1b6rw=="],
|
||||
"supermemory": ["supermemory@3.0.0-alpha.26", "", {}, "sha512-gjLAGEMZLgg1Et5rzCxuy8uuIcy1zjRkKZxsGpbMwxi4b4Z4kH6X/CR9J3QzhSpJRrj35+gP5DW6z8WIMgrCIQ=="],
|
||||
|
||||
"supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="],
|
||||
|
||||
|
|
@ -2762,7 +2783,7 @@
|
|||
|
||||
"ts-tqdm": ["ts-tqdm@0.8.6", "", {}, "sha512-3X3M1PZcHtgQbnwizL+xU8CAgbYbeLHrrDwL9xxcZZrV5J+e7loJm1XrXozHjSkl44J0Zg0SgA8rXbh83kCkcQ=="],
|
||||
|
||||
"tsdown": ["tsdown@0.14.1", "", { "dependencies": { "ansis": "^4.1.0", "cac": "^6.7.14", "chokidar": "^4.0.3", "debug": "^4.4.1", "diff": "^8.0.2", "empathic": "^2.0.0", "hookable": "^5.5.3", "rolldown": "latest", "rolldown-plugin-dts": "^0.15.6", "semver": "^7.7.2", "tinyexec": "^1.0.1", "tinyglobby": "^0.2.14", "tree-kill": "^1.2.2", "unconfig": "^7.3.2" }, "peerDependencies": { "@arethetypeswrong/core": "^0.18.1", "publint": "^0.3.0", "typescript": "^5.0.0", "unplugin-lightningcss": "^0.4.0", "unplugin-unused": "^0.5.0" }, "optionalPeers": ["@arethetypeswrong/core", "publint", "typescript", "unplugin-lightningcss", "unplugin-unused"], "bin": { "tsdown": "dist/run.mjs" } }, "sha512-/nBuFDKZeYln9hAxwWG5Cm55/823sNIVI693iVi0xRFHzf9OVUq4b/lx9PH1TErFr/IQ0kd2hutFbJIPM0XQWA=="],
|
||||
"tsdown": ["tsdown@0.14.2", "", { "dependencies": { "ansis": "^4.1.0", "cac": "^6.7.14", "chokidar": "^4.0.3", "debug": "^4.4.1", "diff": "^8.0.2", "empathic": "^2.0.0", "hookable": "^5.5.3", "rolldown": "latest", "rolldown-plugin-dts": "^0.15.8", "semver": "^7.7.2", "tinyexec": "^1.0.1", "tinyglobby": "^0.2.14", "tree-kill": "^1.2.2", "unconfig": "^7.3.3" }, "peerDependencies": { "@arethetypeswrong/core": "^0.18.1", "publint": "^0.3.0", "typescript": "^5.0.0", "unplugin-lightningcss": "^0.4.0", "unplugin-unused": "^0.5.0" }, "optionalPeers": ["@arethetypeswrong/core", "publint", "typescript", "unplugin-lightningcss", "unplugin-unused"], "bin": { "tsdown": "dist/run.mjs" } }, "sha512-6ThtxVZoTlR5YJov5rYvH8N1+/S/rD/pGfehdCLGznGgbxz+73EASV1tsIIZkLw2n+SXcERqHhcB/OkyxdKv3A=="],
|
||||
|
||||
"tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
|
||||
|
||||
|
|
@ -3218,13 +3239,17 @@
|
|||
|
||||
"@sentry/nextjs/chalk": ["chalk@3.0.0", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg=="],
|
||||
|
||||
"@supermemory/ai-sdk/@ai-sdk/openai": ["@ai-sdk/openai@2.0.19", "", { "dependencies": { "@ai-sdk/provider": "2.0.0", "@ai-sdk/provider-utils": "3.0.5" }, "peerDependencies": { "zod": "^3.25.76 || ^4" } }, "sha512-sG3/IVaPvV7Vn6513I1bcJILHpLCXbVif2ht6CyROcB9FzXCJe2K5uRbAg30HWsdCEe7xu4OAWtMK6yWTOcsSA=="],
|
||||
"@supermemory/ai-sdk/@ai-sdk/openai": ["@ai-sdk/openai@2.0.22", "", { "dependencies": { "@ai-sdk/provider": "2.0.0", "@ai-sdk/provider-utils": "3.0.7" }, "peerDependencies": { "zod": "^3.25.76 || ^4" } }, "sha512-qjSIPL5+LNM9flcBPeR64ZWeAZdYg4XWkAK34H3FaY61dSbuIaeqFPSzmQUrxotVcphAzgfL5tuYRqRYP2ZYyg=="],
|
||||
|
||||
"@supermemory/ai-sdk/ai": ["ai@5.0.22", "", { "dependencies": { "@ai-sdk/gateway": "1.0.11", "@ai-sdk/provider": "2.0.0", "@ai-sdk/provider-utils": "3.0.5", "@opentelemetry/api": "1.9.0" }, "peerDependencies": { "zod": "^3.25.76 || ^4" } }, "sha512-RZiYhj7Ux7hrLtXkHPcxzdiSZt4NOiC69O5AkNfMCsz3twwz/KRkl9ASptosoOsg833s5yRcTSdIu5z53Sl6Pw=="],
|
||||
"@supermemory/ai-sdk/ai": ["ai@5.0.26", "", { "dependencies": { "@ai-sdk/gateway": "1.0.15", "@ai-sdk/provider": "2.0.0", "@ai-sdk/provider-utils": "3.0.7", "@opentelemetry/api": "1.9.0" }, "peerDependencies": { "zod": "^3.25.76 || ^4" } }, "sha512-bGNtG+nYQ2U+5mzuLbxIg9WxGQJ2u5jv2gYgP8C+CJ1YI4qqIjvjOgGEZWzvNet8jiOGIlqstsht9aQefKzmBw=="],
|
||||
|
||||
"@supermemory/ai-sdk/typescript": ["typescript@5.9.2", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A=="],
|
||||
|
||||
"@supermemory/ai-sdk/zod": ["zod@4.1.0", "", {}, "sha512-UWxluYj2IDX9MHRXTMbB/2eeWrAMmmMSESM+MfT9MQw8U1qo9q5ASW08anoJh6AJ7pkt099fLdNFmfI+4aChHg=="],
|
||||
"@supermemory/ai-sdk/zod": ["zod@4.1.4", "", {}, "sha512-2YqJuWkU6IIK9qcE4k1lLLhyZ6zFw7XVRdQGpV97jEIZwTrscUw+DY31Xczd8nwaoksyJUIxCojZXwckJovWxA=="],
|
||||
|
||||
"@supermemory/openai-sdk/typescript": ["typescript@5.9.2", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A=="],
|
||||
|
||||
"@supermemory/openai-sdk/zod": ["zod@4.1.4", "", {}, "sha512-2YqJuWkU6IIK9qcE4k1lLLhyZ6zFw7XVRdQGpV97jEIZwTrscUw+DY31Xczd8nwaoksyJUIxCojZXwckJovWxA=="],
|
||||
|
||||
"@tailwindcss/oxide-wasm32-wasi/@emnapi/core": ["@emnapi/core@1.4.5", "", { "dependencies": { "@emnapi/wasi-threads": "1.0.4", "tslib": "^2.4.0" }, "bundled": true }, "sha512-XsLw1dEOpkSX/WucdqUhPWP7hDxSvZiY+fsUC14h+FtQ2Ifni4znbBt8punRX+Uj2JG/uDb8nEHVKvrVlvdZ5Q=="],
|
||||
|
||||
|
|
@ -3240,6 +3265,8 @@
|
|||
|
||||
"@tokenizer/inflate/fflate": ["fflate@0.8.2", "", {}, "sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A=="],
|
||||
|
||||
"@types/bun/bun-types": ["bun-types@1.2.21", "", { "dependencies": { "@types/node": "*" }, "peerDependencies": { "@types/react": "^19" } }, "sha512-sa2Tj77Ijc/NTLS0/Odjq/qngmEPZfbfnOERi0KRUYhT9R8M4VBioWVmMWE5GrYbKMc+5lVybXygLdibHaqVqw=="],
|
||||
|
||||
"@vitejs/plugin-rsc/@mjackson/node-fetch-server": ["@mjackson/node-fetch-server@0.7.0", "", {}, "sha512-un8diyEBKU3BTVj3GzlTPA1kIjCkGdD+AMYQy31Gf9JCkfoZzwgJ79GUtHrF2BN3XPNMLpubbzPcxys+a3uZEw=="],
|
||||
|
||||
"@vitejs/plugin-rsc/estree-walker": ["estree-walker@3.0.3", "", { "dependencies": { "@types/estree": "^1.0.0" } }, "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g=="],
|
||||
|
|
@ -3330,6 +3357,8 @@
|
|||
|
||||
"next/postcss": ["postcss@8.4.31", "", { "dependencies": { "nanoid": "^3.3.6", "picocolors": "^1.0.0", "source-map-js": "^1.0.2" } }, "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ=="],
|
||||
|
||||
"openai/@types/node": ["@types/node@18.19.123", "", { "dependencies": { "undici-types": "~5.26.4" } }, "sha512-K7DIaHnh0mzVxreCR9qwgNxp3MH9dltPNIEddW9MYUlcKAzm+3grKNSTe2vCJHI1FaLpvpL5JGJrz1UZDKYvDg=="],
|
||||
|
||||
"parse-entities/@types/unist": ["@types/unist@2.0.11", "", {}, "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA=="],
|
||||
|
||||
"periscopic/is-reference": ["is-reference@3.0.3", "", { "dependencies": { "@types/estree": "^1.0.6" } }, "sha512-ixkJoqQvAP88E6wLydLGGqCJsrFUnqoH6HnaczB8XmDH1oaWU+xxdptvikTgaEhtZ53Ky6YXiBuUI2WXLMCwjw=="],
|
||||
|
|
@ -3698,11 +3727,11 @@
|
|||
|
||||
"@sentry/nextjs/chalk/ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="],
|
||||
|
||||
"@supermemory/ai-sdk/@ai-sdk/openai/@ai-sdk/provider-utils": ["@ai-sdk/provider-utils@3.0.5", "", { "dependencies": { "@ai-sdk/provider": "2.0.0", "@standard-schema/spec": "^1.0.0", "eventsource-parser": "^3.0.3", "zod-to-json-schema": "^3.24.1" }, "peerDependencies": { "zod": "^3.25.76 || ^4" } }, "sha512-HliwB/yzufw3iwczbFVE2Fiwf1XqROB/I6ng8EKUsPM5+2wnIa8f4VbljZcDx+grhFrPV+PnRZH7zBqi8WZM7Q=="],
|
||||
"@supermemory/ai-sdk/@ai-sdk/openai/@ai-sdk/provider-utils": ["@ai-sdk/provider-utils@3.0.7", "", { "dependencies": { "@ai-sdk/provider": "2.0.0", "@standard-schema/spec": "^1.0.0", "eventsource-parser": "^3.0.5" }, "peerDependencies": { "zod": "^3.25.76 || ^4" } }, "sha512-o3BS5/t8KnBL3ubP8k3w77AByOypLm+pkIL/DCw0qKkhDbvhCy+L3hRTGPikpdb8WHcylAeKsjgwOxhj4cqTUA=="],
|
||||
|
||||
"@supermemory/ai-sdk/ai/@ai-sdk/gateway": ["@ai-sdk/gateway@1.0.11", "", { "dependencies": { "@ai-sdk/provider": "2.0.0", "@ai-sdk/provider-utils": "3.0.5" }, "peerDependencies": { "zod": "^3.25.76 || ^4" } }, "sha512-ErwWS3sPOuWy42eE3AVxlKkTa1XjjKBEtNCOylVKMO5KNyz5qie8QVlLYbULOG56dtxX4zTKX3rQNJudplhcmQ=="],
|
||||
"@supermemory/ai-sdk/ai/@ai-sdk/gateway": ["@ai-sdk/gateway@1.0.15", "", { "dependencies": { "@ai-sdk/provider": "2.0.0", "@ai-sdk/provider-utils": "3.0.7" }, "peerDependencies": { "zod": "^3.25.76 || ^4" } }, "sha512-xySXoQ29+KbGuGfmDnABx+O6vc7Gj7qugmj1kGpn0rW0rQNn6UKUuvscKMzWyv1Uv05GyC1vqHq8ZhEOLfXscQ=="],
|
||||
|
||||
"@supermemory/ai-sdk/ai/@ai-sdk/provider-utils": ["@ai-sdk/provider-utils@3.0.5", "", { "dependencies": { "@ai-sdk/provider": "2.0.0", "@standard-schema/spec": "^1.0.0", "eventsource-parser": "^3.0.3", "zod-to-json-schema": "^3.24.1" }, "peerDependencies": { "zod": "^3.25.76 || ^4" } }, "sha512-HliwB/yzufw3iwczbFVE2Fiwf1XqROB/I6ng8EKUsPM5+2wnIa8f4VbljZcDx+grhFrPV+PnRZH7zBqi8WZM7Q=="],
|
||||
"@supermemory/ai-sdk/ai/@ai-sdk/provider-utils": ["@ai-sdk/provider-utils@3.0.7", "", { "dependencies": { "@ai-sdk/provider": "2.0.0", "@standard-schema/spec": "^1.0.0", "eventsource-parser": "^3.0.5" }, "peerDependencies": { "zod": "^3.25.76 || ^4" } }, "sha512-o3BS5/t8KnBL3ubP8k3w77AByOypLm+pkIL/DCw0qKkhDbvhCy+L3hRTGPikpdb8WHcylAeKsjgwOxhj4cqTUA=="],
|
||||
|
||||
"alchemy/@cloudflare/unenv-preset/unenv": ["unenv@2.0.0-rc.19", "", { "dependencies": { "defu": "^6.1.4", "exsolve": "^1.0.7", "ohash": "^2.0.11", "pathe": "^2.0.3", "ufo": "^1.6.1" } }, "sha512-t/OMHBNAkknVCI7bVB9OWjUUAwhVv9vsPIAGnNUxnu3FxPQN11rjh0sksLMzc3g7IlTgvHmOTl4JM7JHpcv5wA=="],
|
||||
|
||||
|
|
@ -3780,6 +3809,8 @@
|
|||
|
||||
"next/postcss/nanoid": ["nanoid@3.3.11", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="],
|
||||
|
||||
"openai/@types/node/undici-types": ["undici-types@5.26.5", "", {}, "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA=="],
|
||||
|
||||
"send/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="],
|
||||
|
||||
"string-width-cjs/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="],
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
{
|
||||
"name": "@supermemory/ai-sdk",
|
||||
"version": "1.0.4",
|
||||
"type": "module",
|
||||
"version": "1.0.5",
|
||||
"scripts": {
|
||||
"build": "tsdown",
|
||||
"dev": "tsdown --watch",
|
||||
|
|
@ -9,16 +10,16 @@
|
|||
"test:watch": "vitest --watch"
|
||||
},
|
||||
"dependencies": {
|
||||
"@ai-sdk/openai": "^2.0.15",
|
||||
"@ai-sdk/openai": "^2.0.22",
|
||||
"@ai-sdk/provider": "^2.0.0",
|
||||
"ai": "^5.0.17",
|
||||
"supermemory": "^3.0.0-alpha.22",
|
||||
"zod": "^4.0.17"
|
||||
"ai": "^5.0.26",
|
||||
"supermemory": "^3.0.0-alpha.26",
|
||||
"zod": "^4.1.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@total-typescript/tsconfig": "^1.0.4",
|
||||
"@types/bun": "^1.2.20",
|
||||
"tsdown": "^0.14.1",
|
||||
"@types/bun": "^1.2.21",
|
||||
"tsdown": "^0.14.2",
|
||||
"typescript": "^5.9.2",
|
||||
"vitest": "^3.2.4"
|
||||
},
|
||||
|
|
@ -32,5 +33,11 @@
|
|||
"repository": {
|
||||
"url": "https://github.com/supermemoryai/supermemory",
|
||||
"directory": "packages/ai-sdk"
|
||||
}
|
||||
},
|
||||
"keywords": [
|
||||
"ai",
|
||||
"sdk",
|
||||
"supermemory",
|
||||
"memory"
|
||||
]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,7 +39,6 @@ describe("supermemoryTools", () => {
|
|||
expect(tools).toBeDefined()
|
||||
expect(tools.searchMemories).toBeDefined()
|
||||
expect(tools.addMemory).toBeDefined()
|
||||
expect(tools.fetchMemory).toBeDefined()
|
||||
})
|
||||
|
||||
it("should create tools with custom baseUrl", () => {
|
||||
|
|
@ -51,7 +50,6 @@ describe("supermemoryTools", () => {
|
|||
expect(tools).toBeDefined()
|
||||
expect(tools.searchMemories).toBeDefined()
|
||||
expect(tools.addMemory).toBeDefined()
|
||||
expect(tools.fetchMemory).toBeDefined()
|
||||
})
|
||||
|
||||
it("should create tools with projectId configuration", () => {
|
||||
|
|
@ -63,7 +61,6 @@ describe("supermemoryTools", () => {
|
|||
expect(tools).toBeDefined()
|
||||
expect(tools.searchMemories).toBeDefined()
|
||||
expect(tools.addMemory).toBeDefined()
|
||||
expect(tools.fetchMemory).toBeDefined()
|
||||
})
|
||||
|
||||
it("should create tools with custom container tags", () => {
|
||||
|
|
@ -75,7 +72,6 @@ describe("supermemoryTools", () => {
|
|||
expect(tools).toBeDefined()
|
||||
expect(tools.searchMemories).toBeDefined()
|
||||
expect(tools.addMemory).toBeDefined()
|
||||
expect(tools.fetchMemory).toBeDefined()
|
||||
})
|
||||
})
|
||||
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ export function supermemoryTools(
|
|||
) {
|
||||
const client = new Supermemory({
|
||||
apiKey,
|
||||
...(config?.baseUrl && { baseURL: config.baseUrl }),
|
||||
...(config?.baseUrl ? { baseURL: config.baseUrl } : {}),
|
||||
})
|
||||
|
||||
const containerTags = config?.projectId
|
||||
|
|
@ -30,7 +30,7 @@ export function supermemoryTools(
|
|||
|
||||
const searchMemories = tool({
|
||||
description:
|
||||
"Search user memories and patterns. Run when explicitly asked or when context about user's past choices would be helpful. Uses semantic matching to find relevant details across related experiences.",
|
||||
"Search (recall) memories/details/information about the user or other facts or entities. Run when explicitly asked or when context about user's past choices would be helpful.",
|
||||
inputSchema: z.object({
|
||||
informationToGet: z
|
||||
.string()
|
||||
|
|
@ -48,7 +48,11 @@ export function supermemoryTools(
|
|||
.default(10)
|
||||
.describe("Maximum number of results to return"),
|
||||
}),
|
||||
execute: async ({ informationToGet, includeFullDocs = true, limit = 10 }) => {
|
||||
execute: async ({
|
||||
informationToGet,
|
||||
includeFullDocs = true,
|
||||
limit = 10,
|
||||
}) => {
|
||||
try {
|
||||
const response = await client.search.execute({
|
||||
q: informationToGet,
|
||||
|
|
@ -74,7 +78,7 @@ export function supermemoryTools(
|
|||
|
||||
const addMemory = tool({
|
||||
description:
|
||||
"Add a new memory to the user's memories. Run when explicitly asked or when the user mentions any information generalizable beyond the context of the current conversation.",
|
||||
"Add (remember) memories/details/information about the user or other facts or entities. Run when explicitly asked or when the user mentions any information generalizable beyond the context of the current conversation.",
|
||||
inputSchema: z.object({
|
||||
memory: z
|
||||
.string()
|
||||
|
|
@ -105,32 +109,9 @@ export function supermemoryTools(
|
|||
},
|
||||
})
|
||||
|
||||
const fetchMemory = tool({
|
||||
description: "Fetch a specific memory by ID to get its full details",
|
||||
inputSchema: z.object({
|
||||
memoryId: z.string().describe("The ID of the memory to fetch"),
|
||||
}),
|
||||
execute: async ({ memoryId }) => {
|
||||
try {
|
||||
const response = await client.memories.get(memoryId)
|
||||
|
||||
return {
|
||||
success: true,
|
||||
memory: response,
|
||||
}
|
||||
} catch (error) {
|
||||
return {
|
||||
success: false,
|
||||
error: error instanceof Error ? error.message : "Unknown error",
|
||||
}
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
return {
|
||||
searchMemories,
|
||||
addMemory,
|
||||
fetchMemory,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -150,11 +131,3 @@ export const addMemoryTool = (
|
|||
const { addMemory } = supermemoryTools(apiKey, config)
|
||||
return addMemory
|
||||
}
|
||||
|
||||
export const fetchMemoryTool = (
|
||||
apiKey: string,
|
||||
config?: SupermemoryToolsConfig,
|
||||
) => {
|
||||
const { fetchMemory } = supermemoryTools(apiKey, config)
|
||||
return fetchMemory
|
||||
}
|
||||
|
|
|
|||
318
packages/openai-sdk-python/README.md
Normal file
318
packages/openai-sdk-python/README.md
Normal file
|
|
@ -0,0 +1,318 @@
|
|||
# Supermemory OpenAI Python SDK
|
||||
|
||||
Enhanced OpenAI Python SDK with Supermemory infinite context integration.
|
||||
|
||||
This package extends the official [OpenAI Python SDK](https://github.com/openai/openai-python) with [Supermemory](https://supermemory.ai) capabilities, enabling infinite context chat completions and memory management tools.
|
||||
|
||||
## Features
|
||||
|
||||
- 🚀 **Infinite Context**: Chat completions with unlimited conversation history
|
||||
- 🧠 **Memory Tools**: Search, add, and fetch user memories seamlessly
|
||||
- 🔌 **Multiple Providers**: Support for OpenAI, Anthropic, Groq, and more
|
||||
- 🛠 **Function Calling**: Built-in memory tools for OpenAI function calling
|
||||
- 🔒 **Type Safe**: Full TypeScript-style type hints for Python
|
||||
- ⚡ **Async Support**: Full async/await support
|
||||
|
||||
## Installation
|
||||
|
||||
Install using uv (recommended):
|
||||
|
||||
```bash
|
||||
uv add supermemory-openai
|
||||
```
|
||||
|
||||
Or with pip:
|
||||
|
||||
```bash
|
||||
pip install supermemory-openai
|
||||
```
|
||||
|
||||
## Quick Start
|
||||
|
||||
### Basic Chat Completion
|
||||
|
||||
```python
|
||||
import asyncio
|
||||
from supermemory_openai import SupermemoryOpenAI, SupermemoryInfiniteChatConfigWithProviderName
|
||||
|
||||
async def main():
|
||||
# Initialize client
|
||||
client = SupermemoryOpenAI(
|
||||
supermemory_api_key="your-supermemory-api-key",
|
||||
config=SupermemoryInfiniteChatConfigWithProviderName(
|
||||
provider_name="openai",
|
||||
provider_api_key="your-openai-api-key",
|
||||
)
|
||||
)
|
||||
|
||||
# Create chat completion
|
||||
response = await client.chat_completion(
|
||||
messages=[
|
||||
{"role": "user", "content": "Hello, how are you?"}
|
||||
],
|
||||
model="gpt-4o"
|
||||
)
|
||||
|
||||
print(response.choices[0].message.content)
|
||||
|
||||
asyncio.run(main())
|
||||
```
|
||||
|
||||
### Using Memory Tools
|
||||
|
||||
```python
|
||||
import asyncio
|
||||
from supermemory_openai import SupermemoryOpenAI, SupermemoryTools, SupermemoryInfiniteChatConfigWithProviderName
|
||||
|
||||
async def main():
|
||||
# Initialize client and tools
|
||||
client = SupermemoryOpenAI(
|
||||
supermemory_api_key="your-supermemory-api-key",
|
||||
config=SupermemoryInfiniteChatConfigWithProviderName(
|
||||
provider_name="openai",
|
||||
provider_api_key="your-openai-api-key",
|
||||
)
|
||||
)
|
||||
|
||||
tools = SupermemoryTools(
|
||||
api_key="your-supermemory-api-key",
|
||||
config={"project_id": "my-project"}
|
||||
)
|
||||
|
||||
# Chat with memory tools
|
||||
response = await client.chat_completion(
|
||||
messages=[
|
||||
{
|
||||
"role": "system",
|
||||
"content": "You are a helpful assistant with access to user memories."
|
||||
},
|
||||
{
|
||||
"role": "user",
|
||||
"content": "Remember that I prefer tea over coffee"
|
||||
}
|
||||
],
|
||||
tools=tools.get_tool_definitions(),
|
||||
model="gpt-4o"
|
||||
)
|
||||
|
||||
print(response.choices[0].message.content)
|
||||
|
||||
asyncio.run(main())
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
### Provider Configuration
|
||||
|
||||
#### Using Provider Names
|
||||
|
||||
```python
|
||||
from supermemory_openai import SupermemoryInfiniteChatConfigWithProviderName
|
||||
|
||||
config = SupermemoryInfiniteChatConfigWithProviderName(
|
||||
provider_name="openai", # or "anthropic", "groq", "openrouter", etc.
|
||||
provider_api_key="your-provider-api-key",
|
||||
headers={"custom-header": "value"} # optional
|
||||
)
|
||||
```
|
||||
|
||||
#### Using Custom URLs
|
||||
|
||||
```python
|
||||
from supermemory_openai import SupermemoryInfiniteChatConfigWithProviderUrl
|
||||
|
||||
config = SupermemoryInfiniteChatConfigWithProviderUrl(
|
||||
provider_url="https://your-custom-endpoint.com/v1",
|
||||
provider_api_key="your-provider-api-key",
|
||||
headers={"custom-header": "value"} # optional
|
||||
)
|
||||
```
|
||||
|
||||
### Supported Providers
|
||||
|
||||
- `openai` - OpenAI API
|
||||
- `anthropic` - Anthropic Claude
|
||||
- `openrouter` - OpenRouter
|
||||
- `deepinfra` - DeepInfra
|
||||
- `groq` - Groq
|
||||
- `google` - Google AI
|
||||
- `cloudflare` - Cloudflare Workers AI
|
||||
|
||||
## Memory Tools
|
||||
|
||||
### SupermemoryTools Class
|
||||
|
||||
```python
|
||||
from supermemory_openai import SupermemoryTools
|
||||
|
||||
tools = SupermemoryTools(
|
||||
api_key="your-supermemory-api-key",
|
||||
config={
|
||||
"project_id": "my-project", # or use container_tags
|
||||
"base_url": "https://custom-endpoint.com", # optional
|
||||
}
|
||||
)
|
||||
|
||||
# Search memories
|
||||
result = await tools.search_memories(
|
||||
information_to_get="user preferences",
|
||||
limit=10,
|
||||
include_full_docs=True
|
||||
)
|
||||
|
||||
# Add memory
|
||||
result = await tools.add_memory(
|
||||
memory="User prefers tea over coffee"
|
||||
)
|
||||
|
||||
# Fetch specific memory
|
||||
result = await tools.fetch_memory(
|
||||
memory_id="memory-id-here"
|
||||
)
|
||||
```
|
||||
|
||||
### Individual Tools
|
||||
|
||||
```python
|
||||
from supermemory_openai import (
|
||||
create_search_memories_tool,
|
||||
create_add_memory_tool,
|
||||
create_fetch_memory_tool
|
||||
)
|
||||
|
||||
search_tool = create_search_memories_tool("your-api-key")
|
||||
add_tool = create_add_memory_tool("your-api-key")
|
||||
fetch_tool = create_fetch_memory_tool("your-api-key")
|
||||
```
|
||||
|
||||
### Function Calling Integration
|
||||
|
||||
```python
|
||||
from supermemory_openai import execute_memory_tool_calls
|
||||
|
||||
# After getting tool calls from OpenAI
|
||||
if response.choices[0].message.tool_calls:
|
||||
tool_results = await execute_memory_tool_calls(
|
||||
api_key="your-supermemory-api-key",
|
||||
tool_calls=response.choices[0].message.tool_calls,
|
||||
config={"project_id": "my-project"}
|
||||
)
|
||||
|
||||
# Add tool results to conversation
|
||||
messages.append(response.choices[0].message)
|
||||
messages.extend(tool_results)
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
### SupermemoryOpenAI
|
||||
|
||||
Enhanced OpenAI client with infinite context support.
|
||||
|
||||
#### Constructor
|
||||
|
||||
```python
|
||||
SupermemoryOpenAI(
|
||||
supermemory_api_key: str,
|
||||
config: Optional[SupermemoryInfiniteChatConfig] = None
|
||||
)
|
||||
```
|
||||
|
||||
#### Methods
|
||||
|
||||
- `chat_completion()` - Create chat completion with simplified interface
|
||||
- `create_chat_completion()` - Create chat completion with full OpenAI parameters
|
||||
|
||||
### SupermemoryTools
|
||||
|
||||
Memory management tools for function calling.
|
||||
|
||||
#### Constructor
|
||||
|
||||
```python
|
||||
SupermemoryTools(
|
||||
api_key: str,
|
||||
config: Optional[SupermemoryToolsConfig] = None
|
||||
)
|
||||
```
|
||||
|
||||
#### Methods
|
||||
|
||||
- `get_tool_definitions()` - Get OpenAI function definitions
|
||||
- `search_memories()` - Search user memories
|
||||
- `add_memory()` - Add new memory
|
||||
- `fetch_memory()` - Fetch specific memory by ID
|
||||
- `execute_tool_call()` - Execute individual tool call
|
||||
|
||||
## Error Handling
|
||||
|
||||
```python
|
||||
try:
|
||||
response = await client.chat_completion(
|
||||
messages=[{"role": "user", "content": "Hello"}],
|
||||
model="gpt-4o"
|
||||
)
|
||||
except Exception as e:
|
||||
print(f"Error: {e}")
|
||||
```
|
||||
|
||||
## Environment Variables
|
||||
|
||||
Set these environment variables for testing:
|
||||
|
||||
- `SUPERMEMORY_API_KEY` - Your Supermemory API key
|
||||
- `PROVIDER_API_KEY` - Your AI provider API key
|
||||
- `PROVIDER_NAME` - Provider name (default: "openai")
|
||||
- `PROVIDER_URL` - Custom provider URL (optional)
|
||||
- `MODEL_NAME` - Model to use (default: "gpt-4o-mini")
|
||||
- `SUPERMEMORY_BASE_URL` - Custom Supermemory base URL (optional)
|
||||
|
||||
## Development
|
||||
|
||||
### Setup
|
||||
|
||||
```bash
|
||||
# Install uv
|
||||
curl -LsSf https://astral.sh/uv/install.sh | sh
|
||||
|
||||
# Clone and setup
|
||||
git clone <repository-url>
|
||||
cd packages/openai-sdk-python
|
||||
uv sync --dev
|
||||
```
|
||||
|
||||
### Testing
|
||||
|
||||
```bash
|
||||
# Run tests
|
||||
uv run pytest
|
||||
|
||||
# Run with coverage
|
||||
uv run pytest --cov=supermemory_openai
|
||||
|
||||
# Run specific test file
|
||||
uv run pytest tests/test_infinite_chat.py
|
||||
```
|
||||
|
||||
### Type Checking
|
||||
|
||||
```bash
|
||||
uv run mypy src/supermemory_openai
|
||||
```
|
||||
|
||||
### Formatting
|
||||
|
||||
```bash
|
||||
uv run black src/ tests/
|
||||
uv run isort src/ tests/
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
MIT License - see LICENSE file for details.
|
||||
|
||||
## Links
|
||||
|
||||
- [Supermemory](https://supermemory.ai) - Infinite context memory platform
|
||||
- [OpenAI Python SDK](https://github.com/openai/openai-python) - Official OpenAI Python library
|
||||
- [Documentation](https://docs.supermemory.ai) - Full API documentation
|
||||
96
packages/openai-sdk-python/pyproject.toml
Normal file
96
packages/openai-sdk-python/pyproject.toml
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
[build-system]
|
||||
requires = ["hatchling"]
|
||||
build-backend = "hatchling.build"
|
||||
|
||||
[project]
|
||||
name = "supermemory-openai-sdk"
|
||||
version = "1.0.0"
|
||||
description = "OpenAI SDK utilities for supermemory"
|
||||
readme = "README.md"
|
||||
license = { text = "MIT" }
|
||||
keywords = ["openai", "supermemory", "ai", "memory"]
|
||||
classifiers = [
|
||||
"Development Status :: 3 - Alpha",
|
||||
"Intended Audience :: Developers",
|
||||
"License :: OSI Approved :: MIT License",
|
||||
"Programming Language :: Python :: 3",
|
||||
"Programming Language :: Python :: 3.8",
|
||||
"Programming Language :: Python :: 3.9",
|
||||
"Programming Language :: Python :: 3.10",
|
||||
"Programming Language :: Python :: 3.11",
|
||||
"Programming Language :: Python :: 3.12",
|
||||
"Topic :: Software Development :: Libraries :: Python Modules",
|
||||
"Topic :: Scientific/Engineering :: Artificial Intelligence",
|
||||
]
|
||||
requires-python = ">=3.8.1"
|
||||
dependencies = [
|
||||
"openai>=1.102.0",
|
||||
"supermemory>=3.0.0a28",
|
||||
"typing-extensions>=4.0.0",
|
||||
]
|
||||
|
||||
[dependency-groups]
|
||||
dev = [
|
||||
"black>=24.8.0",
|
||||
"flake8>=7.1.2",
|
||||
"isort>=5.13.2",
|
||||
"mypy>=1.14.1",
|
||||
"pytest>=8.3.5",
|
||||
"pytest-asyncio>=0.24.0",
|
||||
"python-dotenv>=1.0.1",
|
||||
]
|
||||
|
||||
|
||||
[project.urls]
|
||||
Homepage = "https://github.com/supermemoryai/supermemory"
|
||||
Repository = "https://github.com/supermemoryai/supermemory"
|
||||
Documentation = "https://docs.supermemory.ai"
|
||||
|
||||
[tool.hatch.build.targets.wheel]
|
||||
packages = ["src"]
|
||||
|
||||
[tool.black]
|
||||
line-length = 88
|
||||
target-version = ['py38']
|
||||
include = '\.pyi?$'
|
||||
extend-exclude = '''
|
||||
/(
|
||||
# directories
|
||||
\.eggs
|
||||
| \.git
|
||||
| \.hg
|
||||
| \.mypy_cache
|
||||
| \.tox
|
||||
| \.venv
|
||||
| build
|
||||
| dist
|
||||
)/
|
||||
'''
|
||||
|
||||
[tool.isort]
|
||||
profile = "black"
|
||||
multi_line_output = 3
|
||||
line_length = 88
|
||||
|
||||
[tool.mypy]
|
||||
python_version = "3.8"
|
||||
warn_return_any = true
|
||||
warn_unused_configs = true
|
||||
disallow_untyped_defs = true
|
||||
disallow_incomplete_defs = true
|
||||
check_untyped_defs = true
|
||||
disallow_untyped_decorators = true
|
||||
no_implicit_optional = true
|
||||
warn_redundant_casts = true
|
||||
warn_unused_ignores = true
|
||||
warn_no_return = true
|
||||
warn_unreachable = true
|
||||
strict_equality = true
|
||||
|
||||
[tool.pytest.ini_options]
|
||||
testpaths = ["tests"]
|
||||
python_files = ["test_*.py", "*_test.py"]
|
||||
python_classes = ["Test*"]
|
||||
python_functions = ["test_*"]
|
||||
addopts = "-v --tb=short"
|
||||
asyncio_mode = "auto"
|
||||
54
packages/openai-sdk-python/src/__init__.py
Normal file
54
packages/openai-sdk-python/src/__init__.py
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
"""Supermemory OpenAI SDK - Enhanced OpenAI Python SDK with infinite context."""
|
||||
|
||||
from .infinite_chat import (
|
||||
SupermemoryOpenAI,
|
||||
SupermemoryInfiniteChatConfig,
|
||||
SupermemoryInfiniteChatConfigWithProviderName,
|
||||
SupermemoryInfiniteChatConfigWithProviderUrl,
|
||||
ProviderName,
|
||||
PROVIDER_MAP,
|
||||
create_supermemory_openai,
|
||||
)
|
||||
|
||||
from .tools import (
|
||||
SupermemoryTools,
|
||||
SupermemoryToolsConfig,
|
||||
MemoryObject,
|
||||
MemorySearchResult,
|
||||
MemoryAddResult,
|
||||
SearchMemoriesTool,
|
||||
AddMemoryTool,
|
||||
MEMORY_TOOL_SCHEMAS,
|
||||
create_supermemory_tools,
|
||||
get_memory_tool_definitions,
|
||||
execute_memory_tool_calls,
|
||||
create_search_memories_tool,
|
||||
create_add_memory_tool,
|
||||
)
|
||||
|
||||
__version__ = "0.1.0"
|
||||
|
||||
__all__ = [
|
||||
# Infinite Chat
|
||||
"SupermemoryOpenAI",
|
||||
"SupermemoryInfiniteChatConfig",
|
||||
"SupermemoryInfiniteChatConfigWithProviderName",
|
||||
"SupermemoryInfiniteChatConfigWithProviderUrl",
|
||||
"ProviderName",
|
||||
"PROVIDER_MAP",
|
||||
"create_supermemory_openai",
|
||||
# Tools
|
||||
"SupermemoryTools",
|
||||
"SupermemoryToolsConfig",
|
||||
"MemoryObject",
|
||||
"MemorySearchResult",
|
||||
"MemoryAddResult",
|
||||
"SearchMemoriesTool",
|
||||
"AddMemoryTool",
|
||||
"MEMORY_TOOL_SCHEMAS",
|
||||
"create_supermemory_tools",
|
||||
"get_memory_tool_definitions",
|
||||
"execute_memory_tool_calls",
|
||||
"create_search_memories_tool",
|
||||
"create_add_memory_tool",
|
||||
]
|
||||
268
packages/openai-sdk-python/src/infinite_chat.py
Normal file
268
packages/openai-sdk-python/src/infinite_chat.py
Normal file
|
|
@ -0,0 +1,268 @@
|
|||
"""Enhanced OpenAI client with Supermemory infinite context integration."""
|
||||
|
||||
from typing import Dict, List, Optional, Union, overload, Unpack
|
||||
from typing_extensions import Literal
|
||||
|
||||
from openai import OpenAI, AsyncStream
|
||||
from openai.types.chat import (
|
||||
ChatCompletion,
|
||||
ChatCompletionMessageParam,
|
||||
ChatCompletionToolParam,
|
||||
ChatCompletionToolChoiceOptionParam,
|
||||
CompletionCreateParams,
|
||||
)
|
||||
|
||||
|
||||
# Provider URL mapping
|
||||
PROVIDER_MAP = {
|
||||
"openai": "https://api.openai.com/v1",
|
||||
"anthropic": "https://api.anthropic.com/v1",
|
||||
"openrouter": "https://openrouter.ai/api/v1",
|
||||
"deepinfra": "https://api.deepinfra.com/v1/openai",
|
||||
"groq": "https://api.groq.com/openai/v1",
|
||||
"google": "https://generativelanguage.googleapis.com/v1beta/openai",
|
||||
"cloudflare": "https://gateway.ai.cloudflare.com/v1/*/unlimited-context/openai",
|
||||
}
|
||||
|
||||
ProviderName = Literal[
|
||||
"openai", "anthropic", "openrouter", "deepinfra", "groq", "google", "cloudflare"
|
||||
]
|
||||
|
||||
|
||||
class SupermemoryInfiniteChatConfigBase:
|
||||
"""Base configuration for Supermemory infinite chat."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
provider_api_key: str,
|
||||
headers: Optional[Dict[str, str]] = None,
|
||||
):
|
||||
self.provider_api_key = provider_api_key
|
||||
self.headers = headers or {}
|
||||
|
||||
|
||||
class SupermemoryInfiniteChatConfigWithProviderName(SupermemoryInfiniteChatConfigBase):
|
||||
"""Configuration using a predefined provider name."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
provider_name: ProviderName,
|
||||
provider_api_key: str,
|
||||
headers: Optional[Dict[str, str]] = None,
|
||||
):
|
||||
super().__init__(provider_api_key, headers)
|
||||
self.provider_name = provider_name
|
||||
self.provider_url: None = None
|
||||
|
||||
|
||||
class SupermemoryInfiniteChatConfigWithProviderUrl(SupermemoryInfiniteChatConfigBase):
|
||||
"""Configuration using a custom provider URL."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
provider_url: str,
|
||||
provider_api_key: str,
|
||||
headers: Optional[Dict[str, str]] = None,
|
||||
):
|
||||
super().__init__(provider_api_key, headers)
|
||||
self.provider_url = provider_url
|
||||
self.provider_name: None = None
|
||||
|
||||
|
||||
SupermemoryInfiniteChatConfig = Union[
|
||||
SupermemoryInfiniteChatConfigWithProviderName,
|
||||
SupermemoryInfiniteChatConfigWithProviderUrl,
|
||||
]
|
||||
|
||||
|
||||
class SupermemoryOpenAI(OpenAI):
|
||||
"""Enhanced OpenAI client with supermemory integration.
|
||||
|
||||
Only chat completions are supported - all other OpenAI API endpoints are disabled.
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
supermemory_api_key: str,
|
||||
config: Optional[SupermemoryInfiniteChatConfig] = None,
|
||||
):
|
||||
"""Initialize the SupermemoryOpenAI client.
|
||||
|
||||
Args:
|
||||
supermemory_api_key: API key for Supermemory service
|
||||
config: Configuration for the AI provider
|
||||
"""
|
||||
# Determine base URL
|
||||
if config is None:
|
||||
base_url = "https://api.openai.com/v1"
|
||||
api_key = None
|
||||
headers = {}
|
||||
elif hasattr(config, "provider_name") and config.provider_name:
|
||||
base_url = PROVIDER_MAP[config.provider_name]
|
||||
api_key = config.provider_api_key
|
||||
headers = config.headers
|
||||
else:
|
||||
base_url = config.provider_url
|
||||
api_key = config.provider_api_key
|
||||
headers = config.headers
|
||||
|
||||
# Prepare default headers
|
||||
default_headers = {
|
||||
"x-supermemory-api-key": supermemory_api_key,
|
||||
**headers,
|
||||
}
|
||||
|
||||
# Initialize the parent OpenAI client
|
||||
super().__init__(
|
||||
api_key=api_key,
|
||||
base_url=base_url,
|
||||
default_headers=default_headers,
|
||||
)
|
||||
|
||||
self._supermemory_api_key = supermemory_api_key
|
||||
|
||||
# Disable unsupported endpoints
|
||||
self._disable_unsupported_endpoints()
|
||||
|
||||
def _disable_unsupported_endpoints(self) -> None:
|
||||
"""Disable all OpenAI endpoints except chat completions."""
|
||||
|
||||
def unsupported_error() -> None:
|
||||
raise RuntimeError(
|
||||
"Supermemory only supports chat completions. "
|
||||
"Use chat_completion() or chat.completions.create() instead."
|
||||
)
|
||||
|
||||
# List of endpoints to disable
|
||||
endpoints = [
|
||||
"embeddings",
|
||||
"fine_tuning",
|
||||
"images",
|
||||
"audio",
|
||||
"models",
|
||||
"moderations",
|
||||
"files",
|
||||
"batches",
|
||||
"uploads",
|
||||
"beta",
|
||||
]
|
||||
|
||||
# Override endpoints with error function
|
||||
for endpoint in endpoints:
|
||||
setattr(self, endpoint, property(lambda self: unsupported_error()))
|
||||
|
||||
async def create_chat_completion(
|
||||
self,
|
||||
**params: Unpack[CompletionCreateParams],
|
||||
) -> ChatCompletion:
|
||||
"""Create chat completions with infinite context support.
|
||||
|
||||
Args:
|
||||
**params: Parameters for chat completion
|
||||
|
||||
Returns:
|
||||
ChatCompletion response
|
||||
"""
|
||||
return await self.chat.completions.create(**params)
|
||||
|
||||
@overload
|
||||
async def chat_completion(
|
||||
self,
|
||||
messages: List[ChatCompletionMessageParam],
|
||||
*,
|
||||
model: Optional[str] = None,
|
||||
temperature: Optional[float] = None,
|
||||
max_tokens: Optional[int] = None,
|
||||
tools: Optional[List[ChatCompletionToolParam]] = None,
|
||||
tool_choice: Optional[ChatCompletionToolChoiceOptionParam] = None,
|
||||
stream: Literal[False] = False,
|
||||
**kwargs: Unpack[CompletionCreateParams],
|
||||
) -> ChatCompletion: ...
|
||||
|
||||
@overload
|
||||
async def chat_completion(
|
||||
self,
|
||||
messages: List[ChatCompletionMessageParam],
|
||||
*,
|
||||
model: Optional[str] = None,
|
||||
temperature: Optional[float] = None,
|
||||
max_tokens: Optional[int] = None,
|
||||
tools: Optional[List[ChatCompletionToolParam]] = None,
|
||||
tool_choice: Optional[ChatCompletionToolChoiceOptionParam] = None,
|
||||
stream: Literal[True],
|
||||
**kwargs: Unpack[CompletionCreateParams],
|
||||
) -> AsyncStream[ChatCompletion]: ...
|
||||
|
||||
async def chat_completion(
|
||||
self,
|
||||
messages: List[ChatCompletionMessageParam],
|
||||
*,
|
||||
model: Optional[str] = None,
|
||||
temperature: Optional[float] = None,
|
||||
max_tokens: Optional[int] = None,
|
||||
tools: Optional[List[ChatCompletionToolParam]] = None,
|
||||
tool_choice: Optional[ChatCompletionToolChoiceOptionParam] = None,
|
||||
stream: bool = False,
|
||||
**kwargs: Unpack[CompletionCreateParams],
|
||||
) -> Union[ChatCompletion, AsyncStream[ChatCompletion]]:
|
||||
"""Create chat completions with simplified interface.
|
||||
|
||||
Args:
|
||||
messages: List of chat messages
|
||||
model: Model to use (defaults to gpt-4o)
|
||||
temperature: Sampling temperature
|
||||
max_tokens: Maximum tokens to generate
|
||||
tools: Available tools for function calling
|
||||
tool_choice: Tool choice strategy
|
||||
stream: Whether to stream the response
|
||||
**kwargs: Additional parameters
|
||||
|
||||
Returns:
|
||||
ChatCompletion response or stream
|
||||
"""
|
||||
params: Dict[
|
||||
str,
|
||||
Union[
|
||||
str,
|
||||
List[ChatCompletionMessageParam],
|
||||
List[ChatCompletionToolParam],
|
||||
ChatCompletionToolChoiceOptionParam,
|
||||
bool,
|
||||
float,
|
||||
int,
|
||||
],
|
||||
] = {
|
||||
"model": model or "gpt-4o",
|
||||
"messages": messages,
|
||||
**kwargs,
|
||||
}
|
||||
|
||||
# Add optional parameters if provided
|
||||
if temperature is not None:
|
||||
params["temperature"] = temperature
|
||||
if max_tokens is not None:
|
||||
params["max_tokens"] = max_tokens
|
||||
if tools is not None:
|
||||
params["tools"] = tools
|
||||
if tool_choice is not None:
|
||||
params["tool_choice"] = tool_choice
|
||||
if stream is not None:
|
||||
params["stream"] = stream
|
||||
|
||||
return await self.chat.completions.create(**params)
|
||||
|
||||
|
||||
def create_supermemory_openai(
|
||||
supermemory_api_key: str,
|
||||
config: Optional[SupermemoryInfiniteChatConfig] = None,
|
||||
) -> SupermemoryOpenAI:
|
||||
"""Helper function to create a SupermemoryOpenAI instance.
|
||||
|
||||
Args:
|
||||
supermemory_api_key: API key for Supermemory service
|
||||
config: Configuration for the AI provider
|
||||
|
||||
Returns:
|
||||
SupermemoryOpenAI instance
|
||||
"""
|
||||
return SupermemoryOpenAI(supermemory_api_key, config)
|
||||
366
packages/openai-sdk-python/src/tools.py
Normal file
366
packages/openai-sdk-python/src/tools.py
Normal file
|
|
@ -0,0 +1,366 @@
|
|||
"""Supermemory tools for OpenAI function calling."""
|
||||
|
||||
import json
|
||||
from typing import Dict, List, Optional, Union, TypedDict
|
||||
|
||||
from openai.types.chat import (
|
||||
ChatCompletionMessageToolCall,
|
||||
ChatCompletionToolMessageParam,
|
||||
ChatCompletionToolParam,
|
||||
)
|
||||
import supermemory
|
||||
from supermemory.types import (
|
||||
MemoryAddResponse,
|
||||
MemoryGetResponse,
|
||||
SearchExecuteResponse,
|
||||
)
|
||||
from supermemory.types.search_execute_response import Result
|
||||
|
||||
|
||||
class SupermemoryToolsConfig(TypedDict, total=False):
|
||||
"""Configuration for Supermemory tools.
|
||||
|
||||
Only one of `project_id` or `container_tags` can be provided.
|
||||
"""
|
||||
|
||||
base_url: Optional[str]
|
||||
container_tags: Optional[List[str]]
|
||||
project_id: Optional[str]
|
||||
|
||||
|
||||
# Type aliases using inferred types from supermemory package
|
||||
MemoryObject = Union[MemoryGetResponse, MemoryAddResponse]
|
||||
|
||||
|
||||
class MemorySearchResult(TypedDict, total=False):
|
||||
"""Result type for memory search operations."""
|
||||
|
||||
success: bool
|
||||
results: Optional[List[Result]]
|
||||
count: Optional[int]
|
||||
error: Optional[str]
|
||||
|
||||
|
||||
class MemoryAddResult(TypedDict, total=False):
|
||||
"""Result type for memory add operations."""
|
||||
|
||||
success: bool
|
||||
memory: Optional[MemoryAddResponse]
|
||||
error: Optional[str]
|
||||
|
||||
|
||||
# Function schemas for OpenAI function calling
|
||||
MEMORY_TOOL_SCHEMAS = {
|
||||
"search_memories": {
|
||||
"name": "search_memories",
|
||||
"description": (
|
||||
"Search (recall) memories/details/information about the user or other facts or entities. Run when explicitly asked or when context about user's past choices would be helpful."
|
||||
),
|
||||
"parameters": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"information_to_get": {
|
||||
"type": "string",
|
||||
"description": "Terms to search for in the user's memories",
|
||||
},
|
||||
"include_full_docs": {
|
||||
"type": "boolean",
|
||||
"description": (
|
||||
"Whether to include the full document content in the response. "
|
||||
"Defaults to true for better AI context."
|
||||
),
|
||||
"default": True,
|
||||
},
|
||||
"limit": {
|
||||
"type": "number",
|
||||
"description": "Maximum number of results to return",
|
||||
"default": 10,
|
||||
},
|
||||
},
|
||||
"required": ["information_to_get"],
|
||||
},
|
||||
},
|
||||
"add_memory": {
|
||||
"name": "add_memory",
|
||||
"description": (
|
||||
"Add (remember) memories/details/information about the user or other facts or entities. Run when explicitly asked or when the user mentions any information generalizable beyond the context of the current conversation."
|
||||
),
|
||||
"parameters": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"memory": {
|
||||
"type": "string",
|
||||
"description": (
|
||||
"The text content of the memory to add. This should be a "
|
||||
"single sentence or a short paragraph."
|
||||
),
|
||||
},
|
||||
},
|
||||
"required": ["memory"],
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
class SupermemoryTools:
|
||||
"""Create memory tool handlers for OpenAI function calling."""
|
||||
|
||||
def __init__(self, api_key: str, config: Optional[SupermemoryToolsConfig] = None):
|
||||
"""Initialize SupermemoryTools.
|
||||
|
||||
Args:
|
||||
api_key: Supermemory API key
|
||||
config: Optional configuration
|
||||
"""
|
||||
config = config or {}
|
||||
|
||||
# Initialize Supermemory client
|
||||
client_kwargs = {"api_key": api_key}
|
||||
if config.get("base_url"):
|
||||
client_kwargs["base_url"] = config["base_url"]
|
||||
|
||||
self.client = supermemory.Supermemory(**client_kwargs)
|
||||
|
||||
# Set container tags
|
||||
if config.get("project_id"):
|
||||
self.container_tags = [f"sm_project_{config['project_id']}"]
|
||||
elif config.get("container_tags"):
|
||||
self.container_tags = config["container_tags"]
|
||||
else:
|
||||
self.container_tags = ["sm_project_default"]
|
||||
|
||||
def get_tool_definitions(self) -> List[ChatCompletionToolParam]:
|
||||
"""Get OpenAI function definitions for all memory tools.
|
||||
|
||||
Returns:
|
||||
List of ChatCompletionToolParam definitions
|
||||
"""
|
||||
return [
|
||||
{"type": "function", "function": MEMORY_TOOL_SCHEMAS["search_memories"]},
|
||||
{"type": "function", "function": MEMORY_TOOL_SCHEMAS["add_memory"]},
|
||||
]
|
||||
|
||||
async def execute_tool_call(self, tool_call: ChatCompletionMessageToolCall) -> str:
|
||||
"""Execute a tool call based on the function name and arguments.
|
||||
|
||||
Args:
|
||||
tool_call: The tool call from OpenAI
|
||||
|
||||
Returns:
|
||||
JSON string result
|
||||
"""
|
||||
function_name = tool_call.function.name
|
||||
args = json.loads(tool_call.function.arguments)
|
||||
|
||||
if function_name == "search_memories":
|
||||
result = await self.search_memories(**args)
|
||||
elif function_name == "add_memory":
|
||||
result = await self.add_memory(**args)
|
||||
else:
|
||||
result = {
|
||||
"success": False,
|
||||
"error": f"Unknown function: {function_name}",
|
||||
}
|
||||
|
||||
return json.dumps(result)
|
||||
|
||||
async def search_memories(
|
||||
self,
|
||||
information_to_get: str,
|
||||
include_full_docs: bool = True,
|
||||
limit: int = 10,
|
||||
) -> MemorySearchResult:
|
||||
"""Search memories.
|
||||
|
||||
Args:
|
||||
information_to_get: Terms to search for
|
||||
include_full_docs: Whether to include full document content
|
||||
limit: Maximum number of results
|
||||
|
||||
Returns:
|
||||
MemorySearchResult
|
||||
"""
|
||||
try:
|
||||
response: SearchExecuteResponse = await self.client.search.execute(
|
||||
q=information_to_get,
|
||||
container_tags=self.container_tags,
|
||||
limit=limit,
|
||||
chunk_threshold=0.6,
|
||||
include_full_docs=include_full_docs,
|
||||
)
|
||||
|
||||
return MemorySearchResult(
|
||||
success=True,
|
||||
results=response.results,
|
||||
count=len(response.results),
|
||||
)
|
||||
except Exception as error:
|
||||
return MemorySearchResult(
|
||||
success=False,
|
||||
error=str(error),
|
||||
)
|
||||
|
||||
async def add_memory(self, memory: str) -> MemoryAddResult:
|
||||
"""Add a memory.
|
||||
|
||||
Args:
|
||||
memory: The memory content to add
|
||||
|
||||
Returns:
|
||||
MemoryAddResult
|
||||
"""
|
||||
try:
|
||||
metadata: Dict[str, object] = {}
|
||||
|
||||
add_params = {
|
||||
"content": memory,
|
||||
"container_tags": self.container_tags,
|
||||
}
|
||||
if metadata:
|
||||
add_params["metadata"] = metadata
|
||||
|
||||
response: MemoryAddResponse = await self.client.memories.add(**add_params)
|
||||
|
||||
return MemoryAddResult(
|
||||
success=True,
|
||||
memory=response,
|
||||
)
|
||||
except Exception as error:
|
||||
return MemoryAddResult(
|
||||
success=False,
|
||||
error=str(error),
|
||||
)
|
||||
|
||||
|
||||
def create_supermemory_tools(
|
||||
api_key: str, config: Optional[SupermemoryToolsConfig] = None
|
||||
) -> SupermemoryTools:
|
||||
"""Helper function to create SupermemoryTools instance.
|
||||
|
||||
Args:
|
||||
api_key: Supermemory API key
|
||||
config: Optional configuration
|
||||
|
||||
Returns:
|
||||
SupermemoryTools instance
|
||||
"""
|
||||
return SupermemoryTools(api_key, config)
|
||||
|
||||
|
||||
def get_memory_tool_definitions() -> List[ChatCompletionToolParam]:
|
||||
"""Get OpenAI function definitions for memory tools.
|
||||
|
||||
Returns:
|
||||
List of ChatCompletionToolParam definitions
|
||||
"""
|
||||
return [
|
||||
{"type": "function", "function": MEMORY_TOOL_SCHEMAS["search_memories"]},
|
||||
{"type": "function", "function": MEMORY_TOOL_SCHEMAS["add_memory"]},
|
||||
]
|
||||
|
||||
|
||||
async def execute_memory_tool_calls(
|
||||
api_key: str,
|
||||
tool_calls: List[ChatCompletionMessageToolCall],
|
||||
config: Optional[SupermemoryToolsConfig] = None,
|
||||
) -> List[ChatCompletionToolMessageParam]:
|
||||
"""Execute tool calls from OpenAI function calling.
|
||||
|
||||
Args:
|
||||
api_key: Supermemory API key
|
||||
tool_calls: List of tool calls from OpenAI
|
||||
config: Optional configuration
|
||||
|
||||
Returns:
|
||||
List of tool message parameters
|
||||
"""
|
||||
tools = SupermemoryTools(api_key, config)
|
||||
|
||||
async def execute_single_call(
|
||||
tool_call: ChatCompletionMessageToolCall,
|
||||
) -> ChatCompletionToolMessageParam:
|
||||
result = await tools.execute_tool_call(tool_call)
|
||||
return ChatCompletionToolMessageParam(
|
||||
tool_call_id=tool_call.id,
|
||||
role="tool",
|
||||
content=result,
|
||||
)
|
||||
|
||||
# Execute all tool calls concurrently
|
||||
import asyncio
|
||||
|
||||
results = await asyncio.gather(
|
||||
*[execute_single_call(tool_call) for tool_call in tool_calls]
|
||||
)
|
||||
|
||||
return results
|
||||
|
||||
|
||||
# Individual tool creators for more granular control
|
||||
class SearchMemoriesTool:
|
||||
"""Individual search memories tool."""
|
||||
|
||||
def __init__(self, api_key: str, config: Optional[SupermemoryToolsConfig] = None):
|
||||
self.tools = SupermemoryTools(api_key, config)
|
||||
self.definition: ChatCompletionToolParam = {
|
||||
"type": "function",
|
||||
"function": MEMORY_TOOL_SCHEMAS["search_memories"],
|
||||
}
|
||||
|
||||
async def execute(
|
||||
self,
|
||||
information_to_get: str,
|
||||
include_full_docs: bool = True,
|
||||
limit: int = 10,
|
||||
) -> MemorySearchResult:
|
||||
"""Execute search memories."""
|
||||
return await self.tools.search_memories(
|
||||
information_to_get=information_to_get,
|
||||
include_full_docs=include_full_docs,
|
||||
limit=limit,
|
||||
)
|
||||
|
||||
|
||||
class AddMemoryTool:
|
||||
"""Individual add memory tool."""
|
||||
|
||||
def __init__(self, api_key: str, config: Optional[SupermemoryToolsConfig] = None):
|
||||
self.tools = SupermemoryTools(api_key, config)
|
||||
self.definition: ChatCompletionToolParam = {
|
||||
"type": "function",
|
||||
"function": MEMORY_TOOL_SCHEMAS["add_memory"],
|
||||
}
|
||||
|
||||
async def execute(self, memory: str) -> MemoryAddResult:
|
||||
"""Execute add memory."""
|
||||
return await self.tools.add_memory(memory=memory)
|
||||
|
||||
|
||||
def create_search_memories_tool(
|
||||
api_key: str, config: Optional[SupermemoryToolsConfig] = None
|
||||
) -> SearchMemoriesTool:
|
||||
"""Create individual search memories tool.
|
||||
|
||||
Args:
|
||||
api_key: Supermemory API key
|
||||
config: Optional configuration
|
||||
|
||||
Returns:
|
||||
SearchMemoriesTool instance
|
||||
"""
|
||||
return SearchMemoriesTool(api_key, config)
|
||||
|
||||
|
||||
def create_add_memory_tool(
|
||||
api_key: str, config: Optional[SupermemoryToolsConfig] = None
|
||||
) -> AddMemoryTool:
|
||||
"""Create individual add memory tool.
|
||||
|
||||
Args:
|
||||
api_key: Supermemory API key
|
||||
config: Optional configuration
|
||||
|
||||
Returns:
|
||||
AddMemoryTool instance
|
||||
"""
|
||||
return AddMemoryTool(api_key, config)
|
||||
1
packages/openai-sdk-python/tests/__init__.py
Normal file
1
packages/openai-sdk-python/tests/__init__.py
Normal file
|
|
@ -0,0 +1 @@
|
|||
# Test package
|
||||
387
packages/openai-sdk-python/tests/test_infinite_chat.py
Normal file
387
packages/openai-sdk-python/tests/test_infinite_chat.py
Normal file
|
|
@ -0,0 +1,387 @@
|
|||
"""Tests for infinite_chat module."""
|
||||
|
||||
import os
|
||||
import pytest
|
||||
from typing import List
|
||||
|
||||
from openai.types.chat import ChatCompletionMessageParam
|
||||
from ..src import (
|
||||
SupermemoryOpenAI,
|
||||
SupermemoryInfiniteChatConfigWithProviderName,
|
||||
SupermemoryInfiniteChatConfigWithProviderUrl,
|
||||
ProviderName,
|
||||
)
|
||||
|
||||
|
||||
# Test configuration
|
||||
PROVIDERS: List[ProviderName] = [
|
||||
"openai",
|
||||
"anthropic",
|
||||
"openrouter",
|
||||
"deepinfra",
|
||||
"groq",
|
||||
"google",
|
||||
"cloudflare",
|
||||
]
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def test_api_key() -> str:
|
||||
"""Get test Supermemory API key from environment."""
|
||||
api_key = os.getenv("SUPERMEMORY_API_KEY")
|
||||
if not api_key:
|
||||
pytest.skip("SUPERMEMORY_API_KEY environment variable is required for tests")
|
||||
return api_key
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def test_provider_api_key() -> str:
|
||||
"""Get test provider API key from environment."""
|
||||
api_key = os.getenv("PROVIDER_API_KEY")
|
||||
if not api_key:
|
||||
pytest.skip("PROVIDER_API_KEY environment variable is required for tests")
|
||||
return api_key
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def test_provider_name() -> ProviderName:
|
||||
"""Get test provider name from environment."""
|
||||
provider_name = os.getenv("PROVIDER_NAME", "openai")
|
||||
if provider_name not in PROVIDERS:
|
||||
pytest.fail(f"Invalid provider name: {provider_name}")
|
||||
return provider_name # type: ignore
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def test_provider_url() -> str:
|
||||
"""Get test provider URL from environment."""
|
||||
return os.getenv("PROVIDER_URL", "")
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def test_model_name() -> str:
|
||||
"""Get test model name from environment."""
|
||||
return os.getenv("MODEL_NAME", "gpt-4o-mini")
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def test_headers() -> dict:
|
||||
"""Get test headers."""
|
||||
return {"custom-header": "test-value"}
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def test_messages() -> List[List[ChatCompletionMessageParam]]:
|
||||
"""Test message sets."""
|
||||
return [
|
||||
[{"role": "user", "content": "Hello!"}],
|
||||
[
|
||||
{"role": "system", "content": "You are a helpful assistant."},
|
||||
{"role": "user", "content": "What is AI?"},
|
||||
],
|
||||
[
|
||||
{"role": "user", "content": "Tell me a joke"},
|
||||
{
|
||||
"role": "assistant",
|
||||
"content": "Why don't scientists trust atoms? Because they make up everything!",
|
||||
},
|
||||
{"role": "user", "content": "Tell me another one"},
|
||||
],
|
||||
]
|
||||
|
||||
|
||||
class TestClientCreation:
|
||||
"""Test client creation."""
|
||||
|
||||
def test_create_client_with_provider_name(
|
||||
self,
|
||||
test_api_key: str,
|
||||
test_provider_api_key: str,
|
||||
test_provider_name: ProviderName,
|
||||
test_headers: dict,
|
||||
):
|
||||
"""Test creating client with provider name configuration."""
|
||||
config = SupermemoryInfiniteChatConfigWithProviderName(
|
||||
provider_name=test_provider_name,
|
||||
provider_api_key=test_provider_api_key,
|
||||
headers=test_headers,
|
||||
)
|
||||
|
||||
client = SupermemoryOpenAI(test_api_key, config)
|
||||
|
||||
assert client is not None
|
||||
assert client.chat is not None
|
||||
|
||||
def test_create_client_with_openai_provider(
|
||||
self, test_api_key: str, test_provider_api_key: str, test_headers: dict
|
||||
):
|
||||
"""Test creating client with OpenAI provider configuration."""
|
||||
config = SupermemoryInfiniteChatConfigWithProviderName(
|
||||
provider_name="openai",
|
||||
provider_api_key=test_provider_api_key,
|
||||
headers=test_headers,
|
||||
)
|
||||
|
||||
client = SupermemoryOpenAI(test_api_key, config)
|
||||
|
||||
assert client is not None
|
||||
|
||||
def test_create_client_with_custom_provider_url(
|
||||
self, test_api_key: str, test_provider_api_key: str, test_headers: dict
|
||||
):
|
||||
"""Test creating client with custom provider URL."""
|
||||
custom_url = "https://custom-provider.com/v1"
|
||||
config = SupermemoryInfiniteChatConfigWithProviderUrl(
|
||||
provider_url=custom_url,
|
||||
provider_api_key=test_provider_api_key,
|
||||
headers=test_headers,
|
||||
)
|
||||
|
||||
client = SupermemoryOpenAI(test_api_key, config)
|
||||
|
||||
assert client is not None
|
||||
|
||||
|
||||
class TestChatCompletions:
|
||||
"""Test chat completions functionality."""
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_create_chat_completion_simple_message(
|
||||
self,
|
||||
test_api_key: str,
|
||||
test_provider_api_key: str,
|
||||
test_provider_name: ProviderName,
|
||||
test_model_name: str,
|
||||
test_messages: List[List[ChatCompletionMessageParam]],
|
||||
):
|
||||
"""Test creating chat completion with simple message."""
|
||||
config = SupermemoryInfiniteChatConfigWithProviderName(
|
||||
provider_name=test_provider_name,
|
||||
provider_api_key=test_provider_api_key,
|
||||
headers={},
|
||||
)
|
||||
|
||||
client = SupermemoryOpenAI(test_api_key, config)
|
||||
|
||||
result = await client.create_chat_completion(
|
||||
model=test_model_name,
|
||||
messages=test_messages[0], # "Hello!"
|
||||
)
|
||||
|
||||
assert result is not None
|
||||
assert hasattr(result, "choices")
|
||||
assert len(result.choices) > 0
|
||||
assert result.choices[0].message.content is not None
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_chat_completion_convenience_method(
|
||||
self,
|
||||
test_api_key: str,
|
||||
test_provider_api_key: str,
|
||||
test_provider_name: ProviderName,
|
||||
test_model_name: str,
|
||||
test_messages: List[List[ChatCompletionMessageParam]],
|
||||
):
|
||||
"""Test chat completion using convenience method."""
|
||||
config = SupermemoryInfiniteChatConfigWithProviderName(
|
||||
provider_name=test_provider_name,
|
||||
provider_api_key=test_provider_api_key,
|
||||
headers={},
|
||||
)
|
||||
|
||||
client = SupermemoryOpenAI(test_api_key, config)
|
||||
|
||||
result = await client.chat_completion(
|
||||
messages=test_messages[1], # System + user messages
|
||||
model=test_model_name,
|
||||
temperature=0.7,
|
||||
)
|
||||
|
||||
assert result is not None
|
||||
assert hasattr(result, "choices")
|
||||
assert len(result.choices) > 0
|
||||
assert result.choices[0].message.content is not None
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_handle_conversation_history(
|
||||
self,
|
||||
test_api_key: str,
|
||||
test_provider_api_key: str,
|
||||
test_provider_name: ProviderName,
|
||||
test_model_name: str,
|
||||
test_messages: List[List[ChatCompletionMessageParam]],
|
||||
):
|
||||
"""Test handling conversation history."""
|
||||
config = SupermemoryInfiniteChatConfigWithProviderName(
|
||||
provider_name=test_provider_name,
|
||||
provider_api_key=test_provider_api_key,
|
||||
headers={},
|
||||
)
|
||||
|
||||
client = SupermemoryOpenAI(test_api_key, config)
|
||||
|
||||
result = await client.chat_completion(
|
||||
messages=test_messages[2], # Multi-turn conversation
|
||||
model=test_model_name,
|
||||
)
|
||||
|
||||
assert result is not None
|
||||
assert hasattr(result, "choices")
|
||||
assert len(result.choices) > 0
|
||||
assert result.choices[0].message.content is not None
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_custom_headers(
|
||||
self,
|
||||
test_api_key: str,
|
||||
test_provider_api_key: str,
|
||||
test_provider_name: ProviderName,
|
||||
test_model_name: str,
|
||||
):
|
||||
"""Test working with custom headers."""
|
||||
config = SupermemoryInfiniteChatConfigWithProviderName(
|
||||
provider_name=test_provider_name,
|
||||
provider_api_key=test_provider_api_key,
|
||||
headers={"x-custom-header": "test-value"},
|
||||
)
|
||||
|
||||
client = SupermemoryOpenAI(test_api_key, config)
|
||||
|
||||
result = await client.chat_completion(
|
||||
messages=[{"role": "user", "content": "Hello"}],
|
||||
model=test_model_name,
|
||||
)
|
||||
|
||||
assert result is not None
|
||||
assert hasattr(result, "choices")
|
||||
|
||||
|
||||
class TestConfigurationValidation:
|
||||
"""Test configuration validation."""
|
||||
|
||||
def test_handle_empty_headers_object(
|
||||
self,
|
||||
test_api_key: str,
|
||||
test_provider_api_key: str,
|
||||
test_provider_name: ProviderName,
|
||||
):
|
||||
"""Test handling empty headers object."""
|
||||
config = SupermemoryInfiniteChatConfigWithProviderName(
|
||||
provider_name=test_provider_name,
|
||||
provider_api_key=test_provider_api_key,
|
||||
headers={},
|
||||
)
|
||||
|
||||
client = SupermemoryOpenAI(test_api_key, config)
|
||||
|
||||
assert client is not None
|
||||
|
||||
def test_handle_configuration_without_headers(
|
||||
self,
|
||||
test_api_key: str,
|
||||
test_provider_api_key: str,
|
||||
test_provider_name: ProviderName,
|
||||
):
|
||||
"""Test handling configuration without headers."""
|
||||
config = SupermemoryInfiniteChatConfigWithProviderName(
|
||||
provider_name=test_provider_name,
|
||||
provider_api_key=test_provider_api_key,
|
||||
)
|
||||
|
||||
client = SupermemoryOpenAI(test_api_key, config)
|
||||
|
||||
assert client is not None
|
||||
|
||||
def test_handle_different_api_keys(self):
|
||||
"""Test handling different API keys."""
|
||||
config = SupermemoryInfiniteChatConfigWithProviderName(
|
||||
provider_name="openai",
|
||||
provider_api_key="different-provider-key",
|
||||
)
|
||||
|
||||
client = SupermemoryOpenAI("different-sm-key", config)
|
||||
|
||||
assert client is not None
|
||||
|
||||
|
||||
class TestDisabledEndpoints:
|
||||
"""Test that non-chat endpoints are disabled."""
|
||||
|
||||
def test_disabled_endpoints_throw_errors(
|
||||
self, test_api_key: str, test_provider_api_key: str
|
||||
):
|
||||
"""Test that all disabled endpoints throw appropriate errors."""
|
||||
config = SupermemoryInfiniteChatConfigWithProviderName(
|
||||
provider_name="openai",
|
||||
provider_api_key=test_provider_api_key,
|
||||
)
|
||||
|
||||
client = SupermemoryOpenAI(test_api_key, config)
|
||||
|
||||
# Test that all disabled endpoints throw appropriate errors
|
||||
with pytest.raises(
|
||||
RuntimeError, match="Supermemory only supports chat completions"
|
||||
):
|
||||
_ = client.embeddings
|
||||
|
||||
with pytest.raises(
|
||||
RuntimeError, match="Supermemory only supports chat completions"
|
||||
):
|
||||
_ = client.fine_tuning
|
||||
|
||||
with pytest.raises(
|
||||
RuntimeError, match="Supermemory only supports chat completions"
|
||||
):
|
||||
_ = client.images
|
||||
|
||||
with pytest.raises(
|
||||
RuntimeError, match="Supermemory only supports chat completions"
|
||||
):
|
||||
_ = client.audio
|
||||
|
||||
with pytest.raises(
|
||||
RuntimeError, match="Supermemory only supports chat completions"
|
||||
):
|
||||
_ = client.models
|
||||
|
||||
with pytest.raises(
|
||||
RuntimeError, match="Supermemory only supports chat completions"
|
||||
):
|
||||
_ = client.moderations
|
||||
|
||||
with pytest.raises(
|
||||
RuntimeError, match="Supermemory only supports chat completions"
|
||||
):
|
||||
_ = client.files
|
||||
|
||||
with pytest.raises(
|
||||
RuntimeError, match="Supermemory only supports chat completions"
|
||||
):
|
||||
_ = client.batches
|
||||
|
||||
with pytest.raises(
|
||||
RuntimeError, match="Supermemory only supports chat completions"
|
||||
):
|
||||
_ = client.uploads
|
||||
|
||||
with pytest.raises(
|
||||
RuntimeError, match="Supermemory only supports chat completions"
|
||||
):
|
||||
_ = client.beta
|
||||
|
||||
def test_chat_completions_still_work(
|
||||
self, test_api_key: str, test_provider_api_key: str
|
||||
):
|
||||
"""Test that chat completions still work after disabling other endpoints."""
|
||||
config = SupermemoryInfiniteChatConfigWithProviderName(
|
||||
provider_name="openai",
|
||||
provider_api_key=test_provider_api_key,
|
||||
)
|
||||
|
||||
client = SupermemoryOpenAI(test_api_key, config)
|
||||
|
||||
# Chat completions should still be accessible
|
||||
assert client.chat is not None
|
||||
assert client.chat.completions is not None
|
||||
assert callable(client.create_chat_completion)
|
||||
assert callable(client.chat_completion)
|
||||
350
packages/openai-sdk-python/tests/test_tools.py
Normal file
350
packages/openai-sdk-python/tests/test_tools.py
Normal file
|
|
@ -0,0 +1,350 @@
|
|||
"""Tests for tools module."""
|
||||
|
||||
import os
|
||||
import pytest
|
||||
import json
|
||||
from typing import List
|
||||
|
||||
from openai.types.chat import ChatCompletionMessageToolCall
|
||||
from ..src import (
|
||||
SupermemoryTools,
|
||||
SupermemoryToolsConfig,
|
||||
SupermemoryOpenAI,
|
||||
SupermemoryInfiniteChatConfigWithProviderName,
|
||||
create_supermemory_tools,
|
||||
get_memory_tool_definitions,
|
||||
execute_memory_tool_calls,
|
||||
create_search_memories_tool,
|
||||
create_add_memory_tool,
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def test_api_key() -> str:
|
||||
"""Get test Supermemory API key from environment."""
|
||||
api_key = os.getenv("SUPERMEMORY_API_KEY")
|
||||
if not api_key:
|
||||
pytest.skip("SUPERMEMORY_API_KEY environment variable is required for tests")
|
||||
return api_key
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def test_provider_api_key() -> str:
|
||||
"""Get test provider API key from environment."""
|
||||
api_key = os.getenv("PROVIDER_API_KEY")
|
||||
if not api_key:
|
||||
pytest.skip("PROVIDER_API_KEY environment variable is required for tests")
|
||||
return api_key
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def test_base_url() -> str:
|
||||
"""Get test base URL from environment."""
|
||||
return os.getenv("SUPERMEMORY_BASE_URL", "")
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def test_model_name() -> str:
|
||||
"""Get test model name from environment."""
|
||||
return os.getenv("MODEL_NAME", "gpt-4o-mini")
|
||||
|
||||
|
||||
class TestToolInitialization:
|
||||
"""Test tool initialization."""
|
||||
|
||||
def test_create_tools_with_default_configuration(self, test_api_key: str):
|
||||
"""Test creating tools with default configuration."""
|
||||
config: SupermemoryToolsConfig = {}
|
||||
tools = SupermemoryTools(test_api_key, config)
|
||||
|
||||
assert tools is not None
|
||||
assert tools.get_tool_definitions() is not None
|
||||
assert len(tools.get_tool_definitions()) == 3
|
||||
|
||||
def test_create_tools_with_helper(self, test_api_key: str):
|
||||
"""Test creating tools with createSupermemoryTools helper."""
|
||||
tools = create_supermemory_tools(
|
||||
test_api_key,
|
||||
{
|
||||
"project_id": "test-project",
|
||||
},
|
||||
)
|
||||
|
||||
assert tools is not None
|
||||
assert tools.get_tool_definitions() is not None
|
||||
|
||||
def test_create_tools_with_custom_base_url(
|
||||
self, test_api_key: str, test_base_url: str
|
||||
):
|
||||
"""Test creating tools with custom baseUrl."""
|
||||
if not test_base_url:
|
||||
pytest.skip("SUPERMEMORY_BASE_URL not provided")
|
||||
|
||||
config: SupermemoryToolsConfig = {
|
||||
"base_url": test_base_url,
|
||||
}
|
||||
tools = SupermemoryTools(test_api_key, config)
|
||||
|
||||
assert tools is not None
|
||||
assert len(tools.get_tool_definitions()) == 3
|
||||
|
||||
def test_create_tools_with_project_id(self, test_api_key: str):
|
||||
"""Test creating tools with projectId configuration."""
|
||||
config: SupermemoryToolsConfig = {
|
||||
"project_id": "test-project-123",
|
||||
}
|
||||
tools = SupermemoryTools(test_api_key, config)
|
||||
|
||||
assert tools is not None
|
||||
assert len(tools.get_tool_definitions()) == 3
|
||||
|
||||
def test_create_tools_with_custom_container_tags(self, test_api_key: str):
|
||||
"""Test creating tools with custom container tags."""
|
||||
config: SupermemoryToolsConfig = {
|
||||
"container_tags": ["custom-tag-1", "custom-tag-2"],
|
||||
}
|
||||
tools = SupermemoryTools(test_api_key, config)
|
||||
|
||||
assert tools is not None
|
||||
assert len(tools.get_tool_definitions()) == 3
|
||||
|
||||
|
||||
class TestToolDefinitions:
|
||||
"""Test tool definitions."""
|
||||
|
||||
def test_return_proper_openai_function_definitions(self):
|
||||
"""Test returning proper OpenAI function definitions."""
|
||||
definitions = get_memory_tool_definitions()
|
||||
|
||||
assert definitions is not None
|
||||
assert len(definitions) == 3
|
||||
|
||||
# Check searchMemories
|
||||
search_tool = next(
|
||||
(d for d in definitions if d["function"]["name"] == "search_memories"), None
|
||||
)
|
||||
assert search_tool is not None
|
||||
assert search_tool["type"] == "function"
|
||||
assert "information_to_get" in search_tool["function"]["parameters"]["required"]
|
||||
|
||||
# Check addMemory
|
||||
add_tool = next(
|
||||
(d for d in definitions if d["function"]["name"] == "add_memory"), None
|
||||
)
|
||||
assert add_tool is not None
|
||||
assert add_tool["type"] == "function"
|
||||
assert "memory" in add_tool["function"]["parameters"]["required"]
|
||||
|
||||
def test_consistent_tool_definitions_from_class_and_helper(self, test_api_key: str):
|
||||
"""Test that tool definitions are consistent between class and helper."""
|
||||
tools = SupermemoryTools(test_api_key)
|
||||
class_definitions = tools.get_tool_definitions()
|
||||
helper_definitions = get_memory_tool_definitions()
|
||||
|
||||
assert class_definitions == helper_definitions
|
||||
|
||||
|
||||
class TestMemoryOperations:
|
||||
"""Test memory operations."""
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_search_memories(self, test_api_key: str, test_base_url: str):
|
||||
"""Test searching memories."""
|
||||
config: SupermemoryToolsConfig = {
|
||||
"project_id": "test-search",
|
||||
}
|
||||
if test_base_url:
|
||||
config["base_url"] = test_base_url
|
||||
|
||||
tools = SupermemoryTools(test_api_key, config)
|
||||
|
||||
result = await tools.search_memories(
|
||||
information_to_get="test preferences",
|
||||
limit=5,
|
||||
)
|
||||
|
||||
assert result is not None
|
||||
assert "success" in result
|
||||
assert isinstance(result["success"], bool)
|
||||
|
||||
if result["success"]:
|
||||
assert "results" in result
|
||||
assert "count" in result
|
||||
assert isinstance(result["count"], int)
|
||||
else:
|
||||
assert "error" in result
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_add_memory(self, test_api_key: str, test_base_url: str):
|
||||
"""Test adding memory."""
|
||||
config: SupermemoryToolsConfig = {
|
||||
"container_tags": ["test-add-memory"],
|
||||
}
|
||||
if test_base_url:
|
||||
config["base_url"] = test_base_url
|
||||
|
||||
tools = SupermemoryTools(test_api_key, config)
|
||||
|
||||
result = await tools.add_memory(
|
||||
memory="User prefers dark roast coffee in the morning - test memory"
|
||||
)
|
||||
|
||||
assert result is not None
|
||||
assert "success" in result
|
||||
assert isinstance(result["success"], bool)
|
||||
|
||||
if result["success"]:
|
||||
assert "memory" in result
|
||||
else:
|
||||
assert "error" in result
|
||||
|
||||
|
||||
class TestIndividualToolCreators:
|
||||
"""Test individual tool creators."""
|
||||
|
||||
def test_create_individual_search_tool(self, test_api_key: str):
|
||||
"""Test creating individual search tool."""
|
||||
search_tool = create_search_memories_tool(
|
||||
test_api_key,
|
||||
{
|
||||
"project_id": "test-individual",
|
||||
},
|
||||
)
|
||||
|
||||
assert search_tool is not None
|
||||
assert search_tool.definition is not None
|
||||
assert callable(search_tool.execute)
|
||||
assert search_tool.definition["function"]["name"] == "search_memories"
|
||||
|
||||
def test_create_individual_add_tool(self, test_api_key: str):
|
||||
"""Test creating individual add tool."""
|
||||
add_tool = create_add_memory_tool(
|
||||
test_api_key,
|
||||
{
|
||||
"project_id": "test-individual",
|
||||
},
|
||||
)
|
||||
|
||||
assert add_tool is not None
|
||||
assert add_tool.definition is not None
|
||||
assert callable(add_tool.execute)
|
||||
assert add_tool.definition["function"]["name"] == "add_memory"
|
||||
|
||||
|
||||
class TestOpenAIIntegration:
|
||||
"""Test OpenAI integration."""
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_work_with_supermemory_openai_for_function_calling(
|
||||
self,
|
||||
test_api_key: str,
|
||||
test_provider_api_key: str,
|
||||
test_model_name: str,
|
||||
test_base_url: str,
|
||||
):
|
||||
"""Test working with SupermemoryOpenAI for function calling."""
|
||||
client = SupermemoryOpenAI(
|
||||
test_api_key,
|
||||
SupermemoryInfiniteChatConfigWithProviderName(
|
||||
provider_name="openai",
|
||||
provider_api_key=test_provider_api_key,
|
||||
),
|
||||
)
|
||||
|
||||
tools_config: SupermemoryToolsConfig = {
|
||||
"project_id": "test-openai-integration",
|
||||
}
|
||||
if test_base_url:
|
||||
tools_config["base_url"] = test_base_url
|
||||
|
||||
tools = SupermemoryTools(test_api_key, tools_config)
|
||||
|
||||
response = await client.chat_completion(
|
||||
messages=[
|
||||
{
|
||||
"role": "system",
|
||||
"content": (
|
||||
"You are a helpful assistant with access to user memories. "
|
||||
"When the user asks you to remember something, use the add_memory tool."
|
||||
),
|
||||
},
|
||||
{
|
||||
"role": "user",
|
||||
"content": "Please remember that I prefer tea over coffee",
|
||||
},
|
||||
],
|
||||
model=test_model_name,
|
||||
tools=tools.get_tool_definitions(),
|
||||
)
|
||||
|
||||
assert response is not None
|
||||
assert hasattr(response, "choices")
|
||||
|
||||
choice = response.choices[0]
|
||||
assert choice.message is not None
|
||||
|
||||
# If the model decided to use function calling, test the execution
|
||||
if hasattr(choice.message, "tool_calls") and choice.message.tool_calls:
|
||||
tool_results = await execute_memory_tool_calls(
|
||||
test_api_key,
|
||||
choice.message.tool_calls,
|
||||
tools_config,
|
||||
)
|
||||
|
||||
assert tool_results is not None
|
||||
assert len(tool_results) == len(choice.message.tool_calls)
|
||||
|
||||
for result in tool_results:
|
||||
assert result["role"] == "tool"
|
||||
assert "content" in result
|
||||
assert "tool_call_id" in result
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_handle_multiple_tool_calls(
|
||||
self, test_api_key: str, test_base_url: str
|
||||
):
|
||||
"""Test handling multiple tool calls."""
|
||||
tools_config: SupermemoryToolsConfig = {
|
||||
"container_tags": ["test-multi-tools"],
|
||||
}
|
||||
if test_base_url:
|
||||
tools_config["base_url"] = test_base_url
|
||||
|
||||
# Simulate tool calls (normally these would come from OpenAI)
|
||||
mock_tool_calls: List[ChatCompletionMessageToolCall] = [
|
||||
ChatCompletionMessageToolCall(
|
||||
id="call_1",
|
||||
type="function",
|
||||
function={
|
||||
"name": "search_memories",
|
||||
"arguments": json.dumps({"information_to_get": "preferences"}),
|
||||
},
|
||||
),
|
||||
ChatCompletionMessageToolCall(
|
||||
id="call_2",
|
||||
type="function",
|
||||
function={
|
||||
"name": "add_memory",
|
||||
"arguments": json.dumps(
|
||||
{"memory": "Test memory for multiple calls"}
|
||||
),
|
||||
},
|
||||
),
|
||||
]
|
||||
|
||||
results = await execute_memory_tool_calls(
|
||||
test_api_key, mock_tool_calls, tools_config
|
||||
)
|
||||
|
||||
assert results is not None
|
||||
assert len(results) == 2
|
||||
|
||||
assert results[0]["tool_call_id"] == "call_1"
|
||||
assert results[1]["tool_call_id"] == "call_2"
|
||||
|
||||
for result in results:
|
||||
assert result["role"] == "tool"
|
||||
assert "content" in result
|
||||
|
||||
content = json.loads(result["content"])
|
||||
assert "success" in content
|
||||
1313
packages/openai-sdk-python/uv.lock
generated
Normal file
1313
packages/openai-sdk-python/uv.lock
generated
Normal file
File diff suppressed because it is too large
Load diff
5
packages/openai-sdk-ts/.npmignore
Normal file
5
packages/openai-sdk-ts/.npmignore
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
src/
|
||||
.turbo/
|
||||
.env
|
||||
tsdown.config.ts
|
||||
tsconfig.json
|
||||
314
packages/openai-sdk-ts/README.md
Normal file
314
packages/openai-sdk-ts/README.md
Normal file
|
|
@ -0,0 +1,314 @@
|
|||
# supermemory OpenAI SDK Utilities
|
||||
|
||||
OpenAI JS/TS SDK utilities for supermemory
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
npm install @supermemory/openai-sdk
|
||||
# or
|
||||
bun add @supermemory/openai-sdk
|
||||
# or
|
||||
pnpm add @supermemory/openai-sdk
|
||||
# or
|
||||
yarn add @supermemory/openai-sdk
|
||||
```
|
||||
|
||||
## Features
|
||||
|
||||
Choose **one** of the following approaches (they cannot be used together):
|
||||
|
||||
- **Infinite Chat Client**: Enhanced OpenAI client with unlimited context support
|
||||
- **Memory Tools**: Search, add, and fetch memories from supermemory using OpenAI function calling
|
||||
|
||||
## Infinite Chat Client
|
||||
|
||||
The infinite chat client provides an enhanced OpenAI client with supermemory's context management.
|
||||
|
||||
```typescript
|
||||
import { SupermemoryOpenAI } from '@supermemory/openai-sdk'
|
||||
|
||||
// Using a named provider
|
||||
const client = new SupermemoryOpenAI('your-supermemory-api-key', {
|
||||
providerName: 'openai',
|
||||
providerApiKey: 'your-openai-api-key',
|
||||
headers: {
|
||||
// Optional additional headers
|
||||
}
|
||||
})
|
||||
|
||||
// Using a custom provider URL
|
||||
const client = new SupermemoryOpenAI('your-supermemory-api-key', {
|
||||
providerUrl: 'https://your-custom-provider.com/v1',
|
||||
providerApiKey: 'your-provider-api-key',
|
||||
headers: {
|
||||
// Optional additional headers
|
||||
}
|
||||
})
|
||||
|
||||
const response = await client.chat.completions.create({
|
||||
model: 'gpt-4o',
|
||||
messages: [
|
||||
{ role: 'user', content: 'Hello, how are you?' }
|
||||
]
|
||||
})
|
||||
```
|
||||
|
||||
### Complete Infinite Chat Example
|
||||
|
||||
```typescript
|
||||
import { SupermemoryOpenAI } from '@supermemory/openai-sdk'
|
||||
|
||||
const supermemoryApiKey = process.env.SUPERMEMORY_API_KEY!
|
||||
const openaiApiKey = process.env.OPENAI_API_KEY!
|
||||
|
||||
// Initialize infinite chat client
|
||||
const client = new SupermemoryOpenAI(supermemoryApiKey, {
|
||||
providerName: 'openai',
|
||||
providerApiKey: openaiApiKey
|
||||
})
|
||||
|
||||
async function chat(userMessage: string) {
|
||||
const response = await client.chatCompletion([
|
||||
{
|
||||
role: 'system',
|
||||
content: 'You are a helpful assistant with unlimited context.'
|
||||
},
|
||||
{
|
||||
role: 'user',
|
||||
content: userMessage
|
||||
}
|
||||
], {
|
||||
model: 'gpt-4o'
|
||||
})
|
||||
|
||||
return response.choices[0].message.content
|
||||
}
|
||||
```
|
||||
|
||||
### Configuration
|
||||
|
||||
```typescript
|
||||
// Option 1: Use a named provider
|
||||
interface ConfigWithProviderName {
|
||||
providerName: 'openai' | 'anthropic' | 'openrouter' | 'deepinfra' | 'groq' | 'google' | 'cloudflare'
|
||||
providerApiKey: string
|
||||
headers?: Record<string, string>
|
||||
}
|
||||
|
||||
// Option 2: Use a custom provider URL
|
||||
interface ConfigWithProviderUrl {
|
||||
providerUrl: string
|
||||
providerApiKey: string
|
||||
headers?: Record<string, string>
|
||||
}
|
||||
```
|
||||
|
||||
## Memory Tools
|
||||
|
||||
supermemory tools allow OpenAI function calling to interact with user memories for enhanced context and personalization.
|
||||
|
||||
```typescript
|
||||
import { SupermemoryTools, executeMemoryToolCalls } from '@supermemory/openai-sdk'
|
||||
import OpenAI from 'openai'
|
||||
|
||||
const openai = new OpenAI({ apiKey: 'your-openai-api-key' })
|
||||
|
||||
const response = await openai.chat.completions.create({
|
||||
model: 'gpt-4o',
|
||||
messages: [
|
||||
{ role: 'user', content: 'What do you remember about my preferences?' }
|
||||
],
|
||||
tools: new SupermemoryTools('your-supermemory-api-key', {
|
||||
// Optional: specify a base URL for self-hosted instances
|
||||
baseUrl: 'https://api.supermemory.com',
|
||||
|
||||
// Use either projectId OR containerTags, not both
|
||||
projectId: 'your-project-id',
|
||||
// OR
|
||||
containerTags: ['tag1', 'tag2']
|
||||
}).getToolDefinitions()
|
||||
})
|
||||
```
|
||||
|
||||
### Complete Memory Tools Example
|
||||
|
||||
```typescript
|
||||
import { SupermemoryTools, executeMemoryToolCalls } from '@supermemory/openai-sdk'
|
||||
import OpenAI from 'openai'
|
||||
|
||||
const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY! })
|
||||
const supermemoryApiKey = process.env.SUPERMEMORY_API_KEY!
|
||||
|
||||
async function chatWithTools(userMessage: string) {
|
||||
const tools = new SupermemoryTools(supermemoryApiKey, {
|
||||
projectId: 'my-project'
|
||||
})
|
||||
|
||||
const response = await openai.chat.completions.create({
|
||||
model: 'gpt-4o',
|
||||
messages: [
|
||||
{
|
||||
role: 'system',
|
||||
content: 'You are a helpful assistant with access to user memories.'
|
||||
},
|
||||
{
|
||||
role: 'user',
|
||||
content: userMessage
|
||||
}
|
||||
],
|
||||
tools: tools.getToolDefinitions()
|
||||
})
|
||||
|
||||
// Handle tool calls if present
|
||||
if (response.choices[0].message.tool_calls) {
|
||||
const toolResults = await executeMemoryToolCalls(
|
||||
supermemoryApiKey,
|
||||
response.choices[0].message.tool_calls,
|
||||
{ projectId: 'my-project' }
|
||||
)
|
||||
|
||||
// Continue conversation with tool results...
|
||||
}
|
||||
|
||||
return response.choices[0].message.content
|
||||
}
|
||||
```
|
||||
|
||||
### Configuration
|
||||
|
||||
```typescript
|
||||
interface SupermemoryToolsConfig {
|
||||
// Optional: Base URL for API calls (default: https://api.supermemory.com)
|
||||
baseUrl?: string
|
||||
|
||||
// Container tags for organizing memories (cannot be used with projectId)
|
||||
containerTags?: string[]
|
||||
|
||||
// Project ID for scoping memories (cannot be used with containerTags)
|
||||
projectId?: string
|
||||
}
|
||||
```
|
||||
|
||||
### Self-Hosted supermemory
|
||||
|
||||
If you're running a self-hosted supermemory instance:
|
||||
|
||||
```typescript
|
||||
const tools = new SupermemoryTools('your-api-key', {
|
||||
baseUrl: 'https://your-supermemory-instance.com',
|
||||
containerTags: ['production', 'user-memories']
|
||||
})
|
||||
```
|
||||
|
||||
### Available Tools
|
||||
|
||||
##### Search Memories
|
||||
|
||||
Search through user memories using semantic matching.
|
||||
|
||||
```typescript
|
||||
const searchResult = await tools.searchMemories({
|
||||
informationToGet: 'user preferences about coffee'
|
||||
})
|
||||
```
|
||||
|
||||
##### Add Memory
|
||||
|
||||
Add new memories to the user's memory store.
|
||||
|
||||
```typescript
|
||||
const addResult = await tools.addMemory({
|
||||
memory: 'User prefers dark roast coffee in the morning'
|
||||
})
|
||||
```
|
||||
|
||||
##### Fetch Memory
|
||||
|
||||
Retrieve a specific memory by its ID.
|
||||
|
||||
```typescript
|
||||
const fetchResult = await tools.fetchMemory({
|
||||
memoryId: 'memory-id-123'
|
||||
})
|
||||
```
|
||||
|
||||
### Using Individual Tools
|
||||
|
||||
For more flexibility, you can import and use individual tools:
|
||||
|
||||
```typescript
|
||||
import {
|
||||
createSearchMemoriesTool,
|
||||
createAddMemoryTool,
|
||||
createFetchMemoryTool
|
||||
} from '@supermemory/openai-sdk'
|
||||
|
||||
const searchTool = createSearchMemoriesTool('your-api-key', {
|
||||
projectId: 'your-project-id'
|
||||
})
|
||||
|
||||
// Use only the search tool
|
||||
const response = await openai.chat.completions.create({
|
||||
model: 'gpt-4o',
|
||||
messages: [...],
|
||||
tools: [searchTool.definition]
|
||||
})
|
||||
```
|
||||
|
||||
### Error Handling
|
||||
|
||||
All tool executions return a result object with a `success` field:
|
||||
|
||||
```typescript
|
||||
const result = await tools.searchMemories({
|
||||
informationToGet: 'user preferences'
|
||||
})
|
||||
|
||||
if (result.success) {
|
||||
console.log('Found memories:', result.results)
|
||||
console.log('Total count:', result.count)
|
||||
} else {
|
||||
console.error('Error searching memories:', result.error)
|
||||
}
|
||||
```
|
||||
|
||||
## Development
|
||||
|
||||
### Running Tests
|
||||
|
||||
```bash
|
||||
# Run all tests
|
||||
bun test
|
||||
|
||||
# Run tests in watch mode
|
||||
bun test --watch
|
||||
```
|
||||
|
||||
#### Environment Variables for Tests
|
||||
|
||||
All tests require API keys to run. Copy `.env.example` to `.env` and set the required values:
|
||||
|
||||
```bash
|
||||
cp .env.example .env
|
||||
```
|
||||
|
||||
**Required:**
|
||||
- `SUPERMEMORY_API_KEY`: Your Supermemory API key
|
||||
- `PROVIDER_API_KEY`: Your AI provider API key (OpenAI, etc.)
|
||||
|
||||
**Optional:**
|
||||
- `SUPERMEMORY_BASE_URL`: Custom Supermemory base URL (defaults to `https://api.supermemory.ai`)
|
||||
- `PROVIDER_NAME`: Provider name (defaults to `openai`) - one of: `openai`, `anthropic`, `openrouter`, `deepinfra`, `groq`, `google`, `cloudflare`
|
||||
- `PROVIDER_URL`: Custom provider URL (use instead of `PROVIDER_NAME`)
|
||||
- `MODEL_NAME`: Model to use in tests (defaults to `gpt-4o-mini`)
|
||||
|
||||
Tests will fail if required API keys are not provided.
|
||||
|
||||
## License
|
||||
|
||||
MIT
|
||||
|
||||
## Support
|
||||
|
||||
Email our [24/7 Founder/CEO/Support Executive](mailto:dhravya@supermemory.com)
|
||||
46
packages/openai-sdk-ts/package.json
Normal file
46
packages/openai-sdk-ts/package.json
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
{
|
||||
"name": "@supermemory/openai-sdk",
|
||||
"version": "1.0.0",
|
||||
"type": "module",
|
||||
"description": "OpenAI SDK utilities for supermemory",
|
||||
"scripts": {
|
||||
"build": "tsdown",
|
||||
"dev": "tsdown --watch",
|
||||
"check-types": "tsc --noEmit",
|
||||
"test": "vitest",
|
||||
"test:watch": "vitest --watch"
|
||||
},
|
||||
"dependencies": {
|
||||
"openai": "^4.104.0",
|
||||
"supermemory": "^3.0.0-alpha.26",
|
||||
"zod": "^4.1.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@total-typescript/tsconfig": "^1.0.4",
|
||||
"@types/bun": "^1.2.21",
|
||||
"dotenv": "^16.6.1",
|
||||
"tsdown": "^0.14.2",
|
||||
"typescript": "^5.9.2",
|
||||
"vitest": "^3.2.4"
|
||||
},
|
||||
"main": "./dist/index.js",
|
||||
"module": "./dist/index.js",
|
||||
"types": "./dist/index.d.ts",
|
||||
"exports": {
|
||||
".": "./dist/index.js",
|
||||
"./package.json": "./package.json"
|
||||
},
|
||||
"repository": {
|
||||
"url": "https://github.com/supermemoryai/supermemory",
|
||||
"directory": "packages/openai-sdk-ts"
|
||||
},
|
||||
"keywords": [
|
||||
"openai",
|
||||
"typescript",
|
||||
"supermemory",
|
||||
"ai",
|
||||
"memory",
|
||||
"context"
|
||||
],
|
||||
"license": "MIT"
|
||||
}
|
||||
2
packages/openai-sdk-ts/src/index.ts
Normal file
2
packages/openai-sdk-ts/src/index.ts
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
export * from "./infinite-chat"
|
||||
export * from "./tools"
|
||||
338
packages/openai-sdk-ts/src/infinite-chat.test.ts
Normal file
338
packages/openai-sdk-ts/src/infinite-chat.test.ts
Normal file
|
|
@ -0,0 +1,338 @@
|
|||
import { describe, expect, it } from "vitest"
|
||||
import z from "zod"
|
||||
import type OpenAI from "openai"
|
||||
import {
|
||||
SupermemoryOpenAI,
|
||||
type SupermemoryInfiniteChatConfig,
|
||||
} from "./infinite-chat"
|
||||
|
||||
import "dotenv/config"
|
||||
|
||||
const providers = z.enum([
|
||||
"openai",
|
||||
"anthropic",
|
||||
"openrouter",
|
||||
"deepinfra",
|
||||
"groq",
|
||||
"google",
|
||||
"cloudflare",
|
||||
] satisfies SupermemoryInfiniteChatConfig["providerName"][])
|
||||
|
||||
describe("SupermemoryOpenAI", () => {
|
||||
// Required API keys - tests will fail if not provided
|
||||
const testApiKey = process.env.SUPERMEMORY_API_KEY
|
||||
const testProviderApiKey = process.env.PROVIDER_API_KEY
|
||||
|
||||
if (!testApiKey) {
|
||||
throw new Error(
|
||||
"SUPERMEMORY_API_KEY environment variable is required for tests",
|
||||
)
|
||||
}
|
||||
if (!testProviderApiKey) {
|
||||
throw new Error(
|
||||
"PROVIDER_API_KEY environment variable is required for tests",
|
||||
)
|
||||
}
|
||||
|
||||
// Optional configuration with defaults
|
||||
const testProviderName = providers.parse(
|
||||
process.env.PROVIDER_NAME ?? "openai",
|
||||
)
|
||||
const testProviderUrl = process.env.PROVIDER_URL
|
||||
const testModelName = process.env.MODEL_NAME || "gpt-4o-mini"
|
||||
const testHeaders = { "custom-header": "test-value" }
|
||||
|
||||
// Validate provider configuration - either name OR URL, not both
|
||||
if (testProviderUrl && process.env.PROVIDER_NAME) {
|
||||
throw new Error(
|
||||
"Cannot specify both PROVIDER_NAME and PROVIDER_URL - use one or the other",
|
||||
)
|
||||
}
|
||||
|
||||
// Test prompts
|
||||
const testMessages: OpenAI.Chat.Completions.ChatCompletionMessageParam[][] = [
|
||||
[{ role: "user", content: "Hello!" }],
|
||||
[
|
||||
{ role: "system", content: "You are a helpful assistant." },
|
||||
{ role: "user", content: "What is AI?" },
|
||||
],
|
||||
[
|
||||
{ role: "user", content: "Tell me a joke" },
|
||||
{
|
||||
role: "assistant",
|
||||
content:
|
||||
"Why don't scientists trust atoms? Because they make up everything!",
|
||||
},
|
||||
{ role: "user", content: "Tell me another one" },
|
||||
],
|
||||
]
|
||||
|
||||
describe("client creation", () => {
|
||||
it("should create client with SupermemoryOpenAI class", () => {
|
||||
const config: SupermemoryInfiniteChatConfig = testProviderUrl
|
||||
? {
|
||||
providerUrl: testProviderUrl,
|
||||
providerApiKey: testProviderApiKey,
|
||||
headers: testHeaders,
|
||||
}
|
||||
: {
|
||||
providerName: testProviderName,
|
||||
providerApiKey: testProviderApiKey,
|
||||
headers: testHeaders,
|
||||
}
|
||||
|
||||
const client = new SupermemoryOpenAI(testApiKey, config)
|
||||
|
||||
expect(client).toBeDefined()
|
||||
expect(client.chat).toBeDefined()
|
||||
})
|
||||
|
||||
it("should create client with openai provider configuration", () => {
|
||||
const config: SupermemoryInfiniteChatConfig = {
|
||||
providerName: "openai",
|
||||
providerApiKey: testProviderApiKey,
|
||||
headers: testHeaders,
|
||||
}
|
||||
|
||||
const client = new SupermemoryOpenAI(testApiKey, config)
|
||||
|
||||
expect(client).toBeDefined()
|
||||
})
|
||||
|
||||
it("should create client with custom provider URL", () => {
|
||||
const customUrl = "https://custom-provider.com/v1"
|
||||
const config: SupermemoryInfiniteChatConfig = {
|
||||
providerUrl: customUrl,
|
||||
providerApiKey: testProviderApiKey,
|
||||
headers: testHeaders,
|
||||
}
|
||||
|
||||
const client = new SupermemoryOpenAI(testApiKey, config)
|
||||
|
||||
expect(client).toBeDefined()
|
||||
})
|
||||
})
|
||||
|
||||
describe("chat completions", () => {
|
||||
it("should create chat completion with simple message", async () => {
|
||||
const config: SupermemoryInfiniteChatConfig = testProviderUrl
|
||||
? {
|
||||
providerUrl: testProviderUrl,
|
||||
providerApiKey: testProviderApiKey,
|
||||
headers: {},
|
||||
}
|
||||
: {
|
||||
providerName: testProviderName,
|
||||
providerApiKey: testProviderApiKey,
|
||||
headers: {},
|
||||
}
|
||||
|
||||
const client = new SupermemoryOpenAI(testApiKey, config)
|
||||
|
||||
const result = await client.createChatCompletion({
|
||||
model: testModelName,
|
||||
messages: testMessages[0]!, // "Hello!"
|
||||
})
|
||||
|
||||
expect(result).toBeDefined()
|
||||
expect("choices" in result).toBe(true)
|
||||
if ("choices" in result) {
|
||||
expect(result.choices).toBeDefined()
|
||||
expect(result.choices.length).toBeGreaterThan(0)
|
||||
expect(result.choices[0]!.message.content).toBeDefined()
|
||||
}
|
||||
})
|
||||
|
||||
it("should create chat completion using convenience method", async () => {
|
||||
const config: SupermemoryInfiniteChatConfig = testProviderUrl
|
||||
? {
|
||||
providerUrl: testProviderUrl,
|
||||
providerApiKey: testProviderApiKey,
|
||||
headers: {},
|
||||
}
|
||||
: {
|
||||
providerName: testProviderName,
|
||||
providerApiKey: testProviderApiKey,
|
||||
headers: {},
|
||||
}
|
||||
|
||||
const client = new SupermemoryOpenAI(testApiKey, config)
|
||||
|
||||
const result = await client.chatCompletion(testMessages[1]!, {
|
||||
model: testModelName,
|
||||
temperature: 0.7,
|
||||
})
|
||||
|
||||
expect(result).toBeDefined()
|
||||
expect("choices" in result).toBe(true)
|
||||
if ("choices" in result) {
|
||||
expect(result.choices).toBeDefined()
|
||||
expect(result.choices.length).toBeGreaterThan(0)
|
||||
expect(result.choices[0]!.message.content).toBeDefined()
|
||||
}
|
||||
})
|
||||
|
||||
it("should handle conversation history", async () => {
|
||||
const config: SupermemoryInfiniteChatConfig = testProviderUrl
|
||||
? {
|
||||
providerUrl: testProviderUrl,
|
||||
providerApiKey: testProviderApiKey,
|
||||
headers: {},
|
||||
}
|
||||
: {
|
||||
providerName: testProviderName,
|
||||
providerApiKey: testProviderApiKey,
|
||||
headers: {},
|
||||
}
|
||||
|
||||
const client = new SupermemoryOpenAI(testApiKey, config)
|
||||
|
||||
const result = await client.chatCompletion(testMessages[2]!, {
|
||||
model: testModelName,
|
||||
})
|
||||
|
||||
expect(result).toBeDefined()
|
||||
expect("choices" in result).toBe(true)
|
||||
if ("choices" in result) {
|
||||
expect(result.choices).toBeDefined()
|
||||
expect(result.choices.length).toBeGreaterThan(0)
|
||||
expect(result.choices[0]!.message.content).toBeDefined()
|
||||
}
|
||||
})
|
||||
|
||||
it("should work with custom headers", async () => {
|
||||
const config: SupermemoryInfiniteChatConfig = testProviderUrl
|
||||
? {
|
||||
providerUrl: testProviderUrl,
|
||||
providerApiKey: testProviderApiKey,
|
||||
headers: {
|
||||
"x-custom-header": "test-value",
|
||||
},
|
||||
}
|
||||
: {
|
||||
providerName: testProviderName,
|
||||
providerApiKey: testProviderApiKey,
|
||||
headers: {
|
||||
"x-custom-header": "test-value",
|
||||
},
|
||||
}
|
||||
|
||||
const client = new SupermemoryOpenAI(testApiKey, config)
|
||||
|
||||
const result = await client.chatCompletion(
|
||||
[{ role: "user", content: "Hello" }],
|
||||
{
|
||||
model: testModelName,
|
||||
},
|
||||
)
|
||||
|
||||
expect(result).toBeDefined()
|
||||
expect("choices" in result).toBe(true)
|
||||
})
|
||||
})
|
||||
|
||||
describe("configuration validation", () => {
|
||||
it("should handle empty headers object", () => {
|
||||
const config: SupermemoryInfiniteChatConfig = testProviderUrl
|
||||
? {
|
||||
providerUrl: testProviderUrl,
|
||||
providerApiKey: testProviderApiKey,
|
||||
headers: {},
|
||||
}
|
||||
: {
|
||||
providerName: testProviderName,
|
||||
providerApiKey: testProviderApiKey,
|
||||
headers: {},
|
||||
}
|
||||
|
||||
const client = new SupermemoryOpenAI(testApiKey, config)
|
||||
|
||||
expect(client).toBeDefined()
|
||||
})
|
||||
|
||||
it("should handle configuration without headers", () => {
|
||||
const config: SupermemoryInfiniteChatConfig = testProviderUrl
|
||||
? {
|
||||
providerUrl: testProviderUrl,
|
||||
providerApiKey: testProviderApiKey,
|
||||
}
|
||||
: {
|
||||
providerName: testProviderName,
|
||||
providerApiKey: testProviderApiKey,
|
||||
}
|
||||
|
||||
const client = new SupermemoryOpenAI(testApiKey, config)
|
||||
|
||||
expect(client).toBeDefined()
|
||||
})
|
||||
|
||||
it("should handle different API keys", () => {
|
||||
const config: SupermemoryInfiniteChatConfig = {
|
||||
providerName: "openai",
|
||||
providerApiKey: "different-provider-key",
|
||||
}
|
||||
|
||||
const client = new SupermemoryOpenAI("different-sm-key", config)
|
||||
|
||||
expect(client).toBeDefined()
|
||||
})
|
||||
})
|
||||
|
||||
describe("disabled endpoints", () => {
|
||||
it("should throw errors for disabled OpenAI endpoints", () => {
|
||||
const config: SupermemoryInfiniteChatConfig = {
|
||||
providerName: "openai",
|
||||
providerApiKey: testProviderApiKey,
|
||||
}
|
||||
|
||||
const client = new SupermemoryOpenAI(testApiKey, config)
|
||||
|
||||
// Test that all disabled endpoints throw appropriate errors
|
||||
expect(() => client.embeddings).toThrow(
|
||||
"Supermemory only supports chat completions",
|
||||
)
|
||||
expect(() => client.fineTuning).toThrow(
|
||||
"Supermemory only supports chat completions",
|
||||
)
|
||||
expect(() => client.images).toThrow(
|
||||
"Supermemory only supports chat completions",
|
||||
)
|
||||
expect(() => client.audio).toThrow(
|
||||
"Supermemory only supports chat completions",
|
||||
)
|
||||
expect(() => client.models).toThrow(
|
||||
"Supermemory only supports chat completions",
|
||||
)
|
||||
expect(() => client.moderations).toThrow(
|
||||
"Supermemory only supports chat completions",
|
||||
)
|
||||
expect(() => client.files).toThrow(
|
||||
"Supermemory only supports chat completions",
|
||||
)
|
||||
expect(() => client.batches).toThrow(
|
||||
"Supermemory only supports chat completions",
|
||||
)
|
||||
expect(() => client.uploads).toThrow(
|
||||
"Supermemory only supports chat completions",
|
||||
)
|
||||
expect(() => client.beta).toThrow(
|
||||
"Supermemory only supports chat completions",
|
||||
)
|
||||
})
|
||||
|
||||
it("should still allow chat completions to work", () => {
|
||||
const config: SupermemoryInfiniteChatConfig = {
|
||||
providerName: "openai",
|
||||
providerApiKey: testProviderApiKey,
|
||||
}
|
||||
|
||||
const client = new SupermemoryOpenAI(testApiKey, config)
|
||||
|
||||
// Chat completions should still be accessible
|
||||
expect(client.chat).toBeDefined()
|
||||
expect(client.chat.completions).toBeDefined()
|
||||
expect(client.createChatCompletion).toBeDefined()
|
||||
expect(client.chatCompletion).toBeDefined()
|
||||
})
|
||||
})
|
||||
})
|
||||
133
packages/openai-sdk-ts/src/infinite-chat.ts
Normal file
133
packages/openai-sdk-ts/src/infinite-chat.ts
Normal file
|
|
@ -0,0 +1,133 @@
|
|||
import OpenAI from "openai"
|
||||
|
||||
interface SupermemoryInfiniteChatConfigBase {
|
||||
providerApiKey: string
|
||||
headers?: Record<string, string>
|
||||
}
|
||||
|
||||
interface SupermemoryInfiniteChatConfigWithProviderName
|
||||
extends SupermemoryInfiniteChatConfigBase {
|
||||
providerName: keyof typeof providerMap
|
||||
providerUrl?: never
|
||||
}
|
||||
|
||||
interface SupermemoryInfiniteChatConfigWithProviderUrl
|
||||
extends SupermemoryInfiniteChatConfigBase {
|
||||
providerUrl: string
|
||||
providerName?: never
|
||||
}
|
||||
|
||||
export type SupermemoryInfiniteChatConfig =
|
||||
| SupermemoryInfiniteChatConfigWithProviderName
|
||||
| SupermemoryInfiniteChatConfigWithProviderUrl
|
||||
|
||||
type SupermemoryApiKey = string
|
||||
|
||||
const providerMap = {
|
||||
openai: "https://api.openai.com/v1",
|
||||
anthropic: "https://api.anthropic.com/v1",
|
||||
openrouter: "https://openrouter.ai/api/v1",
|
||||
deepinfra: "https://api.deepinfra.com/v1/openai",
|
||||
groq: "https://api.groq.com/openai/v1",
|
||||
google: "https://generativelanguage.googleapis.com/v1beta/openai",
|
||||
cloudflare: "https://gateway.ai.cloudflare.com/v1/*/unlimited-context/openai",
|
||||
} as const
|
||||
|
||||
/**
|
||||
* Enhanced OpenAI client with supermemory integration
|
||||
* Only chat completions are supported - all other OpenAI API endpoints are disabled
|
||||
*/
|
||||
export class SupermemoryOpenAI extends OpenAI {
|
||||
private supermemoryApiKey: string
|
||||
|
||||
constructor(
|
||||
supermemoryApiKey: SupermemoryApiKey,
|
||||
config?: SupermemoryInfiniteChatConfig,
|
||||
) {
|
||||
const baseURL = config?.providerName
|
||||
? providerMap[config.providerName]
|
||||
: (config?.providerUrl ?? "https://api.openai.com/v1")
|
||||
|
||||
super({
|
||||
apiKey: config?.providerApiKey,
|
||||
baseURL,
|
||||
defaultHeaders: {
|
||||
"x-supermemory-api-key": supermemoryApiKey,
|
||||
...config?.headers,
|
||||
},
|
||||
})
|
||||
|
||||
this.supermemoryApiKey = supermemoryApiKey
|
||||
|
||||
// Disable all non-chat completion endpoints
|
||||
this.disableUnsupportedEndpoints()
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable all OpenAI endpoints except chat completions
|
||||
*/
|
||||
private disableUnsupportedEndpoints() {
|
||||
const unsupportedError = (): never => {
|
||||
throw new Error(
|
||||
"Supermemory only supports chat completions. Use chatCompletion() or chat.completions.create() instead.",
|
||||
)
|
||||
}
|
||||
|
||||
// Override all other OpenAI API endpoints using Object.defineProperty
|
||||
const endpoints = [
|
||||
"embeddings",
|
||||
"fineTuning",
|
||||
"images",
|
||||
"audio",
|
||||
"models",
|
||||
"moderations",
|
||||
"files",
|
||||
"batches",
|
||||
"uploads",
|
||||
"beta",
|
||||
]
|
||||
|
||||
for (const endpoint of endpoints) {
|
||||
Object.defineProperty(this, endpoint, {
|
||||
get: unsupportedError,
|
||||
configurable: true,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create chat completions with infinite context support
|
||||
*/
|
||||
async createChatCompletion<
|
||||
T extends OpenAI.Chat.Completions.ChatCompletionCreateParams,
|
||||
>(params: T) {
|
||||
return this.chat.completions.create(params)
|
||||
}
|
||||
|
||||
/**
|
||||
* Create chat completions with simplified interface
|
||||
*/
|
||||
async chatCompletion(
|
||||
messages: OpenAI.Chat.Completions.ChatCompletionMessageParam[],
|
||||
options?: {
|
||||
model?: string
|
||||
temperature?: number
|
||||
maxTokens?: number
|
||||
tools?: OpenAI.Chat.Completions.ChatCompletionTool[]
|
||||
toolChoice?: OpenAI.Chat.Completions.ChatCompletionToolChoiceOption
|
||||
stream?: boolean
|
||||
},
|
||||
) {
|
||||
const params = {
|
||||
model: options?.model ?? "gpt-4o",
|
||||
messages,
|
||||
temperature: options?.temperature,
|
||||
max_tokens: options?.maxTokens,
|
||||
tools: options?.tools,
|
||||
tool_choice: options?.toolChoice,
|
||||
stream: options?.stream,
|
||||
} satisfies OpenAI.Chat.Completions.ChatCompletionCreateParams
|
||||
|
||||
return this.chat.completions.create(params)
|
||||
}
|
||||
}
|
||||
297
packages/openai-sdk-ts/src/tools.test.ts
Normal file
297
packages/openai-sdk-ts/src/tools.test.ts
Normal file
|
|
@ -0,0 +1,297 @@
|
|||
import { describe, expect, it } from "vitest"
|
||||
import {
|
||||
SupermemoryTools,
|
||||
createSupermemoryTools,
|
||||
getMemoryToolDefinitions,
|
||||
executeMemoryToolCalls,
|
||||
createSearchMemoriesTool,
|
||||
createAddMemoryTool,
|
||||
type SupermemoryToolsConfig,
|
||||
} from "./tools"
|
||||
import { SupermemoryOpenAI } from "./infinite-chat"
|
||||
|
||||
import "dotenv/config"
|
||||
|
||||
describe("SupermemoryTools", () => {
|
||||
// Required API keys - tests will fail if not provided
|
||||
const testApiKey = process.env.SUPERMEMORY_API_KEY
|
||||
const testProviderApiKey = process.env.PROVIDER_API_KEY
|
||||
|
||||
if (!testApiKey) {
|
||||
throw new Error(
|
||||
"SUPERMEMORY_API_KEY environment variable is required for tests",
|
||||
)
|
||||
}
|
||||
if (!testProviderApiKey) {
|
||||
throw new Error(
|
||||
"PROVIDER_API_KEY environment variable is required for tests",
|
||||
)
|
||||
}
|
||||
|
||||
// Optional configuration with defaults
|
||||
const testBaseUrl = process.env.SUPERMEMORY_BASE_URL ?? undefined
|
||||
const testModelName = process.env.MODEL_NAME || "gpt-4o-mini"
|
||||
|
||||
describe("tool initialization", () => {
|
||||
it("should create tools with default configuration", () => {
|
||||
const config: SupermemoryToolsConfig = {}
|
||||
const tools = new SupermemoryTools(testApiKey, config)
|
||||
|
||||
expect(tools).toBeDefined()
|
||||
expect(tools.getToolDefinitions()).toBeDefined()
|
||||
expect(tools.getToolDefinitions().length).toBe(3)
|
||||
})
|
||||
|
||||
it("should create tools with createSupermemoryTools helper", () => {
|
||||
const tools = createSupermemoryTools(testApiKey, {
|
||||
projectId: "test-project",
|
||||
})
|
||||
|
||||
expect(tools).toBeDefined()
|
||||
expect(tools.getToolDefinitions()).toBeDefined()
|
||||
})
|
||||
|
||||
it("should create tools with custom baseUrl", () => {
|
||||
const config: SupermemoryToolsConfig = {
|
||||
baseUrl: testBaseUrl,
|
||||
}
|
||||
const tools = new SupermemoryTools(testApiKey, config)
|
||||
|
||||
expect(tools).toBeDefined()
|
||||
expect(tools.getToolDefinitions().length).toBe(3)
|
||||
})
|
||||
|
||||
it("should create tools with projectId configuration", () => {
|
||||
const config: SupermemoryToolsConfig = {
|
||||
projectId: "test-project-123",
|
||||
}
|
||||
const tools = new SupermemoryTools(testApiKey, config)
|
||||
|
||||
expect(tools).toBeDefined()
|
||||
expect(tools.getToolDefinitions().length).toBe(3)
|
||||
})
|
||||
|
||||
it("should create tools with custom container tags", () => {
|
||||
const config: SupermemoryToolsConfig = {
|
||||
containerTags: ["custom-tag-1", "custom-tag-2"],
|
||||
}
|
||||
const tools = new SupermemoryTools(testApiKey, config)
|
||||
|
||||
expect(tools).toBeDefined()
|
||||
expect(tools.getToolDefinitions().length).toBe(3)
|
||||
})
|
||||
})
|
||||
|
||||
describe("tool definitions", () => {
|
||||
it("should return proper OpenAI function definitions", () => {
|
||||
const definitions = getMemoryToolDefinitions()
|
||||
|
||||
expect(definitions).toBeDefined()
|
||||
expect(definitions.length).toBe(3)
|
||||
|
||||
// Check searchMemories
|
||||
const searchTool = definitions.find(
|
||||
(d) => d.function.name === "searchMemories",
|
||||
)
|
||||
expect(searchTool).toBeDefined()
|
||||
expect(searchTool!.type).toBe("function")
|
||||
expect(searchTool!.function.parameters?.required).toContain(
|
||||
"informationToGet",
|
||||
)
|
||||
|
||||
// Check addMemory
|
||||
const addTool = definitions.find((d) => d.function.name === "addMemory")
|
||||
expect(addTool).toBeDefined()
|
||||
expect(addTool!.type).toBe("function")
|
||||
expect(addTool!.function.parameters?.required).toContain("memory")
|
||||
})
|
||||
|
||||
it("should have consistent tool definitions from class and helper", () => {
|
||||
const tools = new SupermemoryTools(testApiKey)
|
||||
const classDefinitions = tools.getToolDefinitions()
|
||||
const helperDefinitions = getMemoryToolDefinitions()
|
||||
|
||||
expect(classDefinitions).toEqual(helperDefinitions)
|
||||
})
|
||||
})
|
||||
|
||||
describe("memory operations", () => {
|
||||
it("should search memories", async () => {
|
||||
const tools = new SupermemoryTools(testApiKey, {
|
||||
projectId: "test-search",
|
||||
baseUrl: testBaseUrl,
|
||||
})
|
||||
|
||||
const result = await tools.searchMemories({
|
||||
informationToGet: "test preferences",
|
||||
limit: 5,
|
||||
})
|
||||
|
||||
expect(result).toBeDefined()
|
||||
expect(result.success).toBeDefined()
|
||||
expect(typeof result.success).toBe("boolean")
|
||||
|
||||
if (result.success) {
|
||||
expect(result.results).toBeDefined()
|
||||
expect(result.count).toBeDefined()
|
||||
expect(typeof result.count).toBe("number")
|
||||
} else {
|
||||
expect(result.error).toBeDefined()
|
||||
}
|
||||
})
|
||||
|
||||
it("should add memory", async () => {
|
||||
const tools = new SupermemoryTools(testApiKey, {
|
||||
containerTags: ["test-add-memory"],
|
||||
baseUrl: testBaseUrl,
|
||||
})
|
||||
|
||||
const result = await tools.addMemory({
|
||||
memory: "User prefers dark roast coffee in the morning - test memory",
|
||||
})
|
||||
|
||||
expect(result).toBeDefined()
|
||||
expect(result.success).toBeDefined()
|
||||
expect(typeof result.success).toBe("boolean")
|
||||
|
||||
if (result.success) {
|
||||
expect(result.memory).toBeDefined()
|
||||
} else {
|
||||
expect(result.error).toBeDefined()
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
describe("individual tool creators", () => {
|
||||
it("should create individual search tool", () => {
|
||||
const searchTool = createSearchMemoriesTool(testApiKey, {
|
||||
projectId: "test-individual",
|
||||
})
|
||||
|
||||
expect(searchTool).toBeDefined()
|
||||
expect(searchTool.definition).toBeDefined()
|
||||
expect(searchTool.execute).toBeDefined()
|
||||
expect(searchTool.definition.function.name).toBe("searchMemories")
|
||||
})
|
||||
|
||||
it("should create individual add tool", () => {
|
||||
const addTool = createAddMemoryTool(testApiKey, {
|
||||
projectId: "test-individual",
|
||||
})
|
||||
|
||||
expect(addTool).toBeDefined()
|
||||
expect(addTool.definition).toBeDefined()
|
||||
expect(addTool.execute).toBeDefined()
|
||||
expect(addTool.definition.function.name).toBe("addMemory")
|
||||
})
|
||||
})
|
||||
|
||||
describe("OpenAI integration", () => {
|
||||
it("should work with SupermemoryOpenAI for function calling", async () => {
|
||||
const client = new SupermemoryOpenAI(testApiKey, {
|
||||
providerName: "openai",
|
||||
providerApiKey: testProviderApiKey,
|
||||
})
|
||||
|
||||
const tools = new SupermemoryTools(testApiKey, {
|
||||
projectId: "test-openai-integration",
|
||||
baseUrl: testBaseUrl,
|
||||
})
|
||||
|
||||
const response = await client.chatCompletion(
|
||||
[
|
||||
{
|
||||
role: "system",
|
||||
content:
|
||||
"You are a helpful assistant with access to user memories. When the user asks you to remember something, use the addMemory tool.",
|
||||
},
|
||||
{
|
||||
role: "user",
|
||||
content: "Please remember that I prefer tea over coffee",
|
||||
},
|
||||
],
|
||||
{
|
||||
model: testModelName,
|
||||
tools: tools.getToolDefinitions(),
|
||||
},
|
||||
)
|
||||
|
||||
expect(response).toBeDefined()
|
||||
expect("choices" in response).toBe(true)
|
||||
|
||||
if ("choices" in response) {
|
||||
const choice = response.choices[0]!
|
||||
expect(choice.message).toBeDefined()
|
||||
|
||||
// If the model decided to use function calling, test the execution
|
||||
if (choice.message.tool_calls && choice.message.tool_calls.length > 0) {
|
||||
const toolResults = await executeMemoryToolCalls(
|
||||
testApiKey,
|
||||
choice.message.tool_calls,
|
||||
{
|
||||
projectId: "test-openai-integration",
|
||||
baseUrl: testBaseUrl,
|
||||
},
|
||||
)
|
||||
|
||||
expect(toolResults).toBeDefined()
|
||||
expect(toolResults.length).toBe(choice.message.tool_calls.length)
|
||||
|
||||
for (const result of toolResults) {
|
||||
expect(result.role).toBe("tool")
|
||||
expect(result.content).toBeDefined()
|
||||
expect(result.tool_call_id).toBeDefined()
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
it("should handle multiple tool calls", async () => {
|
||||
const tools = new SupermemoryTools(testApiKey, {
|
||||
containerTags: ["test-multi-tools"],
|
||||
baseUrl: testBaseUrl,
|
||||
})
|
||||
|
||||
// Simulate tool calls (normally these would come from OpenAI)
|
||||
const mockToolCalls = [
|
||||
{
|
||||
id: "call_1",
|
||||
type: "function" as const,
|
||||
function: {
|
||||
name: "searchMemories",
|
||||
arguments: JSON.stringify({ informationToGet: "preferences" }),
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "call_2",
|
||||
type: "function" as const,
|
||||
function: {
|
||||
name: "addMemory",
|
||||
arguments: JSON.stringify({
|
||||
memory: "Test memory for multiple calls",
|
||||
}),
|
||||
},
|
||||
},
|
||||
]
|
||||
|
||||
const results = await executeMemoryToolCalls(testApiKey, mockToolCalls, {
|
||||
containerTags: ["test-multi-tools"],
|
||||
baseUrl: testBaseUrl,
|
||||
})
|
||||
|
||||
expect(results).toBeDefined()
|
||||
expect(results.length).toBe(2)
|
||||
|
||||
expect(results[0]!.tool_call_id).toBe("call_1")
|
||||
expect(results[1]!.tool_call_id).toBe("call_2")
|
||||
|
||||
for (const result of results) {
|
||||
expect(result.role).toBe("tool")
|
||||
expect(result.content).toBeDefined()
|
||||
|
||||
const content = JSON.parse(result.content as string)
|
||||
expect(content.success).toBeDefined()
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
299
packages/openai-sdk-ts/src/tools.ts
Normal file
299
packages/openai-sdk-ts/src/tools.ts
Normal file
|
|
@ -0,0 +1,299 @@
|
|||
import type OpenAI from "openai"
|
||||
import Supermemory from "supermemory"
|
||||
|
||||
/**
|
||||
* Supermemory configuration
|
||||
* Only one of `projectId` or `containerTags` can be provided.
|
||||
*/
|
||||
export interface SupermemoryToolsConfig {
|
||||
baseUrl?: string
|
||||
containerTags?: string[]
|
||||
projectId?: string
|
||||
}
|
||||
|
||||
/**
|
||||
* Result types for memory operations
|
||||
*/
|
||||
export interface MemorySearchResult {
|
||||
success: boolean
|
||||
results?: Awaited<ReturnType<Supermemory["search"]["execute"]>>["results"]
|
||||
count?: number
|
||||
error?: string
|
||||
}
|
||||
|
||||
export interface MemoryAddResult {
|
||||
success: boolean
|
||||
memory?: Awaited<ReturnType<Supermemory["memories"]["add"]>>
|
||||
error?: string
|
||||
}
|
||||
|
||||
export interface MemoryFetchResult {
|
||||
success: boolean
|
||||
memory?: Awaited<ReturnType<Supermemory["memories"]["get"]>>
|
||||
error?: string
|
||||
}
|
||||
|
||||
/**
|
||||
* Function schemas for OpenAI function calling
|
||||
*/
|
||||
export const memoryToolSchemas = {
|
||||
searchMemories: {
|
||||
name: "searchMemories",
|
||||
description:
|
||||
"Search (recall) memories/details/information about the user or other facts or entities. Run when explicitly asked or when context about user's past choices would be helpful.",
|
||||
parameters: {
|
||||
type: "object",
|
||||
properties: {
|
||||
informationToGet: {
|
||||
type: "string",
|
||||
description: "Terms to search for in the user's memories",
|
||||
},
|
||||
includeFullDocs: {
|
||||
type: "boolean",
|
||||
description:
|
||||
"Whether to include the full document content in the response. Defaults to true for better AI context.",
|
||||
default: true,
|
||||
},
|
||||
limit: {
|
||||
type: "number",
|
||||
description: "Maximum number of results to return",
|
||||
default: 10,
|
||||
},
|
||||
},
|
||||
required: ["informationToGet"],
|
||||
},
|
||||
} satisfies OpenAI.FunctionDefinition,
|
||||
|
||||
addMemory: {
|
||||
name: "addMemory",
|
||||
description:
|
||||
"Add (remember) memories/details/information about the user or other facts or entities. Run when explicitly asked or when the user mentions any information generalizable beyond the context of the current conversation.",
|
||||
parameters: {
|
||||
type: "object",
|
||||
properties: {
|
||||
memory: {
|
||||
type: "string",
|
||||
description:
|
||||
"The text content of the memory to add. This should be a single sentence or a short paragraph.",
|
||||
},
|
||||
},
|
||||
required: ["memory"],
|
||||
},
|
||||
} satisfies OpenAI.FunctionDefinition,
|
||||
} as const
|
||||
|
||||
/**
|
||||
* Create memory tool handlers for OpenAI function calling
|
||||
*/
|
||||
export class SupermemoryTools {
|
||||
private client: Supermemory
|
||||
private containerTags: string[]
|
||||
|
||||
constructor(apiKey: string, config?: SupermemoryToolsConfig) {
|
||||
this.client = new Supermemory({
|
||||
apiKey,
|
||||
...(config?.baseUrl && { baseURL: config.baseUrl }),
|
||||
})
|
||||
|
||||
this.containerTags = config?.projectId
|
||||
? [`sm_project_${config.projectId}`]
|
||||
: (config?.containerTags ?? ["sm_project_default"])
|
||||
}
|
||||
|
||||
/**
|
||||
* Get OpenAI function definitions for all memory tools
|
||||
*/
|
||||
getToolDefinitions(): OpenAI.Chat.Completions.ChatCompletionTool[] {
|
||||
return [
|
||||
{ type: "function", function: memoryToolSchemas.searchMemories },
|
||||
{ type: "function", function: memoryToolSchemas.addMemory },
|
||||
]
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a tool call based on the function name and arguments
|
||||
*/
|
||||
async executeToolCall(
|
||||
toolCall: OpenAI.Chat.Completions.ChatCompletionMessageToolCall,
|
||||
): Promise<string> {
|
||||
const functionName = toolCall.function.name
|
||||
const args = JSON.parse(toolCall.function.arguments)
|
||||
|
||||
switch (functionName) {
|
||||
case "searchMemories":
|
||||
return JSON.stringify(await this.searchMemories(args))
|
||||
case "addMemory":
|
||||
return JSON.stringify(await this.addMemory(args))
|
||||
default:
|
||||
return JSON.stringify({
|
||||
success: false,
|
||||
error: `Unknown function: ${functionName}`,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Search memories
|
||||
*/
|
||||
async searchMemories({
|
||||
informationToGet,
|
||||
includeFullDocs = true,
|
||||
limit = 10,
|
||||
}: {
|
||||
informationToGet: string
|
||||
includeFullDocs?: boolean
|
||||
limit?: number
|
||||
}): Promise<MemorySearchResult> {
|
||||
try {
|
||||
const response = await this.client.search.execute({
|
||||
q: informationToGet,
|
||||
containerTags: this.containerTags,
|
||||
limit,
|
||||
chunkThreshold: 0.6,
|
||||
includeFullDocs,
|
||||
})
|
||||
|
||||
return {
|
||||
success: true,
|
||||
results: response.results,
|
||||
count: response.results?.length || 0,
|
||||
}
|
||||
} catch (error) {
|
||||
return {
|
||||
success: false,
|
||||
error: error instanceof Error ? error.message : "Unknown error",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a memory
|
||||
*/
|
||||
async addMemory({ memory }: { memory: string }): Promise<MemoryAddResult> {
|
||||
try {
|
||||
const metadata: Record<string, string | number | boolean> = {}
|
||||
|
||||
const response = await this.client.memories.add({
|
||||
content: memory,
|
||||
containerTags: this.containerTags,
|
||||
...(Object.keys(metadata).length > 0 && { metadata }),
|
||||
})
|
||||
|
||||
return {
|
||||
success: true,
|
||||
memory: response,
|
||||
}
|
||||
} catch (error) {
|
||||
return {
|
||||
success: false,
|
||||
error: error instanceof Error ? error.message : "Unknown error",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch a specific memory by ID
|
||||
*/
|
||||
async fetchMemory({
|
||||
memoryId,
|
||||
}: {
|
||||
memoryId: string
|
||||
}): Promise<MemoryFetchResult> {
|
||||
try {
|
||||
const response = await this.client.memories.get(memoryId)
|
||||
|
||||
return {
|
||||
success: true,
|
||||
memory: response,
|
||||
}
|
||||
} catch (error) {
|
||||
return {
|
||||
success: false,
|
||||
error: error instanceof Error ? error.message : "Unknown error",
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to create SupermemoryTools instance
|
||||
*/
|
||||
export function createSupermemoryTools(
|
||||
apiKey: string,
|
||||
config?: SupermemoryToolsConfig,
|
||||
): SupermemoryTools {
|
||||
return new SupermemoryTools(apiKey, config)
|
||||
}
|
||||
|
||||
/**
|
||||
* Get OpenAI function definitions for memory tools
|
||||
*/
|
||||
export function getMemoryToolDefinitions(): OpenAI.Chat.Completions.ChatCompletionTool[] {
|
||||
return [
|
||||
{ type: "function", function: memoryToolSchemas.searchMemories },
|
||||
{ type: "function", function: memoryToolSchemas.addMemory },
|
||||
]
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute tool calls from OpenAI function calling
|
||||
*/
|
||||
export async function executeMemoryToolCalls(
|
||||
apiKey: string,
|
||||
toolCalls: OpenAI.Chat.Completions.ChatCompletionMessageToolCall[],
|
||||
config?: SupermemoryToolsConfig,
|
||||
): Promise<OpenAI.Chat.Completions.ChatCompletionToolMessageParam[]> {
|
||||
const tools = new SupermemoryTools(apiKey, config)
|
||||
|
||||
const results = await Promise.all(
|
||||
toolCalls.map(async (toolCall) => {
|
||||
const result = await tools.executeToolCall(toolCall)
|
||||
return {
|
||||
tool_call_id: toolCall.id,
|
||||
role: "tool" as const,
|
||||
content: result,
|
||||
}
|
||||
}),
|
||||
)
|
||||
|
||||
return results
|
||||
}
|
||||
|
||||
/**
|
||||
* Individual tool creators for more granular control
|
||||
*/
|
||||
export function createSearchMemoriesTool(
|
||||
apiKey: string,
|
||||
config?: SupermemoryToolsConfig,
|
||||
) {
|
||||
return {
|
||||
definition: {
|
||||
type: "function" as const,
|
||||
function: memoryToolSchemas.searchMemories,
|
||||
},
|
||||
execute: (args: {
|
||||
informationToGet: string
|
||||
includeFullDocs?: boolean
|
||||
limit?: number
|
||||
}) => {
|
||||
const tools = new SupermemoryTools(apiKey, config)
|
||||
return tools.searchMemories(args)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
export function createAddMemoryTool(
|
||||
apiKey: string,
|
||||
config?: SupermemoryToolsConfig,
|
||||
) {
|
||||
return {
|
||||
definition: {
|
||||
type: "function" as const,
|
||||
function: memoryToolSchemas.addMemory,
|
||||
},
|
||||
execute: (args: { memory: string }) => {
|
||||
const tools = new SupermemoryTools(apiKey, config)
|
||||
return tools.addMemory(args)
|
||||
},
|
||||
}
|
||||
}
|
||||
12
packages/openai-sdk-ts/tsconfig.json
Normal file
12
packages/openai-sdk-ts/tsconfig.json
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"extends": "@total-typescript/tsconfig/bundler/dom/library-monorepo",
|
||||
"compilerOptions": {
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"@/*": ["./*"],
|
||||
"@lib/*": ["../lib/*"]
|
||||
},
|
||||
"declaration": true,
|
||||
"declarationMap": true
|
||||
}
|
||||
}
|
||||
15
packages/openai-sdk-ts/tsdown.config.ts
Normal file
15
packages/openai-sdk-ts/tsdown.config.ts
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
import { defineConfig } from "tsdown"
|
||||
|
||||
export default defineConfig({
|
||||
entry: ["src/index.ts"],
|
||||
format: "esm",
|
||||
sourcemap: true,
|
||||
target: "es2020",
|
||||
tsconfig: "./tsconfig.json",
|
||||
clean: true,
|
||||
minify: true,
|
||||
dts: {
|
||||
sourcemap: true,
|
||||
},
|
||||
exports: true,
|
||||
})
|
||||
Loading…
Add table
Add a link
Reference in a new issue