@cortexmemory/cli 0.27.4 → 0.28.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commands/db.d.ts.map +1 -1
- package/dist/commands/db.js +18 -6
- package/dist/commands/db.js.map +1 -1
- package/dist/commands/deploy.d.ts.map +1 -1
- package/dist/commands/deploy.js +74 -34
- package/dist/commands/deploy.js.map +1 -1
- package/dist/commands/dev.js +3 -2
- package/dist/commands/dev.js.map +1 -1
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +12 -0
- package/dist/commands/init.js.map +1 -1
- package/dist/types.d.ts +1 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/app-template-sync.d.ts.map +1 -1
- package/dist/utils/app-template-sync.js +3 -1
- package/dist/utils/app-template-sync.js.map +1 -1
- package/dist/utils/init/quickstart-setup.d.ts.map +1 -1
- package/dist/utils/init/quickstart-setup.js.map +1 -1
- package/package.json +4 -4
- package/templates/basic/.env.local.example +23 -0
- package/templates/basic/README.md +181 -56
- package/templates/basic/package-lock.json +2180 -406
- package/templates/basic/package.json +23 -5
- package/templates/basic/src/__tests__/chat.test.ts +340 -0
- package/templates/basic/src/__tests__/cortex.test.ts +260 -0
- package/templates/basic/src/__tests__/display.test.ts +455 -0
- package/templates/basic/src/__tests__/e2e/fact-extraction.test.ts +498 -0
- package/templates/basic/src/__tests__/e2e/memory-flow.test.ts +355 -0
- package/templates/basic/src/__tests__/e2e/server-e2e.test.ts +414 -0
- package/templates/basic/src/__tests__/helpers/test-utils.ts +345 -0
- package/templates/basic/src/__tests__/integration/chat-flow.test.ts +422 -0
- package/templates/basic/src/__tests__/integration/server.test.ts +441 -0
- package/templates/basic/src/__tests__/llm.test.ts +344 -0
- package/templates/basic/src/chat.ts +300 -0
- package/templates/basic/src/cortex.ts +203 -0
- package/templates/basic/src/display.ts +425 -0
- package/templates/basic/src/index.ts +194 -64
- package/templates/basic/src/llm.ts +214 -0
- package/templates/basic/src/server.ts +280 -0
- package/templates/basic/vitest.config.ts +33 -0
- package/templates/basic/vitest.e2e.config.ts +28 -0
- package/templates/basic/vitest.integration.config.ts +25 -0
- package/templates/vercel-ai-quickstart/app/api/auth/check/route.ts +1 -1
- package/templates/vercel-ai-quickstart/app/api/auth/login/route.ts +6 -9
- package/templates/vercel-ai-quickstart/app/api/auth/register/route.ts +14 -18
- package/templates/vercel-ai-quickstart/app/api/auth/setup/route.ts +4 -7
- package/templates/vercel-ai-quickstart/app/api/chat/route.ts +28 -11
- package/templates/vercel-ai-quickstart/app/api/chat-v6/route.ts +19 -13
- package/templates/vercel-ai-quickstart/app/api/conversations/route.ts +16 -16
- package/templates/vercel-ai-quickstart/app/globals.css +24 -9
- package/templates/vercel-ai-quickstart/app/page.tsx +25 -13
- package/templates/vercel-ai-quickstart/components/AdminSetup.tsx +3 -1
- package/templates/vercel-ai-quickstart/components/AuthProvider.tsx +6 -6
- package/templates/vercel-ai-quickstart/components/ChatHistorySidebar.tsx +19 -8
- package/templates/vercel-ai-quickstart/components/ChatInterface.tsx +41 -14
- package/templates/vercel-ai-quickstart/components/LoginScreen.tsx +10 -5
- package/templates/vercel-ai-quickstart/lib/agents/memory-agent.ts +3 -3
- package/templates/vercel-ai-quickstart/lib/password.ts +5 -5
- package/templates/vercel-ai-quickstart/next.config.js +10 -2
- package/templates/vercel-ai-quickstart/package.json +18 -11
- package/templates/vercel-ai-quickstart/test-api.mjs +131 -100
- package/templates/vercel-ai-quickstart/tests/e2e/chat-memory-flow.test.ts +73 -44
- package/templates/vercel-ai-quickstart/tests/helpers/mock-cortex.ts +40 -40
- package/templates/vercel-ai-quickstart/tests/integration/auth.test.ts +8 -8
- package/templates/vercel-ai-quickstart/tests/integration/conversations.test.ts +12 -8
- package/templates/vercel-ai-quickstart/tests/unit/password.test.ts +4 -1
|
@@ -0,0 +1,441 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Integration Tests: HTTP Server
|
|
3
|
+
*
|
|
4
|
+
* Tests HTTP endpoints with mocked internals.
|
|
5
|
+
* Uses Hono's test client for request simulation.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
|
|
9
|
+
import { Hono } from "hono";
|
|
10
|
+
import { generateTestId } from "../helpers/test-utils.js";
|
|
11
|
+
|
|
12
|
+
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
13
|
+
// Types
|
|
14
|
+
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
15
|
+
|
|
16
|
+
interface MockMemory {
|
|
17
|
+
memoryId: string;
|
|
18
|
+
content: string;
|
|
19
|
+
importance: number;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
interface MockFact {
|
|
23
|
+
factId: string;
|
|
24
|
+
fact: string;
|
|
25
|
+
factType: string;
|
|
26
|
+
confidence: number;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
interface MockConversation {
|
|
30
|
+
conversationId: string;
|
|
31
|
+
messages: Array<{ role: string; content: string }>;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
35
|
+
// Test State
|
|
36
|
+
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
37
|
+
|
|
38
|
+
// Mutable state for each test
|
|
39
|
+
let memories: MockMemory[] = [];
|
|
40
|
+
let facts: MockFact[] = [];
|
|
41
|
+
let conversations: Map<string, MockConversation> = new Map();
|
|
42
|
+
let chatResult = {
|
|
43
|
+
response: "Test response",
|
|
44
|
+
conversationId: "conv-test-123",
|
|
45
|
+
memoriesRecalled: 0,
|
|
46
|
+
factsRecalled: 0,
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
// Reset state before each test
|
|
50
|
+
function resetState() {
|
|
51
|
+
memories = [];
|
|
52
|
+
facts = [];
|
|
53
|
+
conversations = new Map();
|
|
54
|
+
chatResult = {
|
|
55
|
+
response: "Test response",
|
|
56
|
+
conversationId: "conv-test-123",
|
|
57
|
+
memoriesRecalled: 0,
|
|
58
|
+
factsRecalled: 0,
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
63
|
+
// Create Test App (mirrors server.ts routes)
|
|
64
|
+
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
65
|
+
|
|
66
|
+
function createTestApp() {
|
|
67
|
+
const app = new Hono();
|
|
68
|
+
|
|
69
|
+
const CONFIG = {
|
|
70
|
+
memorySpaceId: "test-space",
|
|
71
|
+
agentId: "test-agent",
|
|
72
|
+
enableFactExtraction: true,
|
|
73
|
+
enableGraphMemory: false,
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
// Health check
|
|
77
|
+
app.get("/health", (c) => {
|
|
78
|
+
return c.json({
|
|
79
|
+
status: "ok",
|
|
80
|
+
memorySpaceId: CONFIG.memorySpaceId,
|
|
81
|
+
agentId: CONFIG.agentId,
|
|
82
|
+
features: {
|
|
83
|
+
factExtraction: CONFIG.enableFactExtraction,
|
|
84
|
+
graphSync: CONFIG.enableGraphMemory,
|
|
85
|
+
llm: false,
|
|
86
|
+
},
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
// Chat endpoint
|
|
91
|
+
app.post("/chat", async (c) => {
|
|
92
|
+
try {
|
|
93
|
+
const body = await c.req.json();
|
|
94
|
+
const { message, conversationId } = body;
|
|
95
|
+
|
|
96
|
+
if (!message || typeof message !== "string") {
|
|
97
|
+
return c.json({ error: "message is required" }, 400);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const convId = conversationId || generateTestId("conv");
|
|
101
|
+
|
|
102
|
+
return c.json({
|
|
103
|
+
response: chatResult.response,
|
|
104
|
+
conversationId: convId,
|
|
105
|
+
memoriesRecalled: chatResult.memoriesRecalled,
|
|
106
|
+
factsRecalled: chatResult.factsRecalled,
|
|
107
|
+
});
|
|
108
|
+
} catch (error) {
|
|
109
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
110
|
+
return c.json({ error: message }, 500);
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
// Recall endpoint
|
|
115
|
+
app.get("/recall", async (c) => {
|
|
116
|
+
try {
|
|
117
|
+
const query = c.req.query("query");
|
|
118
|
+
|
|
119
|
+
if (!query) {
|
|
120
|
+
return c.json({ error: "query parameter is required" }, 400);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
return c.json({
|
|
124
|
+
memories: memories,
|
|
125
|
+
facts: facts,
|
|
126
|
+
query,
|
|
127
|
+
});
|
|
128
|
+
} catch (error) {
|
|
129
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
130
|
+
return c.json({ error: message }, 500);
|
|
131
|
+
}
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
// Facts endpoint
|
|
135
|
+
app.get("/facts", async (c) => {
|
|
136
|
+
try {
|
|
137
|
+
return c.json({ facts: facts, count: facts.length });
|
|
138
|
+
} catch (error) {
|
|
139
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
140
|
+
return c.json({ error: message }, 500);
|
|
141
|
+
}
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
// History endpoint
|
|
145
|
+
app.get("/history/:conversationId", async (c) => {
|
|
146
|
+
try {
|
|
147
|
+
const conversationId = c.req.param("conversationId");
|
|
148
|
+
const conversation = conversations.get(conversationId);
|
|
149
|
+
|
|
150
|
+
if (!conversation) {
|
|
151
|
+
return c.json({ error: "Conversation not found" }, 404);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
return c.json({
|
|
155
|
+
conversationId,
|
|
156
|
+
messages: conversation.messages,
|
|
157
|
+
messageCount: conversation.messages.length,
|
|
158
|
+
});
|
|
159
|
+
} catch (error) {
|
|
160
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
161
|
+
return c.json({ error: message }, 500);
|
|
162
|
+
}
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
// Root endpoint
|
|
166
|
+
app.get("/", (c) => {
|
|
167
|
+
return c.json({
|
|
168
|
+
name: "Cortex Memory - Basic Demo API",
|
|
169
|
+
version: "1.0.0",
|
|
170
|
+
});
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
return app;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
177
|
+
// Tests
|
|
178
|
+
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
179
|
+
|
|
180
|
+
describe("HTTP Server Integration", () => {
|
|
181
|
+
let app: Hono;
|
|
182
|
+
|
|
183
|
+
beforeEach(() => {
|
|
184
|
+
resetState();
|
|
185
|
+
app = createTestApp();
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
189
|
+
// Health Check
|
|
190
|
+
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
191
|
+
|
|
192
|
+
describe("GET /health", () => {
|
|
193
|
+
it("should return status ok", async () => {
|
|
194
|
+
const res = await app.request("/health");
|
|
195
|
+
const data = await res.json();
|
|
196
|
+
|
|
197
|
+
expect(res.status).toBe(200);
|
|
198
|
+
expect(data.status).toBe("ok");
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
it("should return config information", async () => {
|
|
202
|
+
const res = await app.request("/health");
|
|
203
|
+
const data = await res.json();
|
|
204
|
+
|
|
205
|
+
expect(data.memorySpaceId).toBe("test-space");
|
|
206
|
+
expect(data.agentId).toBe("test-agent");
|
|
207
|
+
expect(data.features).toBeDefined();
|
|
208
|
+
expect(data.features.factExtraction).toBe(true);
|
|
209
|
+
});
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
213
|
+
// Chat Endpoint
|
|
214
|
+
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
215
|
+
|
|
216
|
+
describe("POST /chat", () => {
|
|
217
|
+
it("should process valid chat message", async () => {
|
|
218
|
+
const res = await app.request("/chat", {
|
|
219
|
+
method: "POST",
|
|
220
|
+
headers: { "Content-Type": "application/json" },
|
|
221
|
+
body: JSON.stringify({ message: "Hello, world!" }),
|
|
222
|
+
});
|
|
223
|
+
const data = await res.json();
|
|
224
|
+
|
|
225
|
+
expect(res.status).toBe(200);
|
|
226
|
+
expect(data.response).toBeDefined();
|
|
227
|
+
expect(data.conversationId).toBeDefined();
|
|
228
|
+
expect(data.memoriesRecalled).toBeDefined();
|
|
229
|
+
expect(data.factsRecalled).toBeDefined();
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
it("should use provided conversation ID", async () => {
|
|
233
|
+
const customConvId = "conv-custom-456";
|
|
234
|
+
|
|
235
|
+
const res = await app.request("/chat", {
|
|
236
|
+
method: "POST",
|
|
237
|
+
headers: { "Content-Type": "application/json" },
|
|
238
|
+
body: JSON.stringify({
|
|
239
|
+
message: "Hello",
|
|
240
|
+
conversationId: customConvId,
|
|
241
|
+
}),
|
|
242
|
+
});
|
|
243
|
+
const data = await res.json();
|
|
244
|
+
|
|
245
|
+
expect(res.status).toBe(200);
|
|
246
|
+
expect(data.conversationId).toBe(customConvId);
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
it("should return 400 if message is missing", async () => {
|
|
250
|
+
const res = await app.request("/chat", {
|
|
251
|
+
method: "POST",
|
|
252
|
+
headers: { "Content-Type": "application/json" },
|
|
253
|
+
body: JSON.stringify({}),
|
|
254
|
+
});
|
|
255
|
+
const data = await res.json();
|
|
256
|
+
|
|
257
|
+
expect(res.status).toBe(400);
|
|
258
|
+
expect(data.error).toBe("message is required");
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
it("should return 400 if message is not a string", async () => {
|
|
262
|
+
const res = await app.request("/chat", {
|
|
263
|
+
method: "POST",
|
|
264
|
+
headers: { "Content-Type": "application/json" },
|
|
265
|
+
body: JSON.stringify({ message: 123 }),
|
|
266
|
+
});
|
|
267
|
+
const data = await res.json();
|
|
268
|
+
|
|
269
|
+
expect(res.status).toBe(400);
|
|
270
|
+
expect(data.error).toBe("message is required");
|
|
271
|
+
});
|
|
272
|
+
|
|
273
|
+
it("should include memory and fact counts", async () => {
|
|
274
|
+
chatResult.memoriesRecalled = 3;
|
|
275
|
+
chatResult.factsRecalled = 2;
|
|
276
|
+
|
|
277
|
+
const res = await app.request("/chat", {
|
|
278
|
+
method: "POST",
|
|
279
|
+
headers: { "Content-Type": "application/json" },
|
|
280
|
+
body: JSON.stringify({ message: "What do you know?" }),
|
|
281
|
+
});
|
|
282
|
+
const data = await res.json();
|
|
283
|
+
|
|
284
|
+
expect(res.status).toBe(200);
|
|
285
|
+
expect(data.memoriesRecalled).toBe(3);
|
|
286
|
+
expect(data.factsRecalled).toBe(2);
|
|
287
|
+
});
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
291
|
+
// Recall Endpoint
|
|
292
|
+
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
293
|
+
|
|
294
|
+
describe("GET /recall", () => {
|
|
295
|
+
it("should return memories and facts for query", async () => {
|
|
296
|
+
// Add test data
|
|
297
|
+
memories.push({
|
|
298
|
+
memoryId: "mem-1",
|
|
299
|
+
content: "Test memory",
|
|
300
|
+
importance: 80,
|
|
301
|
+
});
|
|
302
|
+
facts.push({
|
|
303
|
+
factId: "fact-1",
|
|
304
|
+
fact: "Test fact",
|
|
305
|
+
factType: "knowledge",
|
|
306
|
+
confidence: 90,
|
|
307
|
+
});
|
|
308
|
+
|
|
309
|
+
const res = await app.request("/recall?query=test");
|
|
310
|
+
const data = await res.json();
|
|
311
|
+
|
|
312
|
+
expect(res.status).toBe(200);
|
|
313
|
+
expect(data.memories).toBeDefined();
|
|
314
|
+
expect(data.memories.length).toBe(1);
|
|
315
|
+
expect(data.facts).toBeDefined();
|
|
316
|
+
expect(data.facts.length).toBe(1);
|
|
317
|
+
expect(data.query).toBe("test");
|
|
318
|
+
});
|
|
319
|
+
|
|
320
|
+
it("should return 400 if query is missing", async () => {
|
|
321
|
+
const res = await app.request("/recall");
|
|
322
|
+
const data = await res.json();
|
|
323
|
+
|
|
324
|
+
expect(res.status).toBe(400);
|
|
325
|
+
expect(data.error).toBe("query parameter is required");
|
|
326
|
+
});
|
|
327
|
+
|
|
328
|
+
it("should return empty arrays when no memories found", async () => {
|
|
329
|
+
const res = await app.request("/recall?query=nonexistent");
|
|
330
|
+
const data = await res.json();
|
|
331
|
+
|
|
332
|
+
expect(res.status).toBe(200);
|
|
333
|
+
expect(data.memories).toEqual([]);
|
|
334
|
+
expect(data.facts).toEqual([]);
|
|
335
|
+
});
|
|
336
|
+
});
|
|
337
|
+
|
|
338
|
+
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
339
|
+
// Facts Endpoint
|
|
340
|
+
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
341
|
+
|
|
342
|
+
describe("GET /facts", () => {
|
|
343
|
+
it("should return list of facts", async () => {
|
|
344
|
+
facts.push({
|
|
345
|
+
factId: "fact-1",
|
|
346
|
+
fact: "User likes coffee",
|
|
347
|
+
factType: "preference",
|
|
348
|
+
confidence: 85,
|
|
349
|
+
});
|
|
350
|
+
facts.push({
|
|
351
|
+
factId: "fact-2",
|
|
352
|
+
fact: "User is a developer",
|
|
353
|
+
factType: "occupation",
|
|
354
|
+
confidence: 90,
|
|
355
|
+
});
|
|
356
|
+
|
|
357
|
+
const res = await app.request("/facts");
|
|
358
|
+
const data = await res.json();
|
|
359
|
+
|
|
360
|
+
expect(res.status).toBe(200);
|
|
361
|
+
expect(data.facts).toBeDefined();
|
|
362
|
+
expect(data.facts.length).toBe(2);
|
|
363
|
+
expect(data.count).toBe(2);
|
|
364
|
+
});
|
|
365
|
+
|
|
366
|
+
it("should return empty array when no facts exist", async () => {
|
|
367
|
+
const res = await app.request("/facts");
|
|
368
|
+
const data = await res.json();
|
|
369
|
+
|
|
370
|
+
expect(res.status).toBe(200);
|
|
371
|
+
expect(data.facts).toEqual([]);
|
|
372
|
+
expect(data.count).toBe(0);
|
|
373
|
+
});
|
|
374
|
+
});
|
|
375
|
+
|
|
376
|
+
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
377
|
+
// History Endpoint
|
|
378
|
+
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
379
|
+
|
|
380
|
+
describe("GET /history/:conversationId", () => {
|
|
381
|
+
it("should return conversation history", async () => {
|
|
382
|
+
// Add conversation
|
|
383
|
+
conversations.set("conv-123", {
|
|
384
|
+
conversationId: "conv-123",
|
|
385
|
+
messages: [
|
|
386
|
+
{ role: "user", content: "Hello" },
|
|
387
|
+
{ role: "assistant", content: "Hi there!" },
|
|
388
|
+
],
|
|
389
|
+
});
|
|
390
|
+
|
|
391
|
+
const res = await app.request("/history/conv-123");
|
|
392
|
+
const data = await res.json();
|
|
393
|
+
|
|
394
|
+
expect(res.status).toBe(200);
|
|
395
|
+
expect(data.conversationId).toBe("conv-123");
|
|
396
|
+
expect(data.messages).toBeDefined();
|
|
397
|
+
expect(data.messageCount).toBe(2);
|
|
398
|
+
});
|
|
399
|
+
|
|
400
|
+
it("should return 404 for non-existent conversation", async () => {
|
|
401
|
+
const res = await app.request("/history/nonexistent-conv");
|
|
402
|
+
const data = await res.json();
|
|
403
|
+
|
|
404
|
+
expect(res.status).toBe(404);
|
|
405
|
+
expect(data.error).toBe("Conversation not found");
|
|
406
|
+
});
|
|
407
|
+
|
|
408
|
+
it("should return message count", async () => {
|
|
409
|
+
conversations.set("conv-456", {
|
|
410
|
+
conversationId: "conv-456",
|
|
411
|
+
messages: [
|
|
412
|
+
{ role: "user", content: "First" },
|
|
413
|
+
{ role: "assistant", content: "First reply" },
|
|
414
|
+
{ role: "user", content: "Second" },
|
|
415
|
+
{ role: "assistant", content: "Second reply" },
|
|
416
|
+
],
|
|
417
|
+
});
|
|
418
|
+
|
|
419
|
+
const res = await app.request("/history/conv-456");
|
|
420
|
+
const data = await res.json();
|
|
421
|
+
|
|
422
|
+
expect(res.status).toBe(200);
|
|
423
|
+
expect(data.messageCount).toBe(4);
|
|
424
|
+
});
|
|
425
|
+
});
|
|
426
|
+
|
|
427
|
+
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
428
|
+
// Root Endpoint
|
|
429
|
+
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
430
|
+
|
|
431
|
+
describe("GET /", () => {
|
|
432
|
+
it("should return API info", async () => {
|
|
433
|
+
const res = await app.request("/");
|
|
434
|
+
const data = await res.json();
|
|
435
|
+
|
|
436
|
+
expect(res.status).toBe(200);
|
|
437
|
+
expect(data.name).toContain("Cortex Memory");
|
|
438
|
+
expect(data.version).toBeDefined();
|
|
439
|
+
});
|
|
440
|
+
});
|
|
441
|
+
});
|