@node-llm/orm 0.5.0 → 0.6.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 +16 -0
- package/dist/adapters/prisma/AgentSession.d.ts +42 -11
- package/dist/adapters/prisma/AgentSession.d.ts.map +1 -1
- package/dist/adapters/prisma/AgentSession.js +137 -13
- package/dist/adapters/prisma/Chat.d.ts +2 -2
- package/dist/adapters/prisma/Chat.d.ts.map +1 -1
- package/dist/adapters/prisma/Chat.js +6 -6
- package/package.json +2 -2
- package/src/adapters/prisma/AgentSession.ts +174 -31
- package/src/adapters/prisma/Chat.ts +6 -6
- package/test/AgentSession.test.ts +131 -3
- package/test/CodeWins.test.ts +1 -0
- package/tsconfig.tsbuildinfo +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,22 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
|
|
5
|
+
## [1.12.0] - 2026-02-22 (@node-llm/core)
|
|
6
|
+
|
|
7
|
+
### Features
|
|
8
|
+
|
|
9
|
+
- **Lazy Agent Evaluation**: Support for defining `instructions` and `tools` as functions that resolve at runtime based on provided `inputs`.
|
|
10
|
+
- **Runtime Agent Inputs**: Pass dynamic context (e.g., user preferences, scope) via `agent.ask(msg, { inputs })` for per-turn configuration overrides.
|
|
11
|
+
- **Agent Telemetry Hooks**: Integrated delegation of life-cycle events (`onToolCallStart`, `onToolCallEnd`, `afterResponse`) from Agents to underlying Chat instances, enabling declarative observability.
|
|
12
|
+
|
|
13
|
+
## [0.6.0] - 2026-02-22 (@node-llm/orm)
|
|
14
|
+
|
|
15
|
+
### Features
|
|
16
|
+
|
|
17
|
+
- **Automated Agent Persistence**: `AgentSession` now automatically registers internal hooks to persist tool calls and provider request metrics (tokens, latency) to the database.
|
|
18
|
+
- **Dynamic Metadata Updates**: Added `session.updateMetadata()` for mid-conversation context updates with immediate agent re-resolution.
|
|
19
|
+
- **Proof-of-Concept**: Full integration in HR Chatbot example demonstrating persistent multi-turn agent conversations with a complete audit trail.
|
|
20
|
+
|
|
5
21
|
## [1.11.0] - 2026-02-07 (@node-llm/core)
|
|
6
22
|
|
|
7
23
|
### Features
|
|
@@ -38,11 +38,11 @@ export interface TableNames {
|
|
|
38
38
|
toolCall?: string;
|
|
39
39
|
request?: string;
|
|
40
40
|
}
|
|
41
|
-
type AgentClass<T extends Agent = Agent
|
|
41
|
+
type AgentClass<T extends Agent<any, any> = Agent<any, any>> = (new (overrides?: Partial<AgentConfig<any> & ChatOptions>) => T) & {
|
|
42
42
|
name: string;
|
|
43
43
|
model?: string;
|
|
44
|
-
instructions?:
|
|
45
|
-
tools?: unknown
|
|
44
|
+
instructions?: unknown;
|
|
45
|
+
tools?: unknown;
|
|
46
46
|
};
|
|
47
47
|
/**
|
|
48
48
|
* AgentSession - Wraps an Agent instance with persistence capabilities.
|
|
@@ -50,6 +50,7 @@ type AgentClass<T extends Agent = Agent> = (new (overrides?: Partial<AgentConfig
|
|
|
50
50
|
* Follows "Code Wins" sovereignty:
|
|
51
51
|
* - Model, Tools, Instructions come from the Agent class (code)
|
|
52
52
|
* - Message history comes from the database
|
|
53
|
+
* - Metadata from DB is injected as 'inputs' for dynamic resolution
|
|
53
54
|
*
|
|
54
55
|
* @example
|
|
55
56
|
* ```typescript
|
|
@@ -65,7 +66,7 @@ type AgentClass<T extends Agent = Agent> = (new (overrides?: Partial<AgentConfig
|
|
|
65
66
|
* const result = await session.ask("Hello");
|
|
66
67
|
* ```
|
|
67
68
|
*/
|
|
68
|
-
export declare class AgentSession<T extends Agent = Agent
|
|
69
|
+
export declare class AgentSession<I extends Record<string, any> = Record<string, any>, T extends Agent<I, any> = Agent<I, any>> {
|
|
69
70
|
private prisma;
|
|
70
71
|
private llm;
|
|
71
72
|
private AgentClass;
|
|
@@ -83,7 +84,7 @@ export declare class AgentSession<T extends Agent = Agent> {
|
|
|
83
84
|
/** Underlying chat ID */
|
|
84
85
|
get chatId(): string;
|
|
85
86
|
/** Session metadata */
|
|
86
|
-
get metadata():
|
|
87
|
+
get metadata(): I | null | undefined;
|
|
87
88
|
/** Agent class name */
|
|
88
89
|
get agentClass(): string;
|
|
89
90
|
/** Model ID used by the agent */
|
|
@@ -96,14 +97,36 @@ export declare class AgentSession<T extends Agent = Agent> {
|
|
|
96
97
|
* Helper to get a typed Prisma model by its dynamic name.
|
|
97
98
|
*/
|
|
98
99
|
private getModel;
|
|
100
|
+
/**
|
|
101
|
+
* Register persistence hooks on the agent.
|
|
102
|
+
*/
|
|
103
|
+
private registerHooks;
|
|
99
104
|
/**
|
|
100
105
|
* Send a message and persist the conversation.
|
|
101
106
|
*/
|
|
102
|
-
ask(
|
|
107
|
+
ask(message: string, options?: AskOptions & {
|
|
108
|
+
inputs?: I;
|
|
109
|
+
}): Promise<MessageRecord>;
|
|
103
110
|
/**
|
|
104
111
|
* Stream a response and persist the conversation.
|
|
105
112
|
*/
|
|
106
|
-
askStream(
|
|
113
|
+
askStream(message: string, options?: AskOptions & {
|
|
114
|
+
inputs?: I;
|
|
115
|
+
}): AsyncGenerator<ChatChunk, MessageRecord, undefined>;
|
|
116
|
+
/**
|
|
117
|
+
* Returns a usage summary for this chat session.
|
|
118
|
+
*/
|
|
119
|
+
stats(): Promise<Usage>;
|
|
120
|
+
/**
|
|
121
|
+
* Add a tool to the session (turn-level).
|
|
122
|
+
*/
|
|
123
|
+
withTool(tool: any): this;
|
|
124
|
+
/**
|
|
125
|
+
* Add instructions to the session (turn-level).
|
|
126
|
+
*/
|
|
127
|
+
withInstructions(instructions: string, options?: {
|
|
128
|
+
replace?: boolean;
|
|
129
|
+
}): this;
|
|
107
130
|
/**
|
|
108
131
|
* Returns the current full message history for this session.
|
|
109
132
|
*/
|
|
@@ -112,19 +135,27 @@ export declare class AgentSession<T extends Agent = Agent> {
|
|
|
112
135
|
* Delete the entire session and its history.
|
|
113
136
|
*/
|
|
114
137
|
delete(): Promise<void>;
|
|
138
|
+
/**
|
|
139
|
+
* Update session metadata and re-resolve agent configuration.
|
|
140
|
+
*/
|
|
141
|
+
updateMetadata(metadata: Partial<I>): Promise<void>;
|
|
115
142
|
}
|
|
116
143
|
/**
|
|
117
144
|
* Options for creating a new agent session.
|
|
118
145
|
*/
|
|
119
|
-
export interface CreateAgentSessionOptions {
|
|
120
|
-
metadata?:
|
|
146
|
+
export interface CreateAgentSessionOptions<I = any> {
|
|
147
|
+
metadata?: I;
|
|
121
148
|
tableNames?: TableNames;
|
|
122
149
|
debug?: boolean;
|
|
150
|
+
model?: string;
|
|
151
|
+
provider?: string;
|
|
152
|
+
instructions?: string;
|
|
153
|
+
maxToolCalls?: number;
|
|
123
154
|
}
|
|
124
155
|
/**
|
|
125
156
|
* Creates a new agent session and its persistent chat record.
|
|
126
157
|
*/
|
|
127
|
-
export declare function createAgentSession<T extends Agent
|
|
158
|
+
export declare function createAgentSession<I extends Record<string, any>, T extends Agent<I, any>>(prisma: any, llm: NodeLLMCore, AgentClass: AgentClass<T>, options?: CreateAgentSessionOptions<I>): Promise<AgentSession<I, T>>;
|
|
128
159
|
/**
|
|
129
160
|
* Options for loading an existing agent session.
|
|
130
161
|
*/
|
|
@@ -135,6 +166,6 @@ export interface LoadAgentSessionOptions {
|
|
|
135
166
|
/**
|
|
136
167
|
* Loads an existing agent session and re-instantiates the agent with history.
|
|
137
168
|
*/
|
|
138
|
-
export declare function loadAgentSession<T extends Agent
|
|
169
|
+
export declare function loadAgentSession<I extends Record<string, any>, T extends Agent<I, any>>(prisma: any, llm: NodeLLMCore, AgentClass: AgentClass<T>, sessionId: string, options?: LoadAgentSessionOptions): Promise<AgentSession<I, T> | null>;
|
|
139
170
|
export {};
|
|
140
171
|
//# sourceMappingURL=AgentSession.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AgentSession.d.ts","sourceRoot":"","sources":["../../../src/adapters/prisma/AgentSession.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,WAAW,EACX,UAAU,EACV,WAAW,EACX,KAAK,EACL,WAAW,EACX,OAAO,EACP,SAAS,EACT,KAAK,EACN,MAAM,gBAAgB,CAAC;AASxB;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IAC1C,SAAS,EAAE,IAAI,CAAC;IAChB,SAAS,EAAE,IAAI,CAAC;CACjB;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,iBAAiB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,SAAS,EAAE,IAAI,CAAC;CACjB;AAED;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAgBD,KAAK,UAAU,CAAC,CAAC,SAAS,KAAK,GAAG,KAAK,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"AgentSession.d.ts","sourceRoot":"","sources":["../../../src/adapters/prisma/AgentSession.ts"],"names":[],"mappings":"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"}
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* Follows "Code Wins" sovereignty:
|
|
5
5
|
* - Model, Tools, Instructions come from the Agent class (code)
|
|
6
6
|
* - Message history comes from the database
|
|
7
|
+
* - Metadata from DB is injected as 'inputs' for dynamic resolution
|
|
7
8
|
*
|
|
8
9
|
* @example
|
|
9
10
|
* ```typescript
|
|
@@ -29,7 +30,8 @@ export class AgentSession {
|
|
|
29
30
|
tableNames;
|
|
30
31
|
debug;
|
|
31
32
|
constructor(prisma, llm, AgentClass, record, tableNames, agent = new AgentClass({
|
|
32
|
-
llm
|
|
33
|
+
llm,
|
|
34
|
+
inputs: record.metadata
|
|
33
35
|
}), debug = false) {
|
|
34
36
|
this.prisma = prisma;
|
|
35
37
|
this.llm = llm;
|
|
@@ -44,6 +46,7 @@ export class AgentSession {
|
|
|
44
46
|
toolCall: tableNames?.toolCall || "llmToolCall",
|
|
45
47
|
request: tableNames?.request || "llmRequest"
|
|
46
48
|
};
|
|
49
|
+
this.registerHooks();
|
|
47
50
|
}
|
|
48
51
|
log(...args) {
|
|
49
52
|
if (this.debug) {
|
|
@@ -88,14 +91,69 @@ export class AgentSession {
|
|
|
88
91
|
getModel(name) {
|
|
89
92
|
return getTable(this.prisma, name);
|
|
90
93
|
}
|
|
94
|
+
/**
|
|
95
|
+
* Register persistence hooks on the agent.
|
|
96
|
+
*/
|
|
97
|
+
registerHooks() {
|
|
98
|
+
this.agent.onToolCallStart(async (toolCall) => {
|
|
99
|
+
if (!this.currentMessageId)
|
|
100
|
+
return;
|
|
101
|
+
const model = this.getModel(this.tableNames.toolCall);
|
|
102
|
+
await model.create({
|
|
103
|
+
data: {
|
|
104
|
+
messageId: this.currentMessageId,
|
|
105
|
+
toolCallId: toolCall.id,
|
|
106
|
+
name: toolCall.function.name,
|
|
107
|
+
arguments: toolCall.function.arguments
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
});
|
|
111
|
+
this.agent.onToolCallEnd(async (toolCall, result) => {
|
|
112
|
+
if (!this.currentMessageId)
|
|
113
|
+
return;
|
|
114
|
+
const model = this.getModel(this.tableNames.toolCall);
|
|
115
|
+
try {
|
|
116
|
+
await model.update({
|
|
117
|
+
where: {
|
|
118
|
+
messageId_toolCallId: {
|
|
119
|
+
messageId: this.currentMessageId,
|
|
120
|
+
toolCallId: toolCall.id
|
|
121
|
+
}
|
|
122
|
+
},
|
|
123
|
+
data: {
|
|
124
|
+
result: typeof result === "string" ? result : JSON.stringify(result)
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
catch (e) {
|
|
129
|
+
this.log(`Failed to update tool call result: ${e}`);
|
|
130
|
+
}
|
|
131
|
+
});
|
|
132
|
+
this.agent.afterResponse(async (response) => {
|
|
133
|
+
const model = this.getModel(this.tableNames.request);
|
|
134
|
+
await model.create({
|
|
135
|
+
data: {
|
|
136
|
+
chatId: this.chatId,
|
|
137
|
+
messageId: this.currentMessageId,
|
|
138
|
+
provider: response.provider || "unknown",
|
|
139
|
+
model: response.model || "unknown",
|
|
140
|
+
statusCode: 200,
|
|
141
|
+
duration: 0,
|
|
142
|
+
inputTokens: response.usage?.input_tokens || 0,
|
|
143
|
+
outputTokens: response.usage?.output_tokens || 0,
|
|
144
|
+
cost: response.usage?.cost || 0
|
|
145
|
+
}
|
|
146
|
+
});
|
|
147
|
+
});
|
|
148
|
+
}
|
|
91
149
|
/**
|
|
92
150
|
* Send a message and persist the conversation.
|
|
93
151
|
*/
|
|
94
|
-
async ask(
|
|
152
|
+
async ask(message, options = {}) {
|
|
95
153
|
const model = this.getModel(this.tableNames.message);
|
|
96
154
|
// Persist user message
|
|
97
155
|
await model.create({
|
|
98
|
-
data: { chatId: this.chatId, role: "user", content:
|
|
156
|
+
data: { chatId: this.chatId, role: "user", content: message }
|
|
99
157
|
});
|
|
100
158
|
// Create placeholder for assistant message
|
|
101
159
|
const assistantMessage = await model.create({
|
|
@@ -103,8 +161,10 @@ export class AgentSession {
|
|
|
103
161
|
});
|
|
104
162
|
this.currentMessageId = assistantMessage.id;
|
|
105
163
|
try {
|
|
164
|
+
// Merge turn-level inputs with session metadata
|
|
165
|
+
const inputs = { ...this.record.metadata, ...options.inputs };
|
|
106
166
|
// Get response from agent (uses code-defined config + injected history)
|
|
107
|
-
const response = await this.agent.ask(
|
|
167
|
+
const response = await this.agent.ask(message, { ...options, inputs });
|
|
108
168
|
// Update assistant message with response
|
|
109
169
|
return await model.update({
|
|
110
170
|
where: { id: assistantMessage.id },
|
|
@@ -130,11 +190,11 @@ export class AgentSession {
|
|
|
130
190
|
/**
|
|
131
191
|
* Stream a response and persist the conversation.
|
|
132
192
|
*/
|
|
133
|
-
async *askStream(
|
|
193
|
+
async *askStream(message, options = {}) {
|
|
134
194
|
const model = this.getModel(this.tableNames.message);
|
|
135
195
|
// Persist user message
|
|
136
196
|
await model.create({
|
|
137
|
-
data: { chatId: this.chatId, role: "user", content:
|
|
197
|
+
data: { chatId: this.chatId, role: "user", content: message }
|
|
138
198
|
});
|
|
139
199
|
// Create placeholder for assistant message
|
|
140
200
|
const assistantMessage = await model.create({
|
|
@@ -142,7 +202,9 @@ export class AgentSession {
|
|
|
142
202
|
});
|
|
143
203
|
this.currentMessageId = assistantMessage.id;
|
|
144
204
|
try {
|
|
145
|
-
|
|
205
|
+
// Merge turn-level inputs with session metadata
|
|
206
|
+
const inputs = { ...this.record.metadata, ...options.inputs };
|
|
207
|
+
const stream = this.agent.stream(message, { ...options, inputs });
|
|
146
208
|
let fullContent = "";
|
|
147
209
|
let lastChunk = null;
|
|
148
210
|
for await (const chunk of stream) {
|
|
@@ -170,6 +232,40 @@ export class AgentSession {
|
|
|
170
232
|
throw error;
|
|
171
233
|
}
|
|
172
234
|
}
|
|
235
|
+
/**
|
|
236
|
+
* Returns a usage summary for this chat session.
|
|
237
|
+
*/
|
|
238
|
+
async stats() {
|
|
239
|
+
const requestModel = getTable(this.prisma, this.tableNames.request);
|
|
240
|
+
const aggregate = await requestModel.aggregate({
|
|
241
|
+
where: { chatId: this.chatId },
|
|
242
|
+
_sum: {
|
|
243
|
+
inputTokens: true,
|
|
244
|
+
outputTokens: true,
|
|
245
|
+
cost: true
|
|
246
|
+
}
|
|
247
|
+
});
|
|
248
|
+
return {
|
|
249
|
+
input_tokens: Number(aggregate._sum.inputTokens || 0),
|
|
250
|
+
output_tokens: Number(aggregate._sum.outputTokens || 0),
|
|
251
|
+
total_tokens: Number((aggregate._sum.inputTokens || 0) + (aggregate._sum.outputTokens || 0)),
|
|
252
|
+
cost: Number(aggregate._sum.cost || 0)
|
|
253
|
+
};
|
|
254
|
+
}
|
|
255
|
+
/**
|
|
256
|
+
* Add a tool to the session (turn-level).
|
|
257
|
+
*/
|
|
258
|
+
withTool(tool) {
|
|
259
|
+
this.agent.use(tool);
|
|
260
|
+
return this;
|
|
261
|
+
}
|
|
262
|
+
/**
|
|
263
|
+
* Add instructions to the session (turn-level).
|
|
264
|
+
*/
|
|
265
|
+
withInstructions(instructions, options) {
|
|
266
|
+
this.agent.withInstructions(instructions, options);
|
|
267
|
+
return this;
|
|
268
|
+
}
|
|
173
269
|
/**
|
|
174
270
|
* Returns the current full message history for this session.
|
|
175
271
|
*/
|
|
@@ -188,6 +284,22 @@ export class AgentSession {
|
|
|
188
284
|
await chatTable.delete({ where: { id: this.chatId } });
|
|
189
285
|
// AgentSession record is deleted via Cascade from LlmChat
|
|
190
286
|
}
|
|
287
|
+
/**
|
|
288
|
+
* Update session metadata and re-resolve agent configuration.
|
|
289
|
+
*/
|
|
290
|
+
async updateMetadata(metadata) {
|
|
291
|
+
const sessionTable = this.getModel(this.tableNames.agentSession);
|
|
292
|
+
const newMetadata = { ...this.record.metadata, ...metadata };
|
|
293
|
+
await sessionTable.update({
|
|
294
|
+
where: { id: this.id },
|
|
295
|
+
data: { metadata: newMetadata }
|
|
296
|
+
});
|
|
297
|
+
this.record.metadata = newMetadata;
|
|
298
|
+
// Apply changes to the underlying agent immediately
|
|
299
|
+
// resolveLazyConfig is private, so we need a cast or make it protected.
|
|
300
|
+
// Given we are in the same package, we can cast.
|
|
301
|
+
this.agent.resolveLazyConfig(newMetadata);
|
|
302
|
+
}
|
|
191
303
|
}
|
|
192
304
|
/**
|
|
193
305
|
* Creates a new agent session and its persistent chat record.
|
|
@@ -205,9 +317,10 @@ export async function createAgentSession(prisma, llm, AgentClass, options = {})
|
|
|
205
317
|
const chatTable = getTable(prisma, tableNames.chat);
|
|
206
318
|
const chatRecord = (await chatTable.create({
|
|
207
319
|
data: {
|
|
208
|
-
model: AgentClass.model || null,
|
|
209
|
-
provider: null,
|
|
210
|
-
instructions:
|
|
320
|
+
model: options.model || AgentClass.model || null,
|
|
321
|
+
provider: options.provider || null,
|
|
322
|
+
instructions: options.instructions ||
|
|
323
|
+
(typeof AgentClass.instructions === "string" ? AgentClass.instructions : null),
|
|
211
324
|
metadata: null // Runtime metadata goes in Chat, session context in AgentSession
|
|
212
325
|
}
|
|
213
326
|
}));
|
|
@@ -220,7 +333,16 @@ export async function createAgentSession(prisma, llm, AgentClass, options = {})
|
|
|
220
333
|
metadata: options.metadata || null
|
|
221
334
|
}
|
|
222
335
|
}));
|
|
223
|
-
|
|
336
|
+
// 3. Instantiate Agent with overrides
|
|
337
|
+
const agent = new AgentClass({
|
|
338
|
+
llm,
|
|
339
|
+
inputs: sessionRecord.metadata,
|
|
340
|
+
model: options.model,
|
|
341
|
+
provider: options.provider,
|
|
342
|
+
instructions: options.instructions,
|
|
343
|
+
maxToolCalls: options.maxToolCalls
|
|
344
|
+
});
|
|
345
|
+
return new AgentSession(prisma, llm, AgentClass, sessionRecord, options.tableNames, agent, options.debug);
|
|
224
346
|
}
|
|
225
347
|
/**
|
|
226
348
|
* Loads an existing agent session and re-instantiates the agent with history.
|
|
@@ -257,11 +379,13 @@ export async function loadAgentSession(prisma, llm, AgentClass, sessionId, optio
|
|
|
257
379
|
role: m.role,
|
|
258
380
|
content: m.content || ""
|
|
259
381
|
}));
|
|
260
|
-
// 4. Instantiate agent with injected history
|
|
382
|
+
// 4. Instantiate agent with injected history, LLM, AND metadata (as inputs)
|
|
261
383
|
// "Code Wins" - model, tools, instructions come from AgentClass
|
|
384
|
+
// Metadata from DB handles the lazy resolution of behavior
|
|
262
385
|
const agent = new AgentClass({
|
|
263
386
|
llm,
|
|
264
|
-
messages: history
|
|
387
|
+
messages: history,
|
|
388
|
+
inputs: sessionRecord.metadata
|
|
265
389
|
});
|
|
266
390
|
return new AgentSession(prisma, llm, AgentClass, sessionRecord, options.tableNames, agent, options.debug);
|
|
267
391
|
}
|
|
@@ -40,12 +40,12 @@ export declare class Chat extends BaseChat {
|
|
|
40
40
|
/**
|
|
41
41
|
* Send a message and persist the conversation.
|
|
42
42
|
*/
|
|
43
|
-
ask(
|
|
43
|
+
ask(message: string, options?: AskOptions): Promise<MessageRecord>;
|
|
44
44
|
/**
|
|
45
45
|
* Stream a response and persist the conversation.
|
|
46
46
|
* Yields ChatChunk objects for full visibility of thinking, content, and tools.
|
|
47
47
|
*/
|
|
48
|
-
askStream(
|
|
48
|
+
askStream(message: string, options?: AskOptions): AsyncGenerator<ChatChunk, MessageRecord, undefined>;
|
|
49
49
|
/**
|
|
50
50
|
* Get all messages for this chat.
|
|
51
51
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Chat.d.ts","sourceRoot":"","sources":["../../../src/adapters/prisma/Chat.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AACnD,OAAO,KAAK,EAAE,WAAW,EAAE,SAAS,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AAChF,OAAO,EAAE,QAAQ,EAAE,KAAK,UAAU,EAAE,KAAK,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAEhF,OAAO,EAAE,KAAK,UAAU,EAAE,KAAK,WAAW,EAAE,CAAC;AAE7C,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,SAAS,EAAE,IAAI,CAAC;CACjB;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;GAEG;AACH,qBAAa,IAAK,SAAQ,QAAQ;IAK9B,OAAO,CAAC,MAAM;IACd,OAAO,CAAC,GAAG;IALb,OAAO,CAAC,MAAM,CAAuB;IACrC,OAAO,CAAC,iBAAiB,CAAoD;gBAGnE,MAAM,EAAE,YAAY,EACpB,GAAG,EAAE,WAAW,EACxB,MAAM,EAAE,UAAU,EAClB,OAAO,GAAE,WAAgB,EACzB,UAAU,GAAE,UAAe;IAgB7B;;OAEG;YACW,eAAe;IAqH7B;;OAEG;IACG,GAAG,CAAC,
|
|
1
|
+
{"version":3,"file":"Chat.d.ts","sourceRoot":"","sources":["../../../src/adapters/prisma/Chat.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AACnD,OAAO,KAAK,EAAE,WAAW,EAAE,SAAS,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AAChF,OAAO,EAAE,QAAQ,EAAE,KAAK,UAAU,EAAE,KAAK,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAEhF,OAAO,EAAE,KAAK,UAAU,EAAE,KAAK,WAAW,EAAE,CAAC;AAE7C,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,SAAS,EAAE,IAAI,CAAC;CACjB;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;GAEG;AACH,qBAAa,IAAK,SAAQ,QAAQ;IAK9B,OAAO,CAAC,MAAM;IACd,OAAO,CAAC,GAAG;IALb,OAAO,CAAC,MAAM,CAAuB;IACrC,OAAO,CAAC,iBAAiB,CAAoD;gBAGnE,MAAM,EAAE,YAAY,EACpB,GAAG,EAAE,WAAW,EACxB,MAAM,EAAE,UAAU,EAClB,OAAO,GAAE,WAAgB,EACzB,UAAU,GAAE,UAAe;IAgB7B;;OAEG;YACW,eAAe;IAqH7B;;OAEG;IACG,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,GAAE,UAAe,GAAG,OAAO,CAAC,aAAa,CAAC;IA8C5E;;;OAGG;IACI,SAAS,CACd,OAAO,EAAE,MAAM,EACf,OAAO,GAAE,UAAe,GACvB,cAAc,CAAC,SAAS,EAAE,aAAa,EAAE,SAAS,CAAC;IAmEtD;;OAEG;IACG,QAAQ,IAAI,OAAO,CAAC,aAAa,EAAE,CAAC;IAQ1C;;OAEG;IACG,KAAK,IAAI,OAAO,CAAC,KAAK,CAAC;CAkB9B;AAuBD;;GAEG;AACH,wBAAsB,UAAU,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EACtD,MAAM,EAAE,GAAG,EACX,GAAG,EAAE,WAAW,EAChB,OAAO,GAAE,WAAW,GAAG;IAAE,UAAU,CAAC,EAAE,UAAU,CAAA;CAAE,GAAG,CAAa,GACjE,OAAO,CAAC,IAAI,CAAC,CA2Cf;AAED;;GAEG;AACH,wBAAsB,QAAQ,CAC5B,MAAM,EAAE,GAAG,EACX,GAAG,EAAE,WAAW,EAChB,MAAM,EAAE,MAAM,EACd,OAAO,GAAE,WAAW,GAAG;IAAE,UAAU,CAAC,EAAE,UAAU,CAAC;IAAC,KAAK,CAAC,EAAE,OAAO,CAAA;CAAO,GACvE,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC,CAiBtB"}
|
|
@@ -131,10 +131,10 @@ export class Chat extends BaseChat {
|
|
|
131
131
|
/**
|
|
132
132
|
* Send a message and persist the conversation.
|
|
133
133
|
*/
|
|
134
|
-
async ask(
|
|
134
|
+
async ask(message, options = {}) {
|
|
135
135
|
const messageModel = this.tables.message;
|
|
136
136
|
const userMessage = await this.prisma[messageModel].create({
|
|
137
|
-
data: { chatId: this.id, role: "user", content:
|
|
137
|
+
data: { chatId: this.id, role: "user", content: message }
|
|
138
138
|
});
|
|
139
139
|
const assistantMessage = await this.prisma[messageModel].create({
|
|
140
140
|
data: { chatId: this.id, role: "assistant", content: null }
|
|
@@ -149,7 +149,7 @@ export class Chat extends BaseChat {
|
|
|
149
149
|
content: m.content || ""
|
|
150
150
|
}));
|
|
151
151
|
const coreChat = await this.prepareCoreChat(history, assistantMessage.id);
|
|
152
|
-
const response = await coreChat.ask(
|
|
152
|
+
const response = await coreChat.ask(message, options);
|
|
153
153
|
return await this.prisma[messageModel].update({
|
|
154
154
|
where: { id: assistantMessage.id },
|
|
155
155
|
data: {
|
|
@@ -176,10 +176,10 @@ export class Chat extends BaseChat {
|
|
|
176
176
|
* Stream a response and persist the conversation.
|
|
177
177
|
* Yields ChatChunk objects for full visibility of thinking, content, and tools.
|
|
178
178
|
*/
|
|
179
|
-
async *askStream(
|
|
179
|
+
async *askStream(message, options = {}) {
|
|
180
180
|
const messageModel = this.tables.message;
|
|
181
181
|
const userMessage = await this.prisma[messageModel].create({
|
|
182
|
-
data: { chatId: this.id, role: "user", content:
|
|
182
|
+
data: { chatId: this.id, role: "user", content: message }
|
|
183
183
|
});
|
|
184
184
|
const assistantMessage = await this.prisma[messageModel].create({
|
|
185
185
|
data: { chatId: this.id, role: "assistant", content: null }
|
|
@@ -194,7 +194,7 @@ export class Chat extends BaseChat {
|
|
|
194
194
|
content: m.content || ""
|
|
195
195
|
}));
|
|
196
196
|
const coreChat = await this.prepareCoreChat(history, assistantMessage.id);
|
|
197
|
-
const stream = coreChat.stream(
|
|
197
|
+
const stream = coreChat.stream(message, options);
|
|
198
198
|
let fullContent = "";
|
|
199
199
|
let metadata = {};
|
|
200
200
|
for await (const chunk of stream) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@node-llm/orm",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "Database persistence layer for NodeLLM - Chat, Message, and ToolCall tracking with streaming support",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -56,7 +56,7 @@
|
|
|
56
56
|
"author": "NodeLLM Contributors",
|
|
57
57
|
"license": "MIT",
|
|
58
58
|
"peerDependencies": {
|
|
59
|
-
"@node-llm/core": "^1.
|
|
59
|
+
"@node-llm/core": "^1.12.0",
|
|
60
60
|
"@prisma/client": "^5.0.0"
|
|
61
61
|
},
|
|
62
62
|
"devDependencies": {
|