@node-llm/orm 0.4.0 → 0.5.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/CHANGELOG.md +38 -2
- package/README.md +94 -8
- package/bin/cli.js +40 -6
- package/dist/adapters/prisma/AgentSession.d.ts +140 -0
- package/dist/adapters/prisma/AgentSession.d.ts.map +1 -0
- package/dist/adapters/prisma/AgentSession.js +284 -0
- package/dist/adapters/prisma/index.d.ts +25 -2
- package/dist/adapters/prisma/index.d.ts.map +1 -1
- package/dist/adapters/prisma/index.js +25 -1
- package/dist/index.d.ts +21 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +21 -1
- package/migrations/README.md +53 -0
- package/migrations/add_agent_session.sql +44 -0
- package/migrations/add_thinking_support.sql +34 -0
- package/package.json +5 -1
- package/schema.prisma +50 -33
- package/src/adapters/prisma/AgentSession.ts +458 -0
- package/src/adapters/prisma/index.ts +33 -2
- package/src/index.ts +21 -1
- package/test/AgentSession.test.ts +204 -0
- package/test/CodeWins.test.ts +116 -0
- package/test/docs/prisma-docs.test.ts +221 -0
- package/test/docs/readme-exports.test.ts +62 -0
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
import { describe, it, expect, vi, beforeEach } from "vitest";
|
|
2
|
+
import { Agent, Tool, NodeLLM } from "@node-llm/core";
|
|
3
|
+
import { createAgentSession, loadAgentSession } from "../src/adapters/prisma/AgentSession";
|
|
4
|
+
|
|
5
|
+
// --- Mocks ---
|
|
6
|
+
|
|
7
|
+
// Mock Prisma Client
|
|
8
|
+
const mockPrisma = {
|
|
9
|
+
llmChat: {
|
|
10
|
+
create: vi.fn(),
|
|
11
|
+
findUnique: vi.fn()
|
|
12
|
+
},
|
|
13
|
+
llmAgentSession: {
|
|
14
|
+
create: vi.fn(),
|
|
15
|
+
findUnique: vi.fn()
|
|
16
|
+
},
|
|
17
|
+
llmMessage: {
|
|
18
|
+
create: vi.fn(),
|
|
19
|
+
findMany: vi.fn(),
|
|
20
|
+
update: vi.fn(),
|
|
21
|
+
delete: vi.fn()
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
// Mock LLM
|
|
26
|
+
const createMockChat = () => {
|
|
27
|
+
const mockChat = {
|
|
28
|
+
withInstructions: vi.fn().mockReturnThis(),
|
|
29
|
+
withTools: vi.fn().mockReturnThis(),
|
|
30
|
+
withSchema: vi.fn().mockReturnThis(),
|
|
31
|
+
ask: vi.fn().mockResolvedValue({
|
|
32
|
+
content: "Response",
|
|
33
|
+
meta: {},
|
|
34
|
+
usage: { input_tokens: 10, output_tokens: 5 }
|
|
35
|
+
}),
|
|
36
|
+
stream: vi.fn(),
|
|
37
|
+
history: [],
|
|
38
|
+
totalUsage: { input_tokens: 0, output_tokens: 0 },
|
|
39
|
+
modelId: "mock-model",
|
|
40
|
+
// Hook methods required by Agent constructor
|
|
41
|
+
beforeRequest: vi.fn().mockReturnThis(),
|
|
42
|
+
onToolCallStart: vi.fn().mockReturnThis(),
|
|
43
|
+
onToolCallEnd: vi.fn().mockReturnThis(),
|
|
44
|
+
onToolCallError: vi.fn().mockReturnThis(),
|
|
45
|
+
onEndMessage: vi.fn().mockReturnThis()
|
|
46
|
+
};
|
|
47
|
+
return mockChat;
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
const mockLlm = {
|
|
51
|
+
chat: vi.fn().mockImplementation(() => createMockChat())
|
|
52
|
+
} as unknown as typeof NodeLLM;
|
|
53
|
+
|
|
54
|
+
// --- Test Classes ---
|
|
55
|
+
|
|
56
|
+
class TestAgent extends Agent {
|
|
57
|
+
static model = "gpt-4-test";
|
|
58
|
+
static instructions = "Test instructions";
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
describe("AgentSession", () => {
|
|
62
|
+
beforeEach(() => {
|
|
63
|
+
vi.clearAllMocks();
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
describe("createAgentSession", () => {
|
|
67
|
+
it("creates a new session with correct metadata", async () => {
|
|
68
|
+
// Setup mocks
|
|
69
|
+
mockPrisma.llmChat.create.mockResolvedValue({ id: "chat-123" });
|
|
70
|
+
mockPrisma.llmAgentSession.create.mockResolvedValue({
|
|
71
|
+
id: "session-123",
|
|
72
|
+
chatId: "chat-123",
|
|
73
|
+
agentClass: "TestAgent",
|
|
74
|
+
metadata: { userId: "user-1" }
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
const session = await createAgentSession(mockPrisma as any, mockLlm, TestAgent, {
|
|
78
|
+
metadata: { userId: "user-1" }
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
// Verify DB calls
|
|
82
|
+
expect(mockPrisma.llmChat.create).toHaveBeenCalledWith(
|
|
83
|
+
expect.objectContaining({
|
|
84
|
+
data: expect.objectContaining({
|
|
85
|
+
model: "gpt-4-test",
|
|
86
|
+
instructions: "Test instructions"
|
|
87
|
+
})
|
|
88
|
+
})
|
|
89
|
+
);
|
|
90
|
+
|
|
91
|
+
expect(mockPrisma.llmAgentSession.create).toHaveBeenCalledWith(
|
|
92
|
+
expect.objectContaining({
|
|
93
|
+
data: expect.objectContaining({
|
|
94
|
+
agentClass: "TestAgent",
|
|
95
|
+
chatId: "chat-123",
|
|
96
|
+
metadata: { userId: "user-1" }
|
|
97
|
+
})
|
|
98
|
+
})
|
|
99
|
+
);
|
|
100
|
+
|
|
101
|
+
// Verify Session Object
|
|
102
|
+
expect(session.id).toBe("session-123");
|
|
103
|
+
expect(session.metadata).toEqual({ userId: "user-1" });
|
|
104
|
+
expect(session.agentClass).toBe("TestAgent");
|
|
105
|
+
});
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
describe("loadAgentSession", () => {
|
|
109
|
+
it("loads an existing session and injects history", async () => {
|
|
110
|
+
// Setup Mocks
|
|
111
|
+
mockPrisma.llmAgentSession.findUnique.mockResolvedValue({
|
|
112
|
+
id: "session-123",
|
|
113
|
+
chatId: "chat-123",
|
|
114
|
+
agentClass: "TestAgent",
|
|
115
|
+
metadata: { userId: "user-1" }
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
mockPrisma.llmMessage.findMany.mockResolvedValue([
|
|
119
|
+
{ role: "user", content: "Hello" },
|
|
120
|
+
{ role: "assistant", content: "Hi there" }
|
|
121
|
+
]);
|
|
122
|
+
|
|
123
|
+
const session = await loadAgentSession(mockPrisma as any, mockLlm, TestAgent, "session-123");
|
|
124
|
+
|
|
125
|
+
expect(session).not.toBeNull();
|
|
126
|
+
expect(session?.id).toBe("session-123");
|
|
127
|
+
|
|
128
|
+
// Verify history injection (implicit via mock setup, would check agent internals in real integration)
|
|
129
|
+
// Implementation detail: The Agent constructor is called with { messages: [...] }
|
|
130
|
+
// We can verify this by checking if the agent property exists and works
|
|
131
|
+
|
|
132
|
+
expect(mockPrisma.llmMessage.findMany).toHaveBeenCalledWith(
|
|
133
|
+
expect.objectContaining({
|
|
134
|
+
where: { chatId: "chat-123" },
|
|
135
|
+
orderBy: { createdAt: "asc" }
|
|
136
|
+
})
|
|
137
|
+
);
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
it("throws error on agent class mismatch", async () => {
|
|
141
|
+
mockPrisma.llmAgentSession.findUnique.mockResolvedValue({
|
|
142
|
+
id: "session-123",
|
|
143
|
+
agentClass: "OtherAgent", // Mismatch
|
|
144
|
+
chatId: "chat-123"
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
await expect(
|
|
148
|
+
loadAgentSession(mockPrisma as any, mockLlm, TestAgent, "session-123")
|
|
149
|
+
).rejects.toThrow("Agent class mismatch");
|
|
150
|
+
});
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
describe("ask", () => {
|
|
154
|
+
it("persists user and assistant messages", async () => {
|
|
155
|
+
// Setup Session
|
|
156
|
+
const sessionRecord = {
|
|
157
|
+
id: "session-123",
|
|
158
|
+
chatId: "chat-123",
|
|
159
|
+
agentClass: "TestAgent",
|
|
160
|
+
metadata: {},
|
|
161
|
+
createdAt: new Date(),
|
|
162
|
+
updatedAt: new Date()
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
// Mock AgentSession manually to test .ask()
|
|
166
|
+
// But simpler to use createAgentSession mock return if we could,
|
|
167
|
+
// here we instantiate directly or via factory.
|
|
168
|
+
|
|
169
|
+
mockPrisma.llmChat.create.mockResolvedValue({ id: "chat-123" });
|
|
170
|
+
mockPrisma.llmAgentSession.create.mockResolvedValue(sessionRecord);
|
|
171
|
+
|
|
172
|
+
const session = await createAgentSession(mockPrisma as any, mockLlm, TestAgent);
|
|
173
|
+
|
|
174
|
+
// Mock message creation
|
|
175
|
+
mockPrisma.llmMessage.create
|
|
176
|
+
.mockResolvedValueOnce({ id: "msg-user" }) // User message
|
|
177
|
+
.mockResolvedValueOnce({ id: "msg-asst" }); // Assistant placeholder
|
|
178
|
+
|
|
179
|
+
mockPrisma.llmMessage.update.mockResolvedValue({
|
|
180
|
+
id: "msg-asst",
|
|
181
|
+
content: "Response",
|
|
182
|
+
role: "assistant"
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
await session.ask("Hello");
|
|
186
|
+
|
|
187
|
+
// Verify persistence
|
|
188
|
+
expect(mockPrisma.llmMessage.create).toHaveBeenCalledTimes(2);
|
|
189
|
+
expect(mockPrisma.llmMessage.create).toHaveBeenNthCalledWith(
|
|
190
|
+
1,
|
|
191
|
+
expect.objectContaining({
|
|
192
|
+
data: expect.objectContaining({ role: "user", content: "Hello" })
|
|
193
|
+
})
|
|
194
|
+
);
|
|
195
|
+
|
|
196
|
+
expect(mockPrisma.llmMessage.update).toHaveBeenCalledWith(
|
|
197
|
+
expect.objectContaining({
|
|
198
|
+
where: { id: "msg-asst" },
|
|
199
|
+
data: expect.objectContaining({ content: "Response" })
|
|
200
|
+
})
|
|
201
|
+
);
|
|
202
|
+
});
|
|
203
|
+
});
|
|
204
|
+
});
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { describe, it, expect, vi, beforeEach } from "vitest";
|
|
2
|
+
import { PrismaClient } from "@prisma/client";
|
|
3
|
+
import { NodeLLMCore, Agent } from "@node-llm/core";
|
|
4
|
+
import { createAgentSession, loadAgentSession } from "../src/adapters/prisma/AgentSession.js";
|
|
5
|
+
|
|
6
|
+
// Mock Prisma
|
|
7
|
+
const mockChatTable = {
|
|
8
|
+
create: vi.fn(),
|
|
9
|
+
findUnique: vi.fn(),
|
|
10
|
+
update: vi.fn()
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
const mockSessionTable = {
|
|
14
|
+
create: vi.fn(),
|
|
15
|
+
findUnique: vi.fn()
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
const mockMessageTable = {
|
|
19
|
+
create: vi.fn(),
|
|
20
|
+
findMany: vi.fn(),
|
|
21
|
+
delete: vi.fn(),
|
|
22
|
+
update: vi.fn()
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const prisma = {
|
|
26
|
+
llmChat: mockChatTable,
|
|
27
|
+
llmAgentSession: mockSessionTable,
|
|
28
|
+
llmMessage: mockMessageTable
|
|
29
|
+
} as unknown as PrismaClient;
|
|
30
|
+
|
|
31
|
+
// Mock Agent & LLM
|
|
32
|
+
class TestAgent extends Agent {
|
|
33
|
+
static override model = "agent-model";
|
|
34
|
+
static override instructions = "agent-instructions";
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const mockChat = {
|
|
38
|
+
withInstructions: vi.fn().mockReturnThis(),
|
|
39
|
+
withTools: vi.fn().mockReturnThis(),
|
|
40
|
+
withSchema: vi.fn().mockReturnThis(),
|
|
41
|
+
beforeRequest: vi.fn().mockReturnThis(),
|
|
42
|
+
onToolCallStart: vi.fn().mockReturnThis(),
|
|
43
|
+
onToolCallEnd: vi.fn().mockReturnThis(),
|
|
44
|
+
onToolCallError: vi.fn().mockReturnThis(),
|
|
45
|
+
onEndMessage: vi.fn().mockReturnThis(),
|
|
46
|
+
ask: vi.fn(),
|
|
47
|
+
messages: [],
|
|
48
|
+
modelId: "agent-model"
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
const llm = {
|
|
52
|
+
chat: vi.fn(() => mockChat)
|
|
53
|
+
} as unknown as NodeLLMCore;
|
|
54
|
+
|
|
55
|
+
describe("AgentSession - Code Wins Sovereignty", () => {
|
|
56
|
+
beforeEach(() => {
|
|
57
|
+
vi.clearAllMocks();
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it("should prioritize Agent class instructions over DB instructions when loading a session", async () => {
|
|
61
|
+
const sessionId = "sess_123";
|
|
62
|
+
const chatId = "chat_456";
|
|
63
|
+
|
|
64
|
+
// 1. Mock DB returning DIFFERENT instructions than the class
|
|
65
|
+
mockSessionTable.findUnique.mockResolvedValue({
|
|
66
|
+
id: sessionId,
|
|
67
|
+
chatId: chatId,
|
|
68
|
+
agentClass: "TestAgent"
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
mockChatTable.findUnique.mockResolvedValue({
|
|
72
|
+
id: chatId,
|
|
73
|
+
model: "db-model", // DB says db-model
|
|
74
|
+
instructions: "db-instructions" // DB says db-instructions
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
mockMessageTable.findMany.mockResolvedValue([]);
|
|
78
|
+
|
|
79
|
+
// 2. Load the session
|
|
80
|
+
const session = await loadAgentSession(prisma, llm, TestAgent, sessionId);
|
|
81
|
+
|
|
82
|
+
expect(session).toBeDefined();
|
|
83
|
+
|
|
84
|
+
// 3. Verify Agent was instantiated with the correct LLM and history (empty here)
|
|
85
|
+
// The Agent constructor calls llm.chat(model, options)
|
|
86
|
+
expect(llm.chat).toHaveBeenCalledWith("agent-model", expect.any(Object));
|
|
87
|
+
|
|
88
|
+
// 4. Verify instructions applied to chat came from TestAgent.instructions
|
|
89
|
+
expect(mockChat.withInstructions).toHaveBeenCalledWith("agent-instructions");
|
|
90
|
+
expect(mockChat.withInstructions).not.toHaveBeenCalledWith("db-instructions");
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
it("should prioritize Agent class model over DB model when creating a session", async () => {
|
|
94
|
+
mockChatTable.create.mockResolvedValue({ id: "chat_789" });
|
|
95
|
+
mockSessionTable.create.mockResolvedValue({
|
|
96
|
+
id: "sess_789",
|
|
97
|
+
chatId: "chat_789",
|
|
98
|
+
agentClass: "TestAgent"
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
// 1. Create a session
|
|
102
|
+
await createAgentSession(prisma, llm, TestAgent);
|
|
103
|
+
|
|
104
|
+
// 2. Verify chat record was created with Agent class properties
|
|
105
|
+
expect(mockChatTable.create).toHaveBeenCalledWith({
|
|
106
|
+
data: expect.objectContaining({
|
|
107
|
+
model: "agent-model",
|
|
108
|
+
instructions: "agent-instructions"
|
|
109
|
+
})
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
// 3. Verify the live agent instance also uses these
|
|
113
|
+
expect(llm.chat).toHaveBeenCalledWith("agent-model", expect.any(Object));
|
|
114
|
+
expect(mockChat.withInstructions).toHaveBeenCalledWith("agent-instructions");
|
|
115
|
+
});
|
|
116
|
+
});
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Documentation Verification Tests: docs/orm/prisma.md
|
|
3
|
+
*
|
|
4
|
+
* Verifies that all code patterns from the Prisma integration docs work correctly.
|
|
5
|
+
* Tests verify API signatures without requiring an actual database connection.
|
|
6
|
+
*/
|
|
7
|
+
import { describe, it, expect } from "vitest";
|
|
8
|
+
import { createChat, loadChat, Chat } from "../../src/adapters/prisma/index.js";
|
|
9
|
+
|
|
10
|
+
describe("prisma-docs", () => {
|
|
11
|
+
describe("createChat() Function", () => {
|
|
12
|
+
it("createChat is a function accepting 3 arguments", () => {
|
|
13
|
+
// Per docs: const chat = await createChat(prisma, llm, { model: "gpt-4o", ... })
|
|
14
|
+
expect(typeof createChat).toBe("function");
|
|
15
|
+
// createChat(prisma, llm, options)
|
|
16
|
+
expect(createChat.length).toBeGreaterThanOrEqual(2);
|
|
17
|
+
});
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
describe("loadChat() Function", () => {
|
|
21
|
+
it("loadChat is a function accepting 3 arguments", () => {
|
|
22
|
+
// Per docs: const savedChat = await loadChat(prisma, llm, "chat-uuid-123")
|
|
23
|
+
expect(typeof loadChat).toBe("function");
|
|
24
|
+
// loadChat(prisma, llm, chatId)
|
|
25
|
+
expect(loadChat.length).toBeGreaterThanOrEqual(2);
|
|
26
|
+
});
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
describe("ChatOptions Interface", () => {
|
|
30
|
+
it("model option is documented", () => {
|
|
31
|
+
// Per docs: { model: "gpt-4o", ... }
|
|
32
|
+
const options = { model: "gpt-4o" };
|
|
33
|
+
expect(options.model).toBe("gpt-4o");
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it("instructions option is documented", () => {
|
|
37
|
+
// Per docs: { instructions: "You are a helpful assistant.", ... }
|
|
38
|
+
const options = { instructions: "You are a helpful assistant." };
|
|
39
|
+
expect(options.instructions).toBe("You are a helpful assistant.");
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it("thinking option is documented", () => {
|
|
43
|
+
// Per docs: { thinking: { budget: 16000 } }
|
|
44
|
+
const options = { thinking: { budget: 16000 } };
|
|
45
|
+
expect(options.thinking.budget).toBe(16000);
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it("tableNames option is documented", () => {
|
|
49
|
+
// Per docs: { tableNames: { chat: "AssistantChat", message: "AssistantMessage", ... } }
|
|
50
|
+
const options = {
|
|
51
|
+
tableNames: {
|
|
52
|
+
chat: "AssistantChat",
|
|
53
|
+
message: "AssistantMessage",
|
|
54
|
+
toolCall: "AssistantToolCall",
|
|
55
|
+
request: "AssistantRequest"
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
expect(options.tableNames.chat).toBe("AssistantChat");
|
|
59
|
+
expect(options.tableNames.message).toBe("AssistantMessage");
|
|
60
|
+
expect(options.tableNames.toolCall).toBe("AssistantToolCall");
|
|
61
|
+
expect(options.tableNames.request).toBe("AssistantRequest");
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
describe("TableNames Interface", () => {
|
|
66
|
+
it("supports custom chat table name", () => {
|
|
67
|
+
// Per docs: tableNames: { chat: "AssistantChat", ... }
|
|
68
|
+
const tableNames = { chat: "AssistantChat" };
|
|
69
|
+
expect(tableNames.chat).toBe("AssistantChat");
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
it("supports custom message table name", () => {
|
|
73
|
+
// Per docs: tableNames: { message: "AssistantMessage", ... }
|
|
74
|
+
const tableNames = { message: "AssistantMessage" };
|
|
75
|
+
expect(tableNames.message).toBe("AssistantMessage");
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
it("supports custom toolCall table name", () => {
|
|
79
|
+
// Per docs: tableNames: { toolCall: "AssistantToolCall", ... }
|
|
80
|
+
const tableNames = { toolCall: "AssistantToolCall" };
|
|
81
|
+
expect(tableNames.toolCall).toBe("AssistantToolCall");
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
it("supports custom request table name", () => {
|
|
85
|
+
// Per docs: tableNames: { request: "AssistantRequest", ... }
|
|
86
|
+
const tableNames = { request: "AssistantRequest" };
|
|
87
|
+
expect(tableNames.request).toBe("AssistantRequest");
|
|
88
|
+
});
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
describe("Default Table Names", () => {
|
|
92
|
+
it("default chat table is llmChat", () => {
|
|
93
|
+
// Per docs: model LlmChat { ... }
|
|
94
|
+
const defaultNames = {
|
|
95
|
+
chat: "llmChat",
|
|
96
|
+
message: "llmMessage",
|
|
97
|
+
toolCall: "llmToolCall",
|
|
98
|
+
request: "llmRequest"
|
|
99
|
+
};
|
|
100
|
+
expect(defaultNames.chat).toBe("llmChat");
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
it("default message table is llmMessage", () => {
|
|
104
|
+
// Per docs: model LlmMessage { ... }
|
|
105
|
+
const defaultNames = { message: "llmMessage" };
|
|
106
|
+
expect(defaultNames.message).toBe("llmMessage");
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
it("default toolCall table is llmToolCall", () => {
|
|
110
|
+
// Per docs: model LlmToolCall { ... }
|
|
111
|
+
const defaultNames = { toolCall: "llmToolCall" };
|
|
112
|
+
expect(defaultNames.toolCall).toBe("llmToolCall");
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
it("default request table is llmRequest", () => {
|
|
116
|
+
// Per docs: model LlmRequest { ... }
|
|
117
|
+
const defaultNames = { request: "llmRequest" };
|
|
118
|
+
expect(defaultNames.request).toBe("llmRequest");
|
|
119
|
+
});
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
describe("Chat Class Structure", () => {
|
|
123
|
+
it("Chat class is exported", () => {
|
|
124
|
+
// Per docs: Chat instance methods like ask(), askStream(), messages(), stats()
|
|
125
|
+
expect(Chat).toBeDefined();
|
|
126
|
+
expect(typeof Chat).toBe("function");
|
|
127
|
+
});
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
describe("Prisma Schema Fields (LlmChat)", () => {
|
|
131
|
+
it("schema includes id field", () => {
|
|
132
|
+
// Per docs: id String @id @default(uuid())
|
|
133
|
+
const field = { name: "id", type: "String", decorator: "@id @default(uuid())" };
|
|
134
|
+
expect(field.name).toBe("id");
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
it("schema includes model field", () => {
|
|
138
|
+
// Per docs: model String?
|
|
139
|
+
const field = { name: "model", type: "String?" };
|
|
140
|
+
expect(field.name).toBe("model");
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
it("schema includes provider field", () => {
|
|
144
|
+
// Per docs: provider String?
|
|
145
|
+
const field = { name: "provider", type: "String?" };
|
|
146
|
+
expect(field.name).toBe("provider");
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
it("schema includes instructions field", () => {
|
|
150
|
+
// Per docs: instructions String?
|
|
151
|
+
const field = { name: "instructions", type: "String?" };
|
|
152
|
+
expect(field.name).toBe("instructions");
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
it("schema includes metadata field", () => {
|
|
156
|
+
// Per docs: metadata Json?
|
|
157
|
+
const field = { name: "metadata", type: "Json?" };
|
|
158
|
+
expect(field.name).toBe("metadata");
|
|
159
|
+
});
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
describe("Prisma Schema Fields (LlmMessage)", () => {
|
|
163
|
+
it("schema includes thinkingText field", () => {
|
|
164
|
+
// Per docs: thinkingText String?
|
|
165
|
+
const field = { name: "thinkingText", type: "String?" };
|
|
166
|
+
expect(field.name).toBe("thinkingText");
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
it("schema includes thinkingSignature field", () => {
|
|
170
|
+
// Per docs: thinkingSignature String?
|
|
171
|
+
const field = { name: "thinkingSignature", type: "String?" };
|
|
172
|
+
expect(field.name).toBe("thinkingSignature");
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
it("schema includes thinkingTokens field", () => {
|
|
176
|
+
// Per docs: thinkingTokens Int?
|
|
177
|
+
const field = { name: "thinkingTokens", type: "Int?" };
|
|
178
|
+
expect(field.name).toBe("thinkingTokens");
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
it("schema includes inputTokens field", () => {
|
|
182
|
+
// Per docs: inputTokens Int?
|
|
183
|
+
const field = { name: "inputTokens", type: "Int?" };
|
|
184
|
+
expect(field.name).toBe("inputTokens");
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
it("schema includes outputTokens field", () => {
|
|
188
|
+
// Per docs: outputTokens Int?
|
|
189
|
+
const field = { name: "outputTokens", type: "Int?" };
|
|
190
|
+
expect(field.name).toBe("outputTokens");
|
|
191
|
+
});
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
describe("Prisma Schema Fields (LlmToolCall)", () => {
|
|
195
|
+
it("schema includes thought field", () => {
|
|
196
|
+
// Per docs: thought String?
|
|
197
|
+
const field = { name: "thought", type: "String?" };
|
|
198
|
+
expect(field.name).toBe("thought");
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
it("schema includes thoughtSignature field", () => {
|
|
202
|
+
// Per docs: thoughtSignature String?
|
|
203
|
+
const field = { name: "thoughtSignature", type: "String?" };
|
|
204
|
+
expect(field.name).toBe("thoughtSignature");
|
|
205
|
+
});
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
describe("Prisma Schema Fields (LlmRequest)", () => {
|
|
209
|
+
it("schema includes cost field", () => {
|
|
210
|
+
// Per docs: cost Float?
|
|
211
|
+
const field = { name: "cost", type: "Float?" };
|
|
212
|
+
expect(field.name).toBe("cost");
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
it("schema includes duration field", () => {
|
|
216
|
+
// Per docs: duration Int (milliseconds)
|
|
217
|
+
const field = { name: "duration", type: "Int" };
|
|
218
|
+
expect(field.name).toBe("duration");
|
|
219
|
+
});
|
|
220
|
+
});
|
|
221
|
+
});
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Documentation Verification Tests: README.md & Docs Exports
|
|
3
|
+
*
|
|
4
|
+
* Verifies that all exports documented in the README actually exist.
|
|
5
|
+
*/
|
|
6
|
+
import { describe, it, expect } from "vitest";
|
|
7
|
+
|
|
8
|
+
describe("readme-exports", () => {
|
|
9
|
+
describe("Prisma Adapter Exports", () => {
|
|
10
|
+
it("exports createChat function", async () => {
|
|
11
|
+
const { createChat } = await import("../../src/adapters/prisma/index.js");
|
|
12
|
+
expect(typeof createChat).toBe("function");
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
it("exports loadChat function", async () => {
|
|
16
|
+
const { loadChat } = await import("../../src/adapters/prisma/index.js");
|
|
17
|
+
expect(typeof loadChat).toBe("function");
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
it("exports Chat class", async () => {
|
|
21
|
+
const { Chat } = await import("../../src/adapters/prisma/index.js");
|
|
22
|
+
expect(Chat).toBeDefined();
|
|
23
|
+
expect(typeof Chat).toBe("function");
|
|
24
|
+
});
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
describe("Type Exports", () => {
|
|
28
|
+
it("exports ChatRecord type", async () => {
|
|
29
|
+
// Type verification - just confirm the module exports it
|
|
30
|
+
const module = await import("../../src/adapters/prisma/index.js");
|
|
31
|
+
expect(module).toBeDefined();
|
|
32
|
+
// Types are compile-time, but the module should exist
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it("exports MessageRecord type", async () => {
|
|
36
|
+
// Type verification - just confirm the module exports it
|
|
37
|
+
const module = await import("../../src/adapters/prisma/index.js");
|
|
38
|
+
expect(module).toBeDefined();
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it("exports ChatOptions type", async () => {
|
|
42
|
+
// Type verification - just confirm the module exports it
|
|
43
|
+
const module = await import("../../src/adapters/prisma/index.js");
|
|
44
|
+
expect(module).toBeDefined();
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it("exports TableNames type", async () => {
|
|
48
|
+
// Type verification - just confirm the module exports it
|
|
49
|
+
const module = await import("../../src/adapters/prisma/index.js");
|
|
50
|
+
expect(module).toBeDefined();
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
describe("Main Package Re-exports", () => {
|
|
55
|
+
it("main index re-exports prisma adapter", async () => {
|
|
56
|
+
const { createChat, loadChat, Chat } = await import("../../src/index.js");
|
|
57
|
+
expect(typeof createChat).toBe("function");
|
|
58
|
+
expect(typeof loadChat).toBe("function");
|
|
59
|
+
expect(Chat).toBeDefined();
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
});
|