convex-supermemory 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +201 -0
- package/README.md +306 -0
- package/dist/client/_generated/_ignore.d.ts +1 -0
- package/dist/client/_generated/_ignore.d.ts.map +1 -0
- package/dist/client/_generated/_ignore.js +3 -0
- package/dist/client/_generated/_ignore.js.map +1 -0
- package/dist/client/index.d.ts +188 -0
- package/dist/client/index.d.ts.map +1 -0
- package/dist/client/index.js +177 -0
- package/dist/client/index.js.map +1 -0
- package/dist/component/_generated/api.d.ts +34 -0
- package/dist/component/_generated/api.d.ts.map +1 -0
- package/dist/component/_generated/api.js +31 -0
- package/dist/component/_generated/api.js.map +1 -0
- package/dist/component/_generated/component.d.ts +152 -0
- package/dist/component/_generated/component.d.ts.map +1 -0
- package/dist/component/_generated/component.js +11 -0
- package/dist/component/_generated/component.js.map +1 -0
- package/dist/component/_generated/dataModel.d.ts +46 -0
- package/dist/component/_generated/dataModel.d.ts.map +1 -0
- package/dist/component/_generated/dataModel.js +11 -0
- package/dist/component/_generated/dataModel.js.map +1 -0
- package/dist/component/_generated/server.d.ts +133 -0
- package/dist/component/_generated/server.d.ts.map +1 -0
- package/dist/component/_generated/server.js +80 -0
- package/dist/component/_generated/server.js.map +1 -0
- package/dist/component/convex.config.d.ts +3 -0
- package/dist/component/convex.config.d.ts.map +1 -0
- package/dist/component/convex.config.js +4 -0
- package/dist/component/convex.config.js.map +1 -0
- package/dist/component/lib.d.ts +128 -0
- package/dist/component/lib.d.ts.map +1 -0
- package/dist/component/lib.js +196 -0
- package/dist/component/lib.js.map +1 -0
- package/dist/component/schema.d.ts +56 -0
- package/dist/component/schema.d.ts.map +1 -0
- package/dist/component/schema.js +33 -0
- package/dist/component/schema.js.map +1 -0
- package/package.json +106 -0
- package/src/client/_generated/_ignore.ts +1 -0
- package/src/client/index.ts +289 -0
- package/src/client/setup.test.ts +26 -0
- package/src/component/_generated/api.ts +50 -0
- package/src/component/_generated/component.ts +232 -0
- package/src/component/_generated/dataModel.ts +60 -0
- package/src/component/_generated/server.ts +169 -0
- package/src/component/convex.config.ts +5 -0
- package/src/component/lib.test.ts +127 -0
- package/src/component/lib.ts +224 -0
- package/src/component/schema.ts +43 -0
- package/src/component/setup.test.ts +11 -0
- package/src/test.ts +18 -0
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
declare const _default: import("convex/server").SchemaDefinition<{
|
|
2
|
+
memories: import("convex/server").TableDefinition<import("convex/values").VObject<{
|
|
3
|
+
metadata?: string | undefined;
|
|
4
|
+
forgetAfter?: number | undefined;
|
|
5
|
+
forgetReason?: string | undefined;
|
|
6
|
+
memoryId: string;
|
|
7
|
+
containerTag: string;
|
|
8
|
+
content: string;
|
|
9
|
+
isStatic: boolean;
|
|
10
|
+
forgotten: boolean;
|
|
11
|
+
createdAt: number;
|
|
12
|
+
updatedAt: number;
|
|
13
|
+
}, {
|
|
14
|
+
memoryId: import("convex/values").VString<string, "required">;
|
|
15
|
+
containerTag: import("convex/values").VString<string, "required">;
|
|
16
|
+
content: import("convex/values").VString<string, "required">;
|
|
17
|
+
isStatic: import("convex/values").VBoolean<boolean, "required">;
|
|
18
|
+
metadata: import("convex/values").VString<string | undefined, "optional">;
|
|
19
|
+
forgetAfter: import("convex/values").VFloat64<number | undefined, "optional">;
|
|
20
|
+
forgetReason: import("convex/values").VString<string | undefined, "optional">;
|
|
21
|
+
forgotten: import("convex/values").VBoolean<boolean, "required">;
|
|
22
|
+
createdAt: import("convex/values").VFloat64<number, "required">;
|
|
23
|
+
updatedAt: import("convex/values").VFloat64<number, "required">;
|
|
24
|
+
}, "required", "memoryId" | "containerTag" | "content" | "metadata" | "forgetAfter" | "forgetReason" | "isStatic" | "forgotten" | "createdAt" | "updatedAt">, {
|
|
25
|
+
by_memoryId: ["memoryId", "_creationTime"];
|
|
26
|
+
by_containerTag: ["containerTag", "_creationTime"];
|
|
27
|
+
}, {}, {}>;
|
|
28
|
+
documents: import("convex/server").TableDefinition<import("convex/values").VObject<{
|
|
29
|
+
content?: string | undefined;
|
|
30
|
+
customId?: string | undefined;
|
|
31
|
+
metadata?: string | undefined;
|
|
32
|
+
summary?: string | undefined;
|
|
33
|
+
title?: string | undefined;
|
|
34
|
+
documentId: string;
|
|
35
|
+
containerTag: string;
|
|
36
|
+
status: "unknown" | "queued" | "extracting" | "chunking" | "embedding" | "indexing" | "done" | "failed";
|
|
37
|
+
createdAt: number;
|
|
38
|
+
updatedAt: number;
|
|
39
|
+
}, {
|
|
40
|
+
documentId: import("convex/values").VString<string, "required">;
|
|
41
|
+
containerTag: import("convex/values").VString<string, "required">;
|
|
42
|
+
content: import("convex/values").VString<string | undefined, "optional">;
|
|
43
|
+
customId: import("convex/values").VString<string | undefined, "optional">;
|
|
44
|
+
metadata: import("convex/values").VString<string | undefined, "optional">;
|
|
45
|
+
status: import("convex/values").VUnion<"unknown" | "queued" | "extracting" | "chunking" | "embedding" | "indexing" | "done" | "failed", [import("convex/values").VLiteral<"unknown", "required">, import("convex/values").VLiteral<"queued", "required">, import("convex/values").VLiteral<"extracting", "required">, import("convex/values").VLiteral<"chunking", "required">, import("convex/values").VLiteral<"embedding", "required">, import("convex/values").VLiteral<"indexing", "required">, import("convex/values").VLiteral<"done", "required">, import("convex/values").VLiteral<"failed", "required">], "required", never>;
|
|
46
|
+
title: import("convex/values").VString<string | undefined, "optional">;
|
|
47
|
+
summary: import("convex/values").VString<string | undefined, "optional">;
|
|
48
|
+
createdAt: import("convex/values").VFloat64<number, "required">;
|
|
49
|
+
updatedAt: import("convex/values").VFloat64<number, "required">;
|
|
50
|
+
}, "required", "documentId" | "containerTag" | "content" | "customId" | "metadata" | "status" | "summary" | "title" | "createdAt" | "updatedAt">, {
|
|
51
|
+
by_documentId: ["documentId", "_creationTime"];
|
|
52
|
+
by_containerTag: ["containerTag", "_creationTime"];
|
|
53
|
+
}, {}, {}>;
|
|
54
|
+
}, true>;
|
|
55
|
+
export default _default;
|
|
56
|
+
//# sourceMappingURL=schema.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../src/component/schema.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAGA,wBAuCG"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { defineSchema, defineTable } from "convex/server";
|
|
2
|
+
import { v } from "convex/values";
|
|
3
|
+
export default defineSchema({
|
|
4
|
+
memories: defineTable({
|
|
5
|
+
memoryId: v.string(),
|
|
6
|
+
containerTag: v.string(),
|
|
7
|
+
content: v.string(),
|
|
8
|
+
isStatic: v.boolean(),
|
|
9
|
+
metadata: v.optional(v.string()),
|
|
10
|
+
forgetAfter: v.optional(v.number()),
|
|
11
|
+
forgetReason: v.optional(v.string()),
|
|
12
|
+
forgotten: v.boolean(),
|
|
13
|
+
createdAt: v.number(),
|
|
14
|
+
updatedAt: v.number(),
|
|
15
|
+
})
|
|
16
|
+
.index("by_memoryId", ["memoryId"])
|
|
17
|
+
.index("by_containerTag", ["containerTag"]),
|
|
18
|
+
documents: defineTable({
|
|
19
|
+
documentId: v.string(),
|
|
20
|
+
containerTag: v.string(),
|
|
21
|
+
content: v.optional(v.string()),
|
|
22
|
+
customId: v.optional(v.string()),
|
|
23
|
+
metadata: v.optional(v.string()),
|
|
24
|
+
status: v.union(v.literal("unknown"), v.literal("queued"), v.literal("extracting"), v.literal("chunking"), v.literal("embedding"), v.literal("indexing"), v.literal("done"), v.literal("failed")),
|
|
25
|
+
title: v.optional(v.string()),
|
|
26
|
+
summary: v.optional(v.string()),
|
|
27
|
+
createdAt: v.number(),
|
|
28
|
+
updatedAt: v.number(),
|
|
29
|
+
})
|
|
30
|
+
.index("by_documentId", ["documentId"])
|
|
31
|
+
.index("by_containerTag", ["containerTag"]),
|
|
32
|
+
});
|
|
33
|
+
//# sourceMappingURL=schema.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema.js","sourceRoot":"","sources":["../../src/component/schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC1D,OAAO,EAAE,CAAC,EAAE,MAAM,eAAe,CAAC;AAElC,eAAe,YAAY,CAAC;IAC1B,QAAQ,EAAE,WAAW,CAAC;QACpB,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE;QACpB,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE;QACxB,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE;QACnB,QAAQ,EAAE,CAAC,CAAC,OAAO,EAAE;QACrB,QAAQ,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;QAChC,WAAW,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;QACnC,YAAY,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;QACpC,SAAS,EAAE,CAAC,CAAC,OAAO,EAAE;QACtB,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE;QACrB,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE;KACtB,CAAC;SACC,KAAK,CAAC,aAAa,EAAE,CAAC,UAAU,CAAC,CAAC;SAClC,KAAK,CAAC,iBAAiB,EAAE,CAAC,cAAc,CAAC,CAAC;IAE7C,SAAS,EAAE,WAAW,CAAC;QACrB,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE;QACtB,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE;QACxB,OAAO,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;QAC/B,QAAQ,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;QAChC,QAAQ,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;QAChC,MAAM,EAAE,CAAC,CAAC,KAAK,CACb,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC,EACpB,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,EACnB,CAAC,CAAC,OAAO,CAAC,YAAY,CAAC,EACvB,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC,EACrB,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC,EACtB,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC,EACrB,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,EACjB,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,CACpB;QACD,KAAK,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;QAC7B,OAAO,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;QAC/B,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE;QACrB,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE;KACtB,CAAC;SACC,KAAK,CAAC,eAAe,EAAE,CAAC,YAAY,CAAC,CAAC;SACtC,KAAK,CAAC,iBAAiB,EAAE,CAAC,cAAc,CAAC,CAAC;CAC9C,CAAC,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "convex-supermemory",
|
|
3
|
+
"description": "Give your Convex app long-term, semantically searchable memory with Supermemory. Reactive local memory and document state, direct REST integration.",
|
|
4
|
+
"repository": {
|
|
5
|
+
"type": "git",
|
|
6
|
+
"url": "git+https://github.com/sholajegede/convex-supermemory.git"
|
|
7
|
+
},
|
|
8
|
+
"homepage": "https://github.com/sholajegede/convex-supermemory#readme",
|
|
9
|
+
"bugs": {
|
|
10
|
+
"url": "https://github.com/sholajegede/convex-supermemory/issues"
|
|
11
|
+
},
|
|
12
|
+
"version": "0.0.1",
|
|
13
|
+
"license": "Apache-2.0",
|
|
14
|
+
"keywords": [
|
|
15
|
+
"convex",
|
|
16
|
+
"component",
|
|
17
|
+
"supermemory",
|
|
18
|
+
"memory",
|
|
19
|
+
"rag",
|
|
20
|
+
"ai",
|
|
21
|
+
"agents",
|
|
22
|
+
"search"
|
|
23
|
+
],
|
|
24
|
+
"type": "module",
|
|
25
|
+
"scripts": {
|
|
26
|
+
"dev": "run-p -r 'dev:*'",
|
|
27
|
+
"dev:backend": "convex dev --typecheck-components",
|
|
28
|
+
"dev:frontend": "cd example && vite --clearScreen false",
|
|
29
|
+
"dev:build": "chokidar 'tsconfig*.json' 'src/**/*.ts' -i '**/*.test.ts' -c 'npm run build:codegen' --initial",
|
|
30
|
+
"predev": "path-exists .env.local dist || (npm run build && convex dev --once)",
|
|
31
|
+
"build": "tsc --project ./tsconfig.build.json",
|
|
32
|
+
"build:codegen": "npx convex codegen --component-dir ./src/component && npm run build",
|
|
33
|
+
"build:clean": "rm -rf dist *.tsbuildinfo && npm run build:codegen",
|
|
34
|
+
"typecheck": "tsc --noEmit && tsc -p example && tsc -p example/convex",
|
|
35
|
+
"lint": "eslint .",
|
|
36
|
+
"all": "run-p -r 'dev:*' 'test:watch'",
|
|
37
|
+
"test": "vitest run --typecheck",
|
|
38
|
+
"test:watch": "vitest --typecheck --clearScreen false",
|
|
39
|
+
"test:debug": "vitest --inspect-brk --no-file-parallelism",
|
|
40
|
+
"test:coverage": "vitest run --coverage --coverage.reporter=text",
|
|
41
|
+
"preversion": "npm install --legacy-peer-deps && npm run build:clean && run-p test lint typecheck",
|
|
42
|
+
"prepublishOnly": "npm whoami || npm login",
|
|
43
|
+
"alpha": "npm version prerelease --preid alpha && npm publish --tag alpha && git push --follow-tags",
|
|
44
|
+
"release": "npm version patch && npm publish && git push --follow-tags",
|
|
45
|
+
"version": "vim -c 'normal o' -c 'normal o## '$npm_package_version CHANGELOG.md && prettier -w CHANGELOG.md && git add CHANGELOG.md"
|
|
46
|
+
},
|
|
47
|
+
"files": [
|
|
48
|
+
"dist",
|
|
49
|
+
"src"
|
|
50
|
+
],
|
|
51
|
+
"exports": {
|
|
52
|
+
"./package.json": "./package.json",
|
|
53
|
+
".": {
|
|
54
|
+
"types": "./dist/client/index.d.ts",
|
|
55
|
+
"default": "./dist/client/index.js"
|
|
56
|
+
},
|
|
57
|
+
"./test": "./src/test.ts",
|
|
58
|
+
"./_generated/component.js": {
|
|
59
|
+
"types": "./dist/component/_generated/component.d.ts"
|
|
60
|
+
},
|
|
61
|
+
"./_generated/component": {
|
|
62
|
+
"types": "./dist/component/_generated/component.d.ts"
|
|
63
|
+
},
|
|
64
|
+
"./convex.config.js": {
|
|
65
|
+
"types": "./dist/component/convex.config.d.ts",
|
|
66
|
+
"default": "./dist/component/convex.config.js"
|
|
67
|
+
},
|
|
68
|
+
"./convex.config": {
|
|
69
|
+
"types": "./dist/component/convex.config.d.ts",
|
|
70
|
+
"default": "./dist/component/convex.config.js"
|
|
71
|
+
}
|
|
72
|
+
},
|
|
73
|
+
"peerDependencies": {
|
|
74
|
+
"convex": "^1.34.1"
|
|
75
|
+
},
|
|
76
|
+
"devDependencies": {
|
|
77
|
+
"@convex-dev/eslint-plugin": "^1.2.0",
|
|
78
|
+
"@edge-runtime/vm": "^5.0.0",
|
|
79
|
+
"@eslint/eslintrc": "^3.3.5",
|
|
80
|
+
"@eslint/js": "9.39.4",
|
|
81
|
+
"@types/node": "^24.12.0",
|
|
82
|
+
"@types/react": "^19.2.14",
|
|
83
|
+
"@types/react-dom": "^19.2.3",
|
|
84
|
+
"@vitejs/plugin-react": "^5.2.0",
|
|
85
|
+
"chokidar-cli": "3.0.0",
|
|
86
|
+
"convex": "1.45.0",
|
|
87
|
+
"convex-test": "0.0.41",
|
|
88
|
+
"eslint": "9.39.4",
|
|
89
|
+
"eslint-plugin-react": "^7.37.5",
|
|
90
|
+
"eslint-plugin-react-hooks": "^7.0.1",
|
|
91
|
+
"eslint-plugin-react-refresh": "^0.5.2",
|
|
92
|
+
"globals": "^17.4.0",
|
|
93
|
+
"npm-run-all2": "8.0.4",
|
|
94
|
+
"path-exists-cli": "2.0.0",
|
|
95
|
+
"pkg-pr-new": "^0.0.66",
|
|
96
|
+
"prettier": "3.8.1",
|
|
97
|
+
"react": "^19.2.4",
|
|
98
|
+
"react-dom": "^19.2.4",
|
|
99
|
+
"typescript": "5.9.3",
|
|
100
|
+
"typescript-eslint": "8.57.1",
|
|
101
|
+
"vite": "7.3.1",
|
|
102
|
+
"vitest": "4.1.0"
|
|
103
|
+
},
|
|
104
|
+
"types": "./dist/client/index.d.ts",
|
|
105
|
+
"module": "./dist/client/index.js"
|
|
106
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
// This is only here so convex-test can detect a _generated folder
|
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
import type { GenericActionCtx, GenericDataModel } from "convex/server";
|
|
2
|
+
import type { ComponentApi } from "../component/_generated/component.js";
|
|
3
|
+
|
|
4
|
+
const SUPERMEMORY_API_BASE = "https://api.supermemory.ai";
|
|
5
|
+
|
|
6
|
+
export type SupermemoryOptions = {
|
|
7
|
+
apiKey: string;
|
|
8
|
+
baseUrl?: string;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export type AddMemoryArgs = {
|
|
12
|
+
containerTag: string;
|
|
13
|
+
content: string;
|
|
14
|
+
isStatic?: boolean;
|
|
15
|
+
metadata?: Record<string, unknown>;
|
|
16
|
+
forgetAfter?: number;
|
|
17
|
+
forgetReason?: string;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export type AddDocumentArgs = {
|
|
21
|
+
containerTag: string;
|
|
22
|
+
content: string;
|
|
23
|
+
customId?: string;
|
|
24
|
+
metadata?: Record<string, unknown>;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export type SearchArgs = {
|
|
28
|
+
containerTag: string;
|
|
29
|
+
query: string;
|
|
30
|
+
limit?: number;
|
|
31
|
+
rerank?: boolean;
|
|
32
|
+
includeFullDocs?: boolean;
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
export type SearchResult = {
|
|
36
|
+
documentId: string;
|
|
37
|
+
title: string | null;
|
|
38
|
+
score: number;
|
|
39
|
+
summary: string | null;
|
|
40
|
+
content: string | null;
|
|
41
|
+
chunks: Array<{ content: string; score: number; position: number; isRelevant: boolean }>;
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
export type SearchResponse = {
|
|
45
|
+
results: SearchResult[];
|
|
46
|
+
total: number;
|
|
47
|
+
timing?: number; // ms, when Supermemory reports it
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
export class Supermemory {
|
|
51
|
+
constructor(
|
|
52
|
+
private component: ComponentApi,
|
|
53
|
+
private options: SupermemoryOptions,
|
|
54
|
+
) {}
|
|
55
|
+
|
|
56
|
+
private baseUrl(): string {
|
|
57
|
+
return this.options.baseUrl ?? SUPERMEMORY_API_BASE;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
private headers(): Record<string, string> {
|
|
61
|
+
return {
|
|
62
|
+
Authorization: `Bearer ${this.options.apiKey}`,
|
|
63
|
+
"Content-Type": "application/json",
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/** Store a single fact/memory directly (fast path — no chunking pipeline). */
|
|
68
|
+
async addMemory(
|
|
69
|
+
ctx: GenericActionCtx<GenericDataModel>,
|
|
70
|
+
args: AddMemoryArgs,
|
|
71
|
+
): Promise<{ memoryId: string }> {
|
|
72
|
+
const res = await fetch(`${this.baseUrl()}/v4/memories`, {
|
|
73
|
+
method: "POST",
|
|
74
|
+
headers: this.headers(),
|
|
75
|
+
body: JSON.stringify({
|
|
76
|
+
containerTag: args.containerTag,
|
|
77
|
+
memories: [
|
|
78
|
+
{
|
|
79
|
+
content: args.content,
|
|
80
|
+
isStatic: args.isStatic ?? false,
|
|
81
|
+
metadata: args.metadata,
|
|
82
|
+
forgetAfter: args.forgetAfter
|
|
83
|
+
? new Date(args.forgetAfter).toISOString()
|
|
84
|
+
: undefined,
|
|
85
|
+
forgetReason: args.forgetReason,
|
|
86
|
+
},
|
|
87
|
+
],
|
|
88
|
+
}),
|
|
89
|
+
});
|
|
90
|
+
if (!res.ok) {
|
|
91
|
+
throw new Error(`Failed to add Supermemory memory: ${res.status} ${await res.text()}`);
|
|
92
|
+
}
|
|
93
|
+
const json = (await res.json()) as {
|
|
94
|
+
memories: Array<{ id: string; memory: string; isStatic: boolean; createdAt: string }>;
|
|
95
|
+
};
|
|
96
|
+
const memory = json.memories[0];
|
|
97
|
+
|
|
98
|
+
await ctx.runMutation(this.component.lib.recordMemory, {
|
|
99
|
+
memoryId: memory.id,
|
|
100
|
+
containerTag: args.containerTag,
|
|
101
|
+
content: args.content,
|
|
102
|
+
isStatic: args.isStatic ?? false,
|
|
103
|
+
metadata: args.metadata ? JSON.stringify(args.metadata) : undefined,
|
|
104
|
+
forgetAfter: args.forgetAfter,
|
|
105
|
+
forgetReason: args.forgetReason,
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
return { memoryId: memory.id };
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/** Mark a memory as forgotten. Supermemory may forget it asynchronously. */
|
|
112
|
+
async forgetMemory(
|
|
113
|
+
ctx: GenericActionCtx<GenericDataModel>,
|
|
114
|
+
args: { containerTag: string; memoryId: string },
|
|
115
|
+
): Promise<{ forgotten: boolean }> {
|
|
116
|
+
const res = await fetch(`${this.baseUrl()}/v4/memories`, {
|
|
117
|
+
method: "DELETE",
|
|
118
|
+
headers: this.headers(),
|
|
119
|
+
// containerTag is required by Supermemory to scope the delete —
|
|
120
|
+
// omitting it makes this a 400, not a silent no-op.
|
|
121
|
+
body: JSON.stringify({ id: args.memoryId, containerTag: args.containerTag }),
|
|
122
|
+
});
|
|
123
|
+
if (!res.ok) {
|
|
124
|
+
throw new Error(`Failed to forget Supermemory memory: ${res.status} ${await res.text()}`);
|
|
125
|
+
}
|
|
126
|
+
const json = (await res.json()) as { id: string; forgotten: boolean };
|
|
127
|
+
|
|
128
|
+
if (json.forgotten) {
|
|
129
|
+
await ctx.runMutation(this.component.lib.markMemoryForgotten, { memoryId: args.memoryId });
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
return { forgotten: json.forgotten };
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Ingest a larger piece of content (a document, page, or conversation) through
|
|
137
|
+
* Supermemory's extraction/chunking pipeline. Use `getDocument`/`refreshDocument`
|
|
138
|
+
* to poll processing status.
|
|
139
|
+
*/
|
|
140
|
+
async addDocument(
|
|
141
|
+
ctx: GenericActionCtx<GenericDataModel>,
|
|
142
|
+
args: AddDocumentArgs,
|
|
143
|
+
): Promise<{ documentId: string; status: string }> {
|
|
144
|
+
const res = await fetch(`${this.baseUrl()}/v3/documents`, {
|
|
145
|
+
method: "POST",
|
|
146
|
+
headers: this.headers(),
|
|
147
|
+
body: JSON.stringify({
|
|
148
|
+
content: args.content,
|
|
149
|
+
containerTag: args.containerTag,
|
|
150
|
+
customId: args.customId,
|
|
151
|
+
metadata: args.metadata,
|
|
152
|
+
}),
|
|
153
|
+
});
|
|
154
|
+
if (!res.ok) {
|
|
155
|
+
throw new Error(`Failed to add Supermemory document: ${res.status} ${await res.text()}`);
|
|
156
|
+
}
|
|
157
|
+
const json = (await res.json()) as { id: string; status: string };
|
|
158
|
+
|
|
159
|
+
await ctx.runMutation(this.component.lib.recordDocument, {
|
|
160
|
+
documentId: json.id,
|
|
161
|
+
containerTag: args.containerTag,
|
|
162
|
+
content: args.content,
|
|
163
|
+
customId: args.customId,
|
|
164
|
+
metadata: args.metadata ? JSON.stringify(args.metadata) : undefined,
|
|
165
|
+
status: (json.status as
|
|
166
|
+
| "unknown"
|
|
167
|
+
| "queued"
|
|
168
|
+
| "extracting"
|
|
169
|
+
| "chunking"
|
|
170
|
+
| "embedding"
|
|
171
|
+
| "indexing"
|
|
172
|
+
| "done"
|
|
173
|
+
| "failed") ?? "queued",
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
return { documentId: json.id, status: json.status };
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/** Refresh a document's processing status, title, and summary from Supermemory. */
|
|
180
|
+
async refreshDocument(
|
|
181
|
+
ctx: GenericActionCtx<GenericDataModel>,
|
|
182
|
+
args: { documentId: string },
|
|
183
|
+
): Promise<void> {
|
|
184
|
+
const res = await fetch(`${this.baseUrl()}/v3/documents/${encodeURIComponent(args.documentId)}`, {
|
|
185
|
+
headers: this.headers(),
|
|
186
|
+
});
|
|
187
|
+
if (!res.ok) {
|
|
188
|
+
throw new Error(`Failed to fetch Supermemory document: ${res.status} ${await res.text()}`);
|
|
189
|
+
}
|
|
190
|
+
const json = (await res.json()) as {
|
|
191
|
+
id: string;
|
|
192
|
+
status: string;
|
|
193
|
+
title: string | null;
|
|
194
|
+
summary: string | null;
|
|
195
|
+
content: string | null;
|
|
196
|
+
metadata: Record<string, unknown> | null;
|
|
197
|
+
};
|
|
198
|
+
|
|
199
|
+
const existing = await ctx.runQuery(this.component.lib.getDocument, { documentId: args.documentId });
|
|
200
|
+
|
|
201
|
+
await ctx.runMutation(this.component.lib.recordDocument, {
|
|
202
|
+
documentId: json.id,
|
|
203
|
+
containerTag: existing?.containerTag ?? "",
|
|
204
|
+
content: json.content ?? existing?.content,
|
|
205
|
+
customId: existing?.customId,
|
|
206
|
+
metadata: json.metadata ? JSON.stringify(json.metadata) : existing?.metadata,
|
|
207
|
+
status: json.status as
|
|
208
|
+
| "unknown"
|
|
209
|
+
| "queued"
|
|
210
|
+
| "extracting"
|
|
211
|
+
| "chunking"
|
|
212
|
+
| "embedding"
|
|
213
|
+
| "indexing"
|
|
214
|
+
| "done"
|
|
215
|
+
| "failed",
|
|
216
|
+
title: json.title ?? undefined,
|
|
217
|
+
summary: json.summary ?? undefined,
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
async deleteDocument(
|
|
222
|
+
ctx: GenericActionCtx<GenericDataModel>,
|
|
223
|
+
args: { documentId: string },
|
|
224
|
+
): Promise<void> {
|
|
225
|
+
const res = await fetch(`${this.baseUrl()}/v3/documents/${encodeURIComponent(args.documentId)}`, {
|
|
226
|
+
method: "DELETE",
|
|
227
|
+
headers: this.headers(),
|
|
228
|
+
});
|
|
229
|
+
if (!res.ok && res.status !== 204) {
|
|
230
|
+
throw new Error(`Failed to delete Supermemory document: ${res.status} ${await res.text()}`);
|
|
231
|
+
}
|
|
232
|
+
await ctx.runMutation(this.component.lib.deleteDocument, { documentId: args.documentId });
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
/** Semantic search over a container's document chunks. Always live — not cached locally. */
|
|
236
|
+
async search(args: SearchArgs): Promise<SearchResponse> {
|
|
237
|
+
const res = await fetch(`${this.baseUrl()}/v3/search`, {
|
|
238
|
+
method: "POST",
|
|
239
|
+
headers: this.headers(),
|
|
240
|
+
body: JSON.stringify({
|
|
241
|
+
q: args.query,
|
|
242
|
+
// Supermemory's /v3/search schema documents singular `containerTag` as
|
|
243
|
+
// valid, but the only worked example in their own docs uses the plural
|
|
244
|
+
// `containerTags` array — and in practice singular reliably returns
|
|
245
|
+
// zero matches even against fully-indexed content. Use the array form.
|
|
246
|
+
containerTags: [args.containerTag],
|
|
247
|
+
limit: args.limit ?? 10,
|
|
248
|
+
rerank: args.rerank ?? false,
|
|
249
|
+
includeFullDocs: args.includeFullDocs ?? false,
|
|
250
|
+
}),
|
|
251
|
+
});
|
|
252
|
+
if (!res.ok) {
|
|
253
|
+
throw new Error(`Failed to search Supermemory: ${res.status} ${await res.text()}`);
|
|
254
|
+
}
|
|
255
|
+
return (await res.json()) as SearchResponse;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
async getMemory(ctx: RunQueryCtx, args: { memoryId: string }) {
|
|
259
|
+
return await ctx.runQuery(this.component.lib.getMemory, args);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
async listMemories(ctx: RunQueryCtx, args: { containerTag: string; limit?: number }) {
|
|
263
|
+
return await ctx.runQuery(this.component.lib.listMemories, args);
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
async getDocument(ctx: RunQueryCtx, args: { documentId: string }) {
|
|
267
|
+
return await ctx.runQuery(this.component.lib.getDocument, args);
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
async listDocuments(ctx: RunQueryCtx, args: { containerTag: string; limit?: number }) {
|
|
271
|
+
return await ctx.runQuery(this.component.lib.listDocuments, args);
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
async getStats(ctx: RunQueryCtx) {
|
|
275
|
+
return await ctx.runQuery(this.component.lib.getStats, {});
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
async listRecentMemories(ctx: RunQueryCtx, args: { limit?: number } = {}) {
|
|
279
|
+
return await ctx.runQuery(this.component.lib.listRecentMemories, args);
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
async listRecentDocuments(ctx: RunQueryCtx, args: { limit?: number } = {}) {
|
|
283
|
+
return await ctx.runQuery(this.component.lib.listRecentDocuments, args);
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
type RunQueryCtx = {
|
|
288
|
+
runQuery: GenericActionCtx<GenericDataModel>["runQuery"];
|
|
289
|
+
};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/// <reference types="vite/client" />
|
|
2
|
+
import { test } from "vitest";
|
|
3
|
+
import { convexTest } from "convex-test";
|
|
4
|
+
export const modules = import.meta.glob("./**/*.*s");
|
|
5
|
+
|
|
6
|
+
import {
|
|
7
|
+
defineSchema,
|
|
8
|
+
type GenericSchema,
|
|
9
|
+
type SchemaDefinition,
|
|
10
|
+
} from "convex/server";
|
|
11
|
+
import { type ComponentApi } from "../component/_generated/component.js";
|
|
12
|
+
import { componentsGeneric } from "convex/server";
|
|
13
|
+
import { register } from "../test.js";
|
|
14
|
+
|
|
15
|
+
export function initConvexTest<
|
|
16
|
+
Schema extends SchemaDefinition<GenericSchema, boolean>,
|
|
17
|
+
>(schema?: Schema) {
|
|
18
|
+
const t = convexTest(schema ?? defineSchema({}), modules);
|
|
19
|
+
register(t);
|
|
20
|
+
return t;
|
|
21
|
+
}
|
|
22
|
+
export const components = componentsGeneric() as unknown as {
|
|
23
|
+
convexSupermemory: ComponentApi;
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
test("setup", () => {});
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/* eslint-disable */
|
|
2
|
+
/**
|
|
3
|
+
* Generated `api` utility.
|
|
4
|
+
*
|
|
5
|
+
* THIS CODE IS AUTOMATICALLY GENERATED.
|
|
6
|
+
*
|
|
7
|
+
* To regenerate, run `npx convex dev`.
|
|
8
|
+
* @module
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import type * as lib from "../lib.js";
|
|
12
|
+
|
|
13
|
+
import type {
|
|
14
|
+
ApiFromModules,
|
|
15
|
+
FilterApi,
|
|
16
|
+
FunctionReference,
|
|
17
|
+
} from "convex/server";
|
|
18
|
+
import { anyApi, componentsGeneric } from "convex/server";
|
|
19
|
+
|
|
20
|
+
const fullApi: ApiFromModules<{
|
|
21
|
+
lib: typeof lib;
|
|
22
|
+
}> = anyApi as any;
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* A utility for referencing Convex functions in your app's public API.
|
|
26
|
+
*
|
|
27
|
+
* Usage:
|
|
28
|
+
* ```js
|
|
29
|
+
* const myFunctionReference = api.myModule.myFunction;
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
export const api: FilterApi<
|
|
33
|
+
typeof fullApi,
|
|
34
|
+
FunctionReference<any, "public">
|
|
35
|
+
> = anyApi as any;
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* A utility for referencing Convex functions in your app's internal API.
|
|
39
|
+
*
|
|
40
|
+
* Usage:
|
|
41
|
+
* ```js
|
|
42
|
+
* const myFunctionReference = internal.myModule.myFunction;
|
|
43
|
+
* ```
|
|
44
|
+
*/
|
|
45
|
+
export const internal: FilterApi<
|
|
46
|
+
typeof fullApi,
|
|
47
|
+
FunctionReference<any, "internal">
|
|
48
|
+
> = anyApi as any;
|
|
49
|
+
|
|
50
|
+
export const components = componentsGeneric() as unknown as {};
|