@cortexmemory/cli 0.26.2 → 0.27.3
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/dist/commands/convex.js +1 -1
- package/dist/commands/convex.js.map +1 -1
- package/dist/commands/deploy.d.ts +1 -1
- package/dist/commands/deploy.d.ts.map +1 -1
- package/dist/commands/deploy.js +771 -144
- package/dist/commands/deploy.js.map +1 -1
- package/dist/commands/dev.d.ts.map +1 -1
- package/dist/commands/dev.js +210 -36
- package/dist/commands/dev.js.map +1 -1
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +273 -43
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/setup.d.ts.map +1 -1
- package/dist/commands/setup.js +102 -46
- package/dist/commands/setup.js.map +1 -1
- package/dist/commands/status.d.ts.map +1 -1
- package/dist/commands/status.js +94 -7
- package/dist/commands/status.js.map +1 -1
- package/dist/index.js +1 -1
- package/dist/types.d.ts +23 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/app-template-sync.d.ts +95 -0
- package/dist/utils/app-template-sync.d.ts.map +1 -0
- package/dist/utils/app-template-sync.js +425 -0
- package/dist/utils/app-template-sync.js.map +1 -0
- package/dist/utils/config.d.ts +11 -0
- package/dist/utils/config.d.ts.map +1 -1
- package/dist/utils/config.js +20 -0
- package/dist/utils/config.js.map +1 -1
- package/dist/utils/deployment-selector.d.ts +21 -0
- package/dist/utils/deployment-selector.d.ts.map +1 -1
- package/dist/utils/deployment-selector.js +32 -0
- package/dist/utils/deployment-selector.js.map +1 -1
- package/dist/utils/init/graph-setup.d.ts.map +1 -1
- package/dist/utils/init/graph-setup.js +25 -2
- package/dist/utils/init/graph-setup.js.map +1 -1
- package/dist/utils/init/quickstart-setup.d.ts +87 -0
- package/dist/utils/init/quickstart-setup.d.ts.map +1 -0
- package/dist/utils/init/quickstart-setup.js +462 -0
- package/dist/utils/init/quickstart-setup.js.map +1 -0
- package/dist/utils/schema-sync.d.ts.map +1 -1
- package/dist/utils/schema-sync.js +27 -21
- package/dist/utils/schema-sync.js.map +1 -1
- package/package.json +3 -2
- package/templates/vercel-ai-quickstart/.env.local.example +45 -0
- package/templates/vercel-ai-quickstart/README.md +280 -0
- package/templates/vercel-ai-quickstart/app/api/auth/check/route.ts +30 -0
- package/templates/vercel-ai-quickstart/app/api/auth/login/route.ts +83 -0
- package/templates/vercel-ai-quickstart/app/api/auth/register/route.ts +94 -0
- package/templates/vercel-ai-quickstart/app/api/auth/setup/route.ts +59 -0
- package/templates/vercel-ai-quickstart/app/api/chat/route.ts +277 -0
- package/templates/vercel-ai-quickstart/app/api/conversations/route.ts +179 -0
- package/templates/vercel-ai-quickstart/app/api/facts/route.ts +39 -0
- package/templates/vercel-ai-quickstart/app/api/health/route.ts +99 -0
- package/templates/vercel-ai-quickstart/app/api/memories/route.ts +37 -0
- package/templates/vercel-ai-quickstart/app/globals.css +275 -0
- package/templates/vercel-ai-quickstart/app/layout.tsx +19 -0
- package/templates/vercel-ai-quickstart/app/page.tsx +216 -0
- package/templates/vercel-ai-quickstart/components/AdminSetup.tsx +139 -0
- package/templates/vercel-ai-quickstart/components/AuthProvider.tsx +283 -0
- package/templates/vercel-ai-quickstart/components/ChatHistorySidebar.tsx +323 -0
- package/templates/vercel-ai-quickstart/components/ChatInterface.tsx +334 -0
- package/templates/vercel-ai-quickstart/components/ConvexClientProvider.tsx +21 -0
- package/templates/vercel-ai-quickstart/components/DataPreview.tsx +57 -0
- package/templates/vercel-ai-quickstart/components/HealthStatus.tsx +214 -0
- package/templates/vercel-ai-quickstart/components/LayerCard.tsx +263 -0
- package/templates/vercel-ai-quickstart/components/LayerFlowDiagram.tsx +195 -0
- package/templates/vercel-ai-quickstart/components/LoginScreen.tsx +202 -0
- package/templates/vercel-ai-quickstart/components/MemorySpaceSwitcher.tsx +93 -0
- package/templates/vercel-ai-quickstart/convex/conversations.ts +67 -0
- package/templates/vercel-ai-quickstart/convex/facts.ts +131 -0
- package/templates/vercel-ai-quickstart/convex/health.ts +15 -0
- package/templates/vercel-ai-quickstart/convex/memories.ts +104 -0
- package/templates/vercel-ai-quickstart/convex/schema.ts +20 -0
- package/templates/vercel-ai-quickstart/convex/users.ts +105 -0
- package/templates/vercel-ai-quickstart/jest.config.js +45 -0
- package/templates/vercel-ai-quickstart/lib/animations.ts +146 -0
- package/templates/vercel-ai-quickstart/lib/cortex.ts +27 -0
- package/templates/vercel-ai-quickstart/lib/layer-tracking.ts +214 -0
- package/templates/vercel-ai-quickstart/lib/password.ts +120 -0
- package/templates/vercel-ai-quickstart/next.config.js +27 -0
- package/templates/vercel-ai-quickstart/package.json +46 -0
- package/templates/vercel-ai-quickstart/postcss.config.js +5 -0
- package/templates/vercel-ai-quickstart/tailwind.config.js +37 -0
- package/templates/vercel-ai-quickstart/tests/helpers/mock-cortex.ts +263 -0
- package/templates/vercel-ai-quickstart/tests/helpers/setup.ts +48 -0
- package/templates/vercel-ai-quickstart/tests/integration/auth.test.ts +455 -0
- package/templates/vercel-ai-quickstart/tests/integration/conversations.test.ts +461 -0
- package/templates/vercel-ai-quickstart/tests/unit/password.test.ts +228 -0
- package/templates/vercel-ai-quickstart/tsconfig.json +33 -0
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { query } from "./_generated/server";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Simple health check query to verify Convex backend is reachable
|
|
5
|
+
*/
|
|
6
|
+
export const ping = query({
|
|
7
|
+
args: {},
|
|
8
|
+
handler: async () => {
|
|
9
|
+
return {
|
|
10
|
+
status: "ok",
|
|
11
|
+
timestamp: Date.now(),
|
|
12
|
+
backend: "convex",
|
|
13
|
+
};
|
|
14
|
+
},
|
|
15
|
+
});
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Convex queries for real-time memory updates
|
|
3
|
+
*
|
|
4
|
+
* These queries enable the LayerFlowDiagram to show live updates
|
|
5
|
+
* as vector memories are created in the Cortex system.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { query } from "./_generated/server";
|
|
9
|
+
import { v } from "convex/values";
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Get recent memories for a memory space
|
|
13
|
+
*
|
|
14
|
+
* Used by the demo to watch for new memories being created.
|
|
15
|
+
*/
|
|
16
|
+
export const getRecent = query({
|
|
17
|
+
args: {
|
|
18
|
+
memorySpaceId: v.string(),
|
|
19
|
+
limit: v.optional(v.number()),
|
|
20
|
+
},
|
|
21
|
+
handler: async (ctx, args) => {
|
|
22
|
+
const limit = args.limit ?? 10;
|
|
23
|
+
|
|
24
|
+
// Query memories table (from Cortex SDK schema)
|
|
25
|
+
const memories = await ctx.db
|
|
26
|
+
.query("memories")
|
|
27
|
+
.filter((q) => q.eq(q.field("memorySpaceId"), args.memorySpaceId))
|
|
28
|
+
.order("desc")
|
|
29
|
+
.take(limit);
|
|
30
|
+
|
|
31
|
+
return memories;
|
|
32
|
+
},
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Get memories for a specific user
|
|
37
|
+
*/
|
|
38
|
+
export const getByUser = query({
|
|
39
|
+
args: {
|
|
40
|
+
memorySpaceId: v.string(),
|
|
41
|
+
userId: v.string(),
|
|
42
|
+
limit: v.optional(v.number()),
|
|
43
|
+
},
|
|
44
|
+
handler: async (ctx, args) => {
|
|
45
|
+
const limit = args.limit ?? 20;
|
|
46
|
+
|
|
47
|
+
const memories = await ctx.db
|
|
48
|
+
.query("memories")
|
|
49
|
+
.filter((q) =>
|
|
50
|
+
q.and(
|
|
51
|
+
q.eq(q.field("memorySpaceId"), args.memorySpaceId),
|
|
52
|
+
q.eq(q.field("userId"), args.userId),
|
|
53
|
+
),
|
|
54
|
+
)
|
|
55
|
+
.order("desc")
|
|
56
|
+
.take(limit);
|
|
57
|
+
|
|
58
|
+
return memories;
|
|
59
|
+
},
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Get memory count for a memory space
|
|
64
|
+
*/
|
|
65
|
+
export const count = query({
|
|
66
|
+
args: {
|
|
67
|
+
memorySpaceId: v.string(),
|
|
68
|
+
},
|
|
69
|
+
handler: async (ctx, args) => {
|
|
70
|
+
const memories = await ctx.db
|
|
71
|
+
.query("memories")
|
|
72
|
+
.filter((q) => q.eq(q.field("memorySpaceId"), args.memorySpaceId))
|
|
73
|
+
.collect();
|
|
74
|
+
|
|
75
|
+
return memories.length;
|
|
76
|
+
},
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Search memories by content (simple text search for demo)
|
|
81
|
+
*/
|
|
82
|
+
export const search = query({
|
|
83
|
+
args: {
|
|
84
|
+
memorySpaceId: v.string(),
|
|
85
|
+
query: v.string(),
|
|
86
|
+
limit: v.optional(v.number()),
|
|
87
|
+
},
|
|
88
|
+
handler: async (ctx, args) => {
|
|
89
|
+
const limit = args.limit ?? 5;
|
|
90
|
+
const queryLower = args.query.toLowerCase();
|
|
91
|
+
|
|
92
|
+
// Simple text search (in production, use vector search)
|
|
93
|
+
const allMemories = await ctx.db
|
|
94
|
+
.query("memories")
|
|
95
|
+
.filter((q) => q.eq(q.field("memorySpaceId"), args.memorySpaceId))
|
|
96
|
+
.collect();
|
|
97
|
+
|
|
98
|
+
const matching = allMemories
|
|
99
|
+
.filter((m) => m.content?.toLowerCase().includes(queryLower))
|
|
100
|
+
.slice(0, limit);
|
|
101
|
+
|
|
102
|
+
return matching;
|
|
103
|
+
},
|
|
104
|
+
});
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Convex schema for the quickstart demo
|
|
3
|
+
*
|
|
4
|
+
* This extends the Cortex SDK schema to add any demo-specific tables.
|
|
5
|
+
* The actual memory tables (conversations, memories, facts) come from @cortexmemory/sdk.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { defineSchema, defineTable } from "convex/server";
|
|
9
|
+
import { v } from "convex/values";
|
|
10
|
+
|
|
11
|
+
export default defineSchema({
|
|
12
|
+
// Demo session tracking (optional, for demo purposes)
|
|
13
|
+
demoSessions: defineTable({
|
|
14
|
+
sessionId: v.string(),
|
|
15
|
+
userId: v.string(),
|
|
16
|
+
memorySpaceId: v.string(),
|
|
17
|
+
startedAt: v.number(),
|
|
18
|
+
messageCount: v.number(),
|
|
19
|
+
}).index("by_session", ["sessionId"]),
|
|
20
|
+
});
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Convex queries for user profile data
|
|
3
|
+
*
|
|
4
|
+
* These queries enable the LayerFlowDiagram to show user context
|
|
5
|
+
* during memory orchestration.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { query } from "./_generated/server";
|
|
9
|
+
import { v } from "convex/values";
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Get user profile by ID
|
|
13
|
+
*
|
|
14
|
+
* Returns user information stored in the Cortex system.
|
|
15
|
+
*/
|
|
16
|
+
export const get = query({
|
|
17
|
+
args: {
|
|
18
|
+
userId: v.string(),
|
|
19
|
+
memorySpaceId: v.string(),
|
|
20
|
+
},
|
|
21
|
+
handler: async (ctx, args) => {
|
|
22
|
+
// Query users table (from Cortex SDK schema)
|
|
23
|
+
const user = await ctx.db
|
|
24
|
+
.query("users")
|
|
25
|
+
.filter((q) =>
|
|
26
|
+
q.and(
|
|
27
|
+
q.eq(q.field("userId"), args.userId),
|
|
28
|
+
q.eq(q.field("memorySpaceId"), args.memorySpaceId),
|
|
29
|
+
),
|
|
30
|
+
)
|
|
31
|
+
.first();
|
|
32
|
+
|
|
33
|
+
return user;
|
|
34
|
+
},
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Get users in a memory space
|
|
39
|
+
*/
|
|
40
|
+
export const list = query({
|
|
41
|
+
args: {
|
|
42
|
+
memorySpaceId: v.string(),
|
|
43
|
+
limit: v.optional(v.number()),
|
|
44
|
+
},
|
|
45
|
+
handler: async (ctx, args) => {
|
|
46
|
+
const limit = args.limit ?? 20;
|
|
47
|
+
|
|
48
|
+
const users = await ctx.db
|
|
49
|
+
.query("users")
|
|
50
|
+
.filter((q) => q.eq(q.field("memorySpaceId"), args.memorySpaceId))
|
|
51
|
+
.take(limit);
|
|
52
|
+
|
|
53
|
+
return users;
|
|
54
|
+
},
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Get user stats (memory count, fact count, etc.)
|
|
59
|
+
*/
|
|
60
|
+
export const stats = query({
|
|
61
|
+
args: {
|
|
62
|
+
userId: v.string(),
|
|
63
|
+
memorySpaceId: v.string(),
|
|
64
|
+
},
|
|
65
|
+
handler: async (ctx, args) => {
|
|
66
|
+
// Count memories
|
|
67
|
+
const memories = await ctx.db
|
|
68
|
+
.query("memories")
|
|
69
|
+
.filter((q) =>
|
|
70
|
+
q.and(
|
|
71
|
+
q.eq(q.field("userId"), args.userId),
|
|
72
|
+
q.eq(q.field("memorySpaceId"), args.memorySpaceId),
|
|
73
|
+
),
|
|
74
|
+
)
|
|
75
|
+
.collect();
|
|
76
|
+
|
|
77
|
+
// Count facts
|
|
78
|
+
const facts = await ctx.db
|
|
79
|
+
.query("facts")
|
|
80
|
+
.filter((q) =>
|
|
81
|
+
q.and(
|
|
82
|
+
q.eq(q.field("userId"), args.userId),
|
|
83
|
+
q.eq(q.field("memorySpaceId"), args.memorySpaceId),
|
|
84
|
+
),
|
|
85
|
+
)
|
|
86
|
+
.collect();
|
|
87
|
+
|
|
88
|
+
// Count conversations
|
|
89
|
+
const conversations = await ctx.db
|
|
90
|
+
.query("conversations")
|
|
91
|
+
.filter((q) =>
|
|
92
|
+
q.and(
|
|
93
|
+
q.eq(q.field("userId"), args.userId),
|
|
94
|
+
q.eq(q.field("memorySpaceId"), args.memorySpaceId),
|
|
95
|
+
),
|
|
96
|
+
)
|
|
97
|
+
.collect();
|
|
98
|
+
|
|
99
|
+
return {
|
|
100
|
+
memoryCount: memories.length,
|
|
101
|
+
factCount: facts.length,
|
|
102
|
+
conversationCount: conversations.length,
|
|
103
|
+
};
|
|
104
|
+
},
|
|
105
|
+
});
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Jest Configuration for Vercel AI Quickstart
|
|
3
|
+
*
|
|
4
|
+
* Two test projects:
|
|
5
|
+
* - unit: Fast unit tests with mocked dependencies
|
|
6
|
+
* - integration: Integration tests for API routes with mocked SDK
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
const baseConfig = {
|
|
10
|
+
preset: "ts-jest",
|
|
11
|
+
testEnvironment: "node",
|
|
12
|
+
moduleNameMapper: {
|
|
13
|
+
// Handle path aliases from tsconfig
|
|
14
|
+
"^@/(.*)$": "<rootDir>/$1",
|
|
15
|
+
},
|
|
16
|
+
transform: {
|
|
17
|
+
"^.+\\.tsx?$": [
|
|
18
|
+
"ts-jest",
|
|
19
|
+
{
|
|
20
|
+
tsconfig: "tsconfig.json",
|
|
21
|
+
},
|
|
22
|
+
],
|
|
23
|
+
},
|
|
24
|
+
setupFilesAfterEnv: ["<rootDir>/tests/helpers/setup.ts"],
|
|
25
|
+
// Ignore Next.js build output
|
|
26
|
+
testPathIgnorePatterns: ["/node_modules/", "/.next/"],
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
module.exports = {
|
|
30
|
+
...baseConfig,
|
|
31
|
+
projects: [
|
|
32
|
+
{
|
|
33
|
+
...baseConfig,
|
|
34
|
+
displayName: "unit",
|
|
35
|
+
testMatch: ["<rootDir>/tests/unit/**/*.test.ts"],
|
|
36
|
+
testTimeout: 10000,
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
...baseConfig,
|
|
40
|
+
displayName: "integration",
|
|
41
|
+
testMatch: ["<rootDir>/tests/integration/**/*.test.ts"],
|
|
42
|
+
testTimeout: 30000,
|
|
43
|
+
},
|
|
44
|
+
],
|
|
45
|
+
};
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import type { Variants } from "framer-motion";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Framer Motion animation variants for the layer flow visualization
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
// Layer card entrance animation
|
|
8
|
+
export const layerCardVariants: Variants = {
|
|
9
|
+
hidden: {
|
|
10
|
+
opacity: 0,
|
|
11
|
+
x: -20,
|
|
12
|
+
scale: 0.95,
|
|
13
|
+
},
|
|
14
|
+
visible: (i: number) => ({
|
|
15
|
+
opacity: 1,
|
|
16
|
+
x: 0,
|
|
17
|
+
scale: 1,
|
|
18
|
+
transition: {
|
|
19
|
+
delay: i * 0.1,
|
|
20
|
+
duration: 0.3,
|
|
21
|
+
ease: "easeOut",
|
|
22
|
+
},
|
|
23
|
+
}),
|
|
24
|
+
exit: {
|
|
25
|
+
opacity: 0,
|
|
26
|
+
x: 20,
|
|
27
|
+
transition: {
|
|
28
|
+
duration: 0.2,
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
// Status indicator pulse animation
|
|
34
|
+
export const statusPulseVariants: Variants = {
|
|
35
|
+
pending: {
|
|
36
|
+
scale: 1,
|
|
37
|
+
opacity: 0.5,
|
|
38
|
+
},
|
|
39
|
+
processing: {
|
|
40
|
+
scale: [1, 1.2, 1],
|
|
41
|
+
opacity: [0.5, 1, 0.5],
|
|
42
|
+
transition: {
|
|
43
|
+
duration: 1,
|
|
44
|
+
repeat: Infinity,
|
|
45
|
+
ease: "easeInOut",
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
complete: {
|
|
49
|
+
scale: [1, 1.3, 1],
|
|
50
|
+
opacity: 1,
|
|
51
|
+
transition: {
|
|
52
|
+
duration: 0.3,
|
|
53
|
+
ease: "easeOut",
|
|
54
|
+
},
|
|
55
|
+
},
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
// Flow line animation
|
|
59
|
+
export const flowLineVariants: Variants = {
|
|
60
|
+
idle: {
|
|
61
|
+
opacity: 0.2,
|
|
62
|
+
pathLength: 0,
|
|
63
|
+
},
|
|
64
|
+
flowing: {
|
|
65
|
+
opacity: [0.2, 1, 0.2],
|
|
66
|
+
pathLength: [0, 1, 0],
|
|
67
|
+
transition: {
|
|
68
|
+
duration: 1.5,
|
|
69
|
+
repeat: Infinity,
|
|
70
|
+
ease: "easeInOut",
|
|
71
|
+
},
|
|
72
|
+
},
|
|
73
|
+
complete: {
|
|
74
|
+
opacity: 1,
|
|
75
|
+
pathLength: 1,
|
|
76
|
+
},
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
// Data preview expand animation
|
|
80
|
+
export const dataPreviewVariants: Variants = {
|
|
81
|
+
collapsed: {
|
|
82
|
+
height: 0,
|
|
83
|
+
opacity: 0,
|
|
84
|
+
},
|
|
85
|
+
expanded: {
|
|
86
|
+
height: "auto",
|
|
87
|
+
opacity: 1,
|
|
88
|
+
transition: {
|
|
89
|
+
height: {
|
|
90
|
+
duration: 0.3,
|
|
91
|
+
ease: "easeOut",
|
|
92
|
+
},
|
|
93
|
+
opacity: {
|
|
94
|
+
duration: 0.2,
|
|
95
|
+
delay: 0.1,
|
|
96
|
+
},
|
|
97
|
+
},
|
|
98
|
+
},
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
// Message animation
|
|
102
|
+
export const messageVariants: Variants = {
|
|
103
|
+
hidden: {
|
|
104
|
+
opacity: 0,
|
|
105
|
+
y: 10,
|
|
106
|
+
scale: 0.95,
|
|
107
|
+
},
|
|
108
|
+
visible: {
|
|
109
|
+
opacity: 1,
|
|
110
|
+
y: 0,
|
|
111
|
+
scale: 1,
|
|
112
|
+
transition: {
|
|
113
|
+
duration: 0.2,
|
|
114
|
+
ease: "easeOut",
|
|
115
|
+
},
|
|
116
|
+
},
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
// Stagger children animation
|
|
120
|
+
export const staggerContainerVariants: Variants = {
|
|
121
|
+
hidden: { opacity: 0 },
|
|
122
|
+
visible: {
|
|
123
|
+
opacity: 1,
|
|
124
|
+
transition: {
|
|
125
|
+
staggerChildren: 0.1,
|
|
126
|
+
delayChildren: 0.2,
|
|
127
|
+
},
|
|
128
|
+
},
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
// Glow effect animation (for completed layers)
|
|
132
|
+
export const glowVariants: Variants = {
|
|
133
|
+
idle: {
|
|
134
|
+
boxShadow: "0 0 0 0 rgba(34, 197, 94, 0)",
|
|
135
|
+
},
|
|
136
|
+
glow: {
|
|
137
|
+
boxShadow: [
|
|
138
|
+
"0 0 0 0 rgba(34, 197, 94, 0.4)",
|
|
139
|
+
"0 0 0 10px rgba(34, 197, 94, 0)",
|
|
140
|
+
],
|
|
141
|
+
transition: {
|
|
142
|
+
duration: 0.6,
|
|
143
|
+
ease: "easeOut",
|
|
144
|
+
},
|
|
145
|
+
},
|
|
146
|
+
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cortex SDK Client
|
|
3
|
+
*
|
|
4
|
+
* Shared Cortex client instance for API routes.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { Cortex } from "@cortexmemory/sdk";
|
|
8
|
+
|
|
9
|
+
let cortexClient: Cortex | null = null;
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Get or create a Cortex SDK client
|
|
13
|
+
*/
|
|
14
|
+
export function getCortex(): Cortex {
|
|
15
|
+
if (!cortexClient) {
|
|
16
|
+
const convexUrl = process.env.CONVEX_URL;
|
|
17
|
+
if (!convexUrl) {
|
|
18
|
+
throw new Error("CONVEX_URL environment variable is required");
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
cortexClient = new Cortex({
|
|
22
|
+
convexUrl,
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
return cortexClient;
|
|
27
|
+
}
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { useState, useCallback } from "react";
|
|
4
|
+
|
|
5
|
+
// Layer types (defined locally to avoid import issues before npm install)
|
|
6
|
+
export type MemoryLayer =
|
|
7
|
+
| "memorySpace"
|
|
8
|
+
| "user"
|
|
9
|
+
| "agent"
|
|
10
|
+
| "conversation"
|
|
11
|
+
| "vector"
|
|
12
|
+
| "facts"
|
|
13
|
+
| "graph";
|
|
14
|
+
|
|
15
|
+
export type LayerStatus =
|
|
16
|
+
| "pending"
|
|
17
|
+
| "in_progress"
|
|
18
|
+
| "complete"
|
|
19
|
+
| "error"
|
|
20
|
+
| "skipped";
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Revision action taken by the belief revision system (v0.24.0+)
|
|
24
|
+
* - ADD: New fact was created (no conflicts)
|
|
25
|
+
* - UPDATE: Existing fact was updated with new information
|
|
26
|
+
* - SUPERSEDE: Old fact was superseded by contradicting information
|
|
27
|
+
* - NONE: No action taken (duplicate or irrelevant)
|
|
28
|
+
*/
|
|
29
|
+
export type RevisionAction = "ADD" | "UPDATE" | "SUPERSEDE" | "NONE";
|
|
30
|
+
|
|
31
|
+
export interface LayerState {
|
|
32
|
+
status: LayerStatus;
|
|
33
|
+
latencyMs?: number;
|
|
34
|
+
data?: {
|
|
35
|
+
id?: string;
|
|
36
|
+
preview?: string;
|
|
37
|
+
metadata?: Record<string, unknown>;
|
|
38
|
+
};
|
|
39
|
+
startedAt?: number;
|
|
40
|
+
completedAt?: number;
|
|
41
|
+
/**
|
|
42
|
+
* Revision action taken (v0.24.0+)
|
|
43
|
+
* Only present for facts layer when belief revision is enabled
|
|
44
|
+
*/
|
|
45
|
+
revisionAction?: RevisionAction;
|
|
46
|
+
/**
|
|
47
|
+
* Facts that were superseded by this action (v0.24.0+)
|
|
48
|
+
* Only present when revisionAction is "SUPERSEDE"
|
|
49
|
+
*/
|
|
50
|
+
supersededFacts?: string[];
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export interface LayerTrackingState {
|
|
54
|
+
layers: Record<string, LayerState>;
|
|
55
|
+
isOrchestrating: boolean;
|
|
56
|
+
orchestrationStartTime?: number;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const initialLayerState: LayerState = {
|
|
60
|
+
status: "pending",
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
const allLayers: MemoryLayer[] = [
|
|
64
|
+
"memorySpace",
|
|
65
|
+
"user",
|
|
66
|
+
"agent",
|
|
67
|
+
"conversation",
|
|
68
|
+
"vector",
|
|
69
|
+
"facts",
|
|
70
|
+
"graph",
|
|
71
|
+
];
|
|
72
|
+
|
|
73
|
+
export function useLayerTracking() {
|
|
74
|
+
const [state, setState] = useState<LayerTrackingState>({
|
|
75
|
+
layers: Object.fromEntries(
|
|
76
|
+
allLayers.map((layer) => [layer, { ...initialLayerState }]),
|
|
77
|
+
),
|
|
78
|
+
isOrchestrating: false,
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
const startOrchestration = useCallback(() => {
|
|
82
|
+
const now = Date.now();
|
|
83
|
+
setState({
|
|
84
|
+
layers: Object.fromEntries(
|
|
85
|
+
allLayers.map((layer) => [
|
|
86
|
+
layer,
|
|
87
|
+
{ status: "pending" as LayerStatus, startedAt: now },
|
|
88
|
+
]),
|
|
89
|
+
),
|
|
90
|
+
isOrchestrating: true,
|
|
91
|
+
orchestrationStartTime: now,
|
|
92
|
+
});
|
|
93
|
+
}, []);
|
|
94
|
+
|
|
95
|
+
const updateLayer = useCallback(
|
|
96
|
+
(
|
|
97
|
+
layer: MemoryLayer,
|
|
98
|
+
status: LayerStatus,
|
|
99
|
+
data?: LayerState["data"],
|
|
100
|
+
revisionInfo?: {
|
|
101
|
+
action?: RevisionAction;
|
|
102
|
+
supersededFacts?: string[];
|
|
103
|
+
},
|
|
104
|
+
) => {
|
|
105
|
+
setState((prev: LayerTrackingState) => {
|
|
106
|
+
const now = Date.now();
|
|
107
|
+
const layerState = prev.layers[layer];
|
|
108
|
+
const latencyMs = layerState?.startedAt
|
|
109
|
+
? now - layerState.startedAt
|
|
110
|
+
: prev.orchestrationStartTime
|
|
111
|
+
? now - prev.orchestrationStartTime
|
|
112
|
+
: undefined;
|
|
113
|
+
|
|
114
|
+
// Check if all layers are complete
|
|
115
|
+
const updatedLayers: Record<string, LayerState> = {
|
|
116
|
+
...prev.layers,
|
|
117
|
+
[layer]: {
|
|
118
|
+
...layerState,
|
|
119
|
+
status,
|
|
120
|
+
latencyMs,
|
|
121
|
+
data,
|
|
122
|
+
completedAt: status === "complete" ? now : layerState?.completedAt,
|
|
123
|
+
// Belief revision info (v0.24.0+)
|
|
124
|
+
revisionAction: revisionInfo?.action,
|
|
125
|
+
supersededFacts: revisionInfo?.supersededFacts,
|
|
126
|
+
},
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
const isStillOrchestrating = Object.values(updatedLayers).some(
|
|
130
|
+
(l: LayerState) =>
|
|
131
|
+
l.status === "pending" || l.status === "in_progress",
|
|
132
|
+
);
|
|
133
|
+
|
|
134
|
+
return {
|
|
135
|
+
...prev,
|
|
136
|
+
layers: updatedLayers,
|
|
137
|
+
isOrchestrating: isStillOrchestrating,
|
|
138
|
+
};
|
|
139
|
+
});
|
|
140
|
+
},
|
|
141
|
+
[],
|
|
142
|
+
);
|
|
143
|
+
|
|
144
|
+
const resetLayers = useCallback(() => {
|
|
145
|
+
setState({
|
|
146
|
+
layers: Object.fromEntries(
|
|
147
|
+
allLayers.map((layer) => [layer, { ...initialLayerState }]),
|
|
148
|
+
),
|
|
149
|
+
isOrchestrating: false,
|
|
150
|
+
});
|
|
151
|
+
}, []);
|
|
152
|
+
|
|
153
|
+
return {
|
|
154
|
+
layers: state.layers,
|
|
155
|
+
isOrchestrating: state.isOrchestrating,
|
|
156
|
+
startOrchestration,
|
|
157
|
+
updateLayer,
|
|
158
|
+
resetLayers,
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Generate sample data for layer previews (used in demos)
|
|
164
|
+
*/
|
|
165
|
+
export function generateSampleLayerData(
|
|
166
|
+
layer: MemoryLayer,
|
|
167
|
+
userMessage?: string,
|
|
168
|
+
): LayerState["data"] {
|
|
169
|
+
switch (layer) {
|
|
170
|
+
case "memorySpace":
|
|
171
|
+
return {
|
|
172
|
+
id: "quickstart-demo",
|
|
173
|
+
preview: "Memory space for demo",
|
|
174
|
+
metadata: { isolation: "full" },
|
|
175
|
+
};
|
|
176
|
+
case "user":
|
|
177
|
+
return {
|
|
178
|
+
id: "demo-user",
|
|
179
|
+
preview: "Demo User",
|
|
180
|
+
metadata: { memories: 5 },
|
|
181
|
+
};
|
|
182
|
+
case "agent":
|
|
183
|
+
return {
|
|
184
|
+
id: "quickstart-assistant",
|
|
185
|
+
preview: "Cortex Demo Assistant",
|
|
186
|
+
};
|
|
187
|
+
case "conversation":
|
|
188
|
+
return {
|
|
189
|
+
id: `conv-${Date.now()}`,
|
|
190
|
+
preview: userMessage?.slice(0, 50) || "New conversation",
|
|
191
|
+
metadata: { messages: 2 },
|
|
192
|
+
};
|
|
193
|
+
case "vector":
|
|
194
|
+
return {
|
|
195
|
+
id: `mem-${Date.now()}`,
|
|
196
|
+
preview: "Embedded content...",
|
|
197
|
+
metadata: { dimensions: 1536, importance: 75 },
|
|
198
|
+
};
|
|
199
|
+
case "facts":
|
|
200
|
+
return {
|
|
201
|
+
id: `fact-${Date.now()}`,
|
|
202
|
+
preview: "Extracted facts from conversation",
|
|
203
|
+
metadata: { count: 3, types: ["identity", "preference"] },
|
|
204
|
+
};
|
|
205
|
+
case "graph":
|
|
206
|
+
return {
|
|
207
|
+
id: `graph-sync-${Date.now()}`,
|
|
208
|
+
preview: "Entity relationships",
|
|
209
|
+
metadata: { nodes: 4, edges: 3 },
|
|
210
|
+
};
|
|
211
|
+
default:
|
|
212
|
+
return undefined;
|
|
213
|
+
}
|
|
214
|
+
}
|