@pikku/mongodb 0.12.17 → 0.12.18
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 +72 -0
- package/dist/src/index.d.ts +3 -3
- package/dist/src/index.js +1 -1
- package/dist/src/mongodb-agent-run-service.d.ts +5 -4
- package/dist/src/mongodb-agent-run-service.js +4 -4
- package/dist/src/mongodb-agent-storage-service.d.ts +45 -0
- package/dist/src/mongodb-agent-storage-service.js +440 -0
- package/dist/src/mongodb-deployment-service.d.ts +1 -1
- package/dist/src/mongodb-deployment-service.js +2 -2
- package/dist/src/mongodb-eventhub-store.d.ts +1 -1
- package/dist/src/mongodb-eventhub-store.js +1 -1
- package/dist/src/mongodb-workflow-run-service.d.ts +1 -1
- package/dist/src/mongodb-workflow-service.d.ts +3 -2
- package/dist/src/mongodb-workflow-service.js +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +2 -2
- package/src/index.ts +6 -3
- package/src/mongodb-agent-run-service.ts +22 -23
- package/src/{mongodb-ai-storage-service.ts → mongodb-agent-storage-service.ts} +61 -50
- package/src/mongodb-deployment-service.ts +3 -3
- package/src/mongodb-eventhub-store.ts +1 -1
- package/src/mongodb-services.test.ts +4 -4
- package/src/mongodb-workflow-run-service.ts +1 -1
- package/src/mongodb-workflow-service.ts +3 -12
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,77 @@
|
|
|
1
1
|
# @pikku/mongodb
|
|
2
2
|
|
|
3
|
+
## 0.12.18
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 7406bfe: Rename the agent runtime from `AI*` to `Agent*` (#596)
|
|
8
|
+
|
|
9
|
+
`AI` described the model provider, not the thing being named. Every symbol that
|
|
10
|
+
belongs to the agent runtime now says `Agent`; the symbols that genuinely wrap a
|
|
11
|
+
model provider — `AIEmbeddingService`, `AIProviderOptions`, `AIEmbedParams`,
|
|
12
|
+
`AITranscriptionParams`, `AIGenerateImageParams` and their siblings, and the
|
|
13
|
+
`@pikku/ai-vercel` / `@pikku/ai-deepinfra` / `@pikku/ai-voice` packages — keep
|
|
14
|
+
their names.
|
|
15
|
+
|
|
16
|
+
**Wiring**
|
|
17
|
+
- `pikkuAIAgent` → `pikkuAgent`, `pikkuAIScorer` → `pikkuAgentScorer`,
|
|
18
|
+
`pikkuAIJudge` → `pikkuAgentJudge`
|
|
19
|
+
- `CoreAIAgent` → `CoreAgent`, `AIAgentInput` → `AgentInput`, `AIAgentStep` →
|
|
20
|
+
`AgentStep`, `AIMessage` → `AgentMessage`, and the rest of the agent types
|
|
21
|
+
- `AIAgentRunnerService` → `AgentRunnerService`, `AIStorageService` →
|
|
22
|
+
`AgentStorageService`, `AIRunStateService` → `AgentRunStateService`
|
|
23
|
+
|
|
24
|
+
**Entry points**
|
|
25
|
+
|
|
26
|
+
`@pikku/core/agent` → `@pikku/core/agent`, `@pikku/core/agent-scorer` →
|
|
27
|
+
`@pikku/core/agent-scorer`.
|
|
28
|
+
|
|
29
|
+
**Queues**
|
|
30
|
+
|
|
31
|
+
The scorer queues are now `agent-score-fast` and `agent-score-slow`. Drain the
|
|
32
|
+
old `ai-score-fast` / `ai-score-slow` queues before deploying — jobs still
|
|
33
|
+
sitting on them when the new workers start will never be picked up.
|
|
34
|
+
|
|
35
|
+
**Scaffolds**
|
|
36
|
+
|
|
37
|
+
The agent scaffold pikku wrote for your project — `<scaffold>/agent/agent.gen.ts`
|
|
38
|
+
and its schemas file — imports `@pikku/core/ai-agent`, which no longer exists. A
|
|
39
|
+
scaffold is normally written once and then left alone, so `pikku all` would find
|
|
40
|
+
it present and leave the broken import in place. It now deletes an agent scaffold
|
|
41
|
+
importing either removed entry point and regenerates it in the same run. Anything
|
|
42
|
+
you added to that file goes with it, so move local edits out first.
|
|
43
|
+
|
|
44
|
+
**Database**
|
|
45
|
+
|
|
46
|
+
The agent tables are renamed: `ai_threads`, `ai_message`, `ai_tool_call`,
|
|
47
|
+
`ai_working_memory`, `ai_run` and `ai_run_score` become `agent_threads`,
|
|
48
|
+
`agent_message`, `agent_tool_call`, `agent_working_memory`, `agent_run` and
|
|
49
|
+
`agent_run_score`, along with their indexes and the `ai_working_memory_pk`
|
|
50
|
+
constraint. The same rename applies to the MongoDB collections.
|
|
51
|
+
|
|
52
|
+
`ensurePikkuSchema` creates tables it cannot find, so an existing database will
|
|
53
|
+
get empty `agent_*` tables and leave the old data stranded in `ai_*`. Rename
|
|
54
|
+
them before the first boot on the new version:
|
|
55
|
+
|
|
56
|
+
```sql
|
|
57
|
+
ALTER TABLE ai_threads RENAME TO agent_threads;
|
|
58
|
+
ALTER TABLE ai_message RENAME TO agent_message;
|
|
59
|
+
ALTER TABLE ai_tool_call RENAME TO agent_tool_call;
|
|
60
|
+
ALTER TABLE ai_working_memory RENAME TO agent_working_memory;
|
|
61
|
+
ALTER TABLE ai_run RENAME TO agent_run;
|
|
62
|
+
ALTER TABLE ai_run_score RENAME TO agent_run_score;
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
- 6794681: Publish the ecosystem surface as per-area sub-barrels under `@pikku/core/ecosystem/*`, and point generated code, the CLI, the inspector and the runtime adapters at them.
|
|
66
|
+
|
|
67
|
+
348 names that only generated code, the toolchain or a runtime adapter ever imports now have a second home on `@pikku/core/ecosystem/<area>` — one sub-barrel per area, matching how core already publishes its entrypoints, so no single barrel grows without bound and a consumer only pulls in the area it uses.
|
|
68
|
+
|
|
69
|
+
This step is additive: every name is still exported from the entrypoint it was published from before, so nothing downstream breaks. Removing them from the app-facing barrels is a later change, and needs a release carrying `./ecosystem/*` first.
|
|
70
|
+
|
|
71
|
+
- Updated dependencies [7406bfe]
|
|
72
|
+
- Updated dependencies [6794681]
|
|
73
|
+
- @pikku/core@0.12.84
|
|
74
|
+
|
|
3
75
|
## 0.12.17
|
|
4
76
|
|
|
5
77
|
### Patch Changes
|
package/dist/src/index.d.ts
CHANGED
|
@@ -4,9 +4,9 @@ export { MongoDBEventHubStore } from './mongodb-eventhub-store.js';
|
|
|
4
4
|
export { MongoDBWorkflowService } from './mongodb-workflow-service.js';
|
|
5
5
|
export { MongoDBWorkflowRunService } from './mongodb-workflow-run-service.js';
|
|
6
6
|
export { MongoDBDeploymentService } from './mongodb-deployment-service.js';
|
|
7
|
-
export {
|
|
7
|
+
export { MongoDBAgentStorageService } from './mongodb-agent-storage-service.js';
|
|
8
8
|
export { MongoDBAgentRunService } from './mongodb-agent-run-service.js';
|
|
9
9
|
export { MongoDBSecretService } from './mongodb-secret-service.js';
|
|
10
|
-
export type { WorkflowRunService } from '@pikku/core/workflow';
|
|
11
|
-
export type { AgentRunService, AgentRunRow } from '@pikku/core/
|
|
10
|
+
export type { WorkflowRunService } from '@pikku/core/ecosystem/workflow';
|
|
11
|
+
export type { AgentRunService, AgentRunRow, } from '@pikku/core/ecosystem/agent';
|
|
12
12
|
export { MongoDBSessionStore } from './mongodb-session-store.js';
|
package/dist/src/index.js
CHANGED
|
@@ -4,7 +4,7 @@ export { MongoDBEventHubStore } from './mongodb-eventhub-store.js';
|
|
|
4
4
|
export { MongoDBWorkflowService } from './mongodb-workflow-service.js';
|
|
5
5
|
export { MongoDBWorkflowRunService } from './mongodb-workflow-run-service.js';
|
|
6
6
|
export { MongoDBDeploymentService } from './mongodb-deployment-service.js';
|
|
7
|
-
export {
|
|
7
|
+
export { MongoDBAgentStorageService } from './mongodb-agent-storage-service.js';
|
|
8
8
|
export { MongoDBAgentRunService } from './mongodb-agent-run-service.js';
|
|
9
9
|
export { MongoDBSecretService } from './mongodb-secret-service.js';
|
|
10
10
|
export { MongoDBSessionStore } from './mongodb-session-store.js';
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { AgentThread, AgentMessage } from '@pikku/core/agent';
|
|
2
|
+
import type { AgentRunRow, AgentRunService } from '@pikku/core/ecosystem/agent';
|
|
2
3
|
import type { Db } from 'mongodb';
|
|
3
4
|
export declare class MongoDBAgentRunService implements AgentRunService {
|
|
4
5
|
private threads;
|
|
@@ -12,9 +13,9 @@ export declare class MongoDBAgentRunService implements AgentRunService {
|
|
|
12
13
|
owners?: string[];
|
|
13
14
|
limit?: number;
|
|
14
15
|
offset?: number;
|
|
15
|
-
}): Promise<
|
|
16
|
-
getThread(threadId: string): Promise<
|
|
17
|
-
getThreadMessages(threadId: string): Promise<
|
|
16
|
+
}): Promise<AgentThread[]>;
|
|
17
|
+
getThread(threadId: string): Promise<AgentThread | null>;
|
|
18
|
+
getThreadMessages(threadId: string): Promise<AgentMessage[]>;
|
|
18
19
|
getThreadRuns(threadId: string): Promise<AgentRunRow[]>;
|
|
19
20
|
deleteThread(threadId: string): Promise<boolean>;
|
|
20
21
|
getDistinctAgentNames(): Promise<string[]>;
|
|
@@ -7,10 +7,10 @@ export class MongoDBAgentRunService {
|
|
|
7
7
|
toolCalls;
|
|
8
8
|
runs;
|
|
9
9
|
constructor(db) {
|
|
10
|
-
this.threads = db.collection('
|
|
11
|
-
this.messages = db.collection('
|
|
12
|
-
this.toolCalls = db.collection('
|
|
13
|
-
this.runs = db.collection('
|
|
10
|
+
this.threads = db.collection('agent_threads');
|
|
11
|
+
this.messages = db.collection('agent_message');
|
|
12
|
+
this.toolCalls = db.collection('agent_tool_call');
|
|
13
|
+
this.runs = db.collection('agent_run');
|
|
14
14
|
}
|
|
15
15
|
async listThreads(options) {
|
|
16
16
|
const { agentName, resourceId, owners, limit = 50, offset = 0, } = options ?? {};
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type { AgentStorageService, AgentRunStateService, CreateRunInput, SaveScoreInput } from '@pikku/core/services';
|
|
2
|
+
import type { AgentThread, AgentMessage, AgentRunState } from '@pikku/core/agent';
|
|
3
|
+
import type { AgentRunScore } from '@pikku/core/agent-scorer';
|
|
4
|
+
import type { Db } from 'mongodb';
|
|
5
|
+
export declare class MongoDBAgentStorageService implements AgentStorageService, AgentRunStateService {
|
|
6
|
+
private db;
|
|
7
|
+
private initialized;
|
|
8
|
+
private threads;
|
|
9
|
+
private agentMessages;
|
|
10
|
+
private toolCalls;
|
|
11
|
+
private workingMemory;
|
|
12
|
+
private agentRuns;
|
|
13
|
+
private agentRunScores;
|
|
14
|
+
constructor(db: Db);
|
|
15
|
+
init(): Promise<void>;
|
|
16
|
+
createThread(resourceId: string, options?: {
|
|
17
|
+
threadId?: string;
|
|
18
|
+
title?: string;
|
|
19
|
+
metadata?: Record<string, unknown>;
|
|
20
|
+
}): Promise<AgentThread>;
|
|
21
|
+
getThread(threadId: string): Promise<AgentThread>;
|
|
22
|
+
getThreads(resourceId: string): Promise<AgentThread[]>;
|
|
23
|
+
deleteThread(threadId: string): Promise<void>;
|
|
24
|
+
getMessages(threadId: string, options?: {
|
|
25
|
+
lastN?: number;
|
|
26
|
+
cursor?: string;
|
|
27
|
+
}): Promise<AgentMessage[]>;
|
|
28
|
+
saveMessages(threadId: string, messages: AgentMessage[]): Promise<void>;
|
|
29
|
+
getWorkingMemory(id: string, scope: 'resource' | 'thread'): Promise<Record<string, unknown> | null>;
|
|
30
|
+
saveWorkingMemory(id: string, scope: 'resource' | 'thread', data: Record<string, unknown>): Promise<void>;
|
|
31
|
+
createRun(run: CreateRunInput): Promise<string>;
|
|
32
|
+
updateRun(runId: string, updates: Partial<AgentRunState>): Promise<void>;
|
|
33
|
+
getRun(runId: string): Promise<AgentRunState | null>;
|
|
34
|
+
getRunsByThread(threadId: string): Promise<AgentRunState[]>;
|
|
35
|
+
private setApprovals;
|
|
36
|
+
private mapRunRow;
|
|
37
|
+
findRunByToolCallId(toolCallId: string): Promise<{
|
|
38
|
+
run: AgentRunState;
|
|
39
|
+
approval: NonNullable<AgentRunState['pendingApprovals']>[number];
|
|
40
|
+
} | null>;
|
|
41
|
+
resolveApproval(toolCallId: string, status: 'approved' | 'denied'): Promise<boolean>;
|
|
42
|
+
saveScore(score: SaveScoreInput): Promise<void>;
|
|
43
|
+
getScores(runId: string): Promise<AgentRunScore[]>;
|
|
44
|
+
close(): Promise<void>;
|
|
45
|
+
}
|
|
@@ -0,0 +1,440 @@
|
|
|
1
|
+
export class MongoDBAgentStorageService {
|
|
2
|
+
db;
|
|
3
|
+
initialized = false;
|
|
4
|
+
threads;
|
|
5
|
+
agentMessages;
|
|
6
|
+
toolCalls;
|
|
7
|
+
workingMemory;
|
|
8
|
+
agentRuns;
|
|
9
|
+
agentRunScores;
|
|
10
|
+
constructor(db) {
|
|
11
|
+
this.db = db;
|
|
12
|
+
}
|
|
13
|
+
async init() {
|
|
14
|
+
if (this.initialized)
|
|
15
|
+
return;
|
|
16
|
+
this.threads = this.db.collection('agent_threads');
|
|
17
|
+
this.agentMessages = this.db.collection('agent_message');
|
|
18
|
+
this.toolCalls = this.db.collection('agent_tool_call');
|
|
19
|
+
this.workingMemory = this.db.collection('agent_working_memory');
|
|
20
|
+
this.agentRuns = this.db.collection('agent_run');
|
|
21
|
+
this.agentRunScores =
|
|
22
|
+
this.db.collection('agent_run_score');
|
|
23
|
+
await this.threads.createIndex({ resourceId: 1 });
|
|
24
|
+
await this.agentMessages.createIndex({ threadId: 1, createdAt: 1 });
|
|
25
|
+
await this.toolCalls.createIndex({ threadId: 1 });
|
|
26
|
+
await this.toolCalls.createIndex({ messageId: 1 });
|
|
27
|
+
await this.workingMemory.createIndex({ id: 1, scope: 1 }, { unique: true });
|
|
28
|
+
await this.agentRuns.createIndex({ threadId: 1, createdAt: 1 });
|
|
29
|
+
await this.agentRunScores.createIndex({ runId: 1, createdAt: 1 });
|
|
30
|
+
this.initialized = true;
|
|
31
|
+
}
|
|
32
|
+
async createThread(resourceId, options) {
|
|
33
|
+
const id = options?.threadId ?? crypto.randomUUID();
|
|
34
|
+
const now = new Date();
|
|
35
|
+
await this.threads.insertOne({
|
|
36
|
+
_id: id,
|
|
37
|
+
resourceId,
|
|
38
|
+
title: options?.title ?? null,
|
|
39
|
+
metadata: options?.metadata ?? null,
|
|
40
|
+
createdAt: now,
|
|
41
|
+
updatedAt: now,
|
|
42
|
+
});
|
|
43
|
+
return {
|
|
44
|
+
id,
|
|
45
|
+
resourceId,
|
|
46
|
+
title: options?.title,
|
|
47
|
+
metadata: options?.metadata,
|
|
48
|
+
createdAt: now,
|
|
49
|
+
updatedAt: now,
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
async getThread(threadId) {
|
|
53
|
+
const row = await this.threads.findOne({ _id: threadId });
|
|
54
|
+
if (!row) {
|
|
55
|
+
throw new Error(`Thread not found: ${threadId}`);
|
|
56
|
+
}
|
|
57
|
+
return {
|
|
58
|
+
id: row._id,
|
|
59
|
+
resourceId: row.resourceId,
|
|
60
|
+
title: row.title ?? undefined,
|
|
61
|
+
metadata: row.metadata ?? undefined,
|
|
62
|
+
createdAt: new Date(row.createdAt),
|
|
63
|
+
updatedAt: new Date(row.updatedAt),
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
async getThreads(resourceId) {
|
|
67
|
+
const result = await this.threads
|
|
68
|
+
.find({ resourceId })
|
|
69
|
+
.sort({ updatedAt: -1 })
|
|
70
|
+
.toArray();
|
|
71
|
+
return result.map((row) => ({
|
|
72
|
+
id: row._id,
|
|
73
|
+
resourceId: row.resourceId,
|
|
74
|
+
title: row.title ?? undefined,
|
|
75
|
+
metadata: row.metadata ?? undefined,
|
|
76
|
+
createdAt: new Date(row.createdAt),
|
|
77
|
+
updatedAt: new Date(row.updatedAt),
|
|
78
|
+
}));
|
|
79
|
+
}
|
|
80
|
+
async deleteThread(threadId) {
|
|
81
|
+
await this.toolCalls.deleteMany({ threadId });
|
|
82
|
+
await this.agentMessages.deleteMany({ threadId });
|
|
83
|
+
await this.agentRuns.deleteMany({ threadId });
|
|
84
|
+
await this.threads.deleteOne({ _id: threadId });
|
|
85
|
+
}
|
|
86
|
+
async getMessages(threadId, options) {
|
|
87
|
+
let filter = { threadId };
|
|
88
|
+
if (options?.cursor) {
|
|
89
|
+
const cursorRow = await this.agentMessages.findOne({
|
|
90
|
+
_id: options.cursor,
|
|
91
|
+
});
|
|
92
|
+
if (cursorRow) {
|
|
93
|
+
filter.createdAt = { $lt: cursorRow.createdAt };
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
let msgResult;
|
|
97
|
+
if (options?.cursor || options?.lastN) {
|
|
98
|
+
const innerResult = await this.agentMessages
|
|
99
|
+
.find(filter)
|
|
100
|
+
.sort({ createdAt: -1 })
|
|
101
|
+
.limit(options?.lastN ?? 50)
|
|
102
|
+
.toArray();
|
|
103
|
+
innerResult.reverse();
|
|
104
|
+
msgResult = innerResult;
|
|
105
|
+
}
|
|
106
|
+
else {
|
|
107
|
+
msgResult = await this.agentMessages
|
|
108
|
+
.find(filter)
|
|
109
|
+
.sort({ createdAt: 1 })
|
|
110
|
+
.toArray();
|
|
111
|
+
}
|
|
112
|
+
const tcResult = await this.toolCalls
|
|
113
|
+
.find({ threadId })
|
|
114
|
+
.sort({ createdAt: 1 })
|
|
115
|
+
.toArray();
|
|
116
|
+
const tcByMessage = new Map();
|
|
117
|
+
for (const tc of tcResult) {
|
|
118
|
+
const msgId = tc.messageId;
|
|
119
|
+
if (!tcByMessage.has(msgId))
|
|
120
|
+
tcByMessage.set(msgId, []);
|
|
121
|
+
tcByMessage.get(msgId).push(tc);
|
|
122
|
+
}
|
|
123
|
+
const messages = [];
|
|
124
|
+
for (const row of msgResult) {
|
|
125
|
+
let parsedContent = row.content ?? undefined;
|
|
126
|
+
if (typeof row.content === 'string') {
|
|
127
|
+
try {
|
|
128
|
+
const parsed = JSON.parse(row.content);
|
|
129
|
+
if (Array.isArray(parsed)) {
|
|
130
|
+
parsedContent = parsed;
|
|
131
|
+
}
|
|
132
|
+
else if (typeof parsed === 'string') {
|
|
133
|
+
parsedContent = parsed;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
catch {
|
|
137
|
+
// Not JSON, use raw string
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
const msg = {
|
|
141
|
+
id: row._id,
|
|
142
|
+
role: row.role,
|
|
143
|
+
content: parsedContent,
|
|
144
|
+
createdAt: new Date(row.createdAt),
|
|
145
|
+
};
|
|
146
|
+
const tcs = tcByMessage.get(msg.id);
|
|
147
|
+
if (tcs?.length) {
|
|
148
|
+
msg.toolCalls = tcs.map((tc) => ({
|
|
149
|
+
id: tc._id,
|
|
150
|
+
name: tc.toolName,
|
|
151
|
+
args: tc.args,
|
|
152
|
+
}));
|
|
153
|
+
const completed = tcs.filter((tc) => tc.result != null);
|
|
154
|
+
if (completed.length) {
|
|
155
|
+
messages.push(msg);
|
|
156
|
+
messages.push({
|
|
157
|
+
id: `tool-results-${msg.id}`,
|
|
158
|
+
role: 'tool',
|
|
159
|
+
toolResults: completed.map((tc) => ({
|
|
160
|
+
id: tc._id,
|
|
161
|
+
name: tc.toolName,
|
|
162
|
+
result: tc.result,
|
|
163
|
+
})),
|
|
164
|
+
createdAt: msg.createdAt,
|
|
165
|
+
});
|
|
166
|
+
continue;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
messages.push(msg);
|
|
170
|
+
}
|
|
171
|
+
return messages;
|
|
172
|
+
}
|
|
173
|
+
async saveMessages(threadId, messages) {
|
|
174
|
+
if (messages.length === 0)
|
|
175
|
+
return;
|
|
176
|
+
const toolMessages = messages.filter((m) => m.role === 'tool');
|
|
177
|
+
const nonToolMessages = messages.filter((m) => m.role !== 'tool');
|
|
178
|
+
if (nonToolMessages.length > 0) {
|
|
179
|
+
await this.agentMessages.insertMany(nonToolMessages.map((msg) => ({
|
|
180
|
+
_id: msg.id,
|
|
181
|
+
threadId,
|
|
182
|
+
role: msg.role,
|
|
183
|
+
content: msg.content != null ? JSON.stringify(msg.content) : null,
|
|
184
|
+
createdAt: msg.createdAt ?? new Date(),
|
|
185
|
+
})));
|
|
186
|
+
}
|
|
187
|
+
const toolCallDocs = nonToolMessages.flatMap((msg) => msg.toolCalls?.map((tc) => ({ ...tc, messageId: msg.id })) ?? []);
|
|
188
|
+
if (toolCallDocs.length > 0) {
|
|
189
|
+
await this.toolCalls.insertMany(toolCallDocs.map((tc) => ({
|
|
190
|
+
_id: tc.id,
|
|
191
|
+
threadId,
|
|
192
|
+
messageId: tc.messageId,
|
|
193
|
+
runId: null,
|
|
194
|
+
toolName: tc.name,
|
|
195
|
+
args: tc.args,
|
|
196
|
+
result: null,
|
|
197
|
+
approvalStatus: null,
|
|
198
|
+
approvalType: null,
|
|
199
|
+
agentRunId: null,
|
|
200
|
+
displayToolName: null,
|
|
201
|
+
displayArgs: null,
|
|
202
|
+
createdAt: new Date(),
|
|
203
|
+
})));
|
|
204
|
+
}
|
|
205
|
+
for (const toolMsg of toolMessages) {
|
|
206
|
+
if (!toolMsg.toolResults)
|
|
207
|
+
continue;
|
|
208
|
+
for (const tr of toolMsg.toolResults) {
|
|
209
|
+
await this.toolCalls.updateOne({ _id: tr.id }, { $set: { result: tr.result } });
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
await this.threads.updateOne({ _id: threadId }, { $set: { updatedAt: new Date() } });
|
|
213
|
+
}
|
|
214
|
+
async getWorkingMemory(id, scope) {
|
|
215
|
+
const row = await this.workingMemory.findOne({ id, scope });
|
|
216
|
+
if (!row)
|
|
217
|
+
return null;
|
|
218
|
+
return row.data;
|
|
219
|
+
}
|
|
220
|
+
async saveWorkingMemory(id, scope, data) {
|
|
221
|
+
await this.workingMemory.updateOne({ id, scope }, {
|
|
222
|
+
$set: {
|
|
223
|
+
data,
|
|
224
|
+
updatedAt: new Date(),
|
|
225
|
+
},
|
|
226
|
+
$setOnInsert: {
|
|
227
|
+
id,
|
|
228
|
+
scope,
|
|
229
|
+
},
|
|
230
|
+
}, { upsert: true });
|
|
231
|
+
}
|
|
232
|
+
async createRun(run) {
|
|
233
|
+
const runId = crypto.randomUUID();
|
|
234
|
+
await this.agentRuns.insertOne({
|
|
235
|
+
_id: runId,
|
|
236
|
+
agentName: run.agentName,
|
|
237
|
+
threadId: run.threadId,
|
|
238
|
+
resourceId: run.resourceId,
|
|
239
|
+
status: run.status,
|
|
240
|
+
errorMessage: run.errorMessage ?? null,
|
|
241
|
+
suspendReason: run.suspendReason ?? null,
|
|
242
|
+
missingRpcs: run.missingRpcs ?? null,
|
|
243
|
+
usageInputTokens: run.usage.inputTokens,
|
|
244
|
+
usageOutputTokens: run.usage.outputTokens,
|
|
245
|
+
usageModel: run.usage.model,
|
|
246
|
+
createdAt: run.createdAt,
|
|
247
|
+
updatedAt: run.updatedAt,
|
|
248
|
+
});
|
|
249
|
+
if (run.pendingApprovals?.length) {
|
|
250
|
+
await this.setApprovals(runId, run.pendingApprovals);
|
|
251
|
+
}
|
|
252
|
+
return runId;
|
|
253
|
+
}
|
|
254
|
+
async updateRun(runId, updates) {
|
|
255
|
+
const setValues = { updatedAt: new Date() };
|
|
256
|
+
if (updates.status !== undefined) {
|
|
257
|
+
setValues.status = updates.status;
|
|
258
|
+
}
|
|
259
|
+
if (updates.errorMessage !== undefined) {
|
|
260
|
+
setValues.errorMessage = updates.errorMessage;
|
|
261
|
+
}
|
|
262
|
+
if (updates.suspendReason !== undefined) {
|
|
263
|
+
setValues.suspendReason = updates.suspendReason;
|
|
264
|
+
}
|
|
265
|
+
if (updates.missingRpcs !== undefined) {
|
|
266
|
+
setValues.missingRpcs = updates.missingRpcs;
|
|
267
|
+
}
|
|
268
|
+
if (updates.usage !== undefined) {
|
|
269
|
+
setValues.usageInputTokens = updates.usage.inputTokens;
|
|
270
|
+
setValues.usageOutputTokens = updates.usage.outputTokens;
|
|
271
|
+
setValues.usageModel = updates.usage.model;
|
|
272
|
+
}
|
|
273
|
+
await this.agentRuns.updateOne({ _id: runId }, { $set: setValues });
|
|
274
|
+
if (updates.pendingApprovals !== undefined) {
|
|
275
|
+
await this.toolCalls.updateMany({ runId, approvalStatus: { $ne: null } }, {
|
|
276
|
+
$set: {
|
|
277
|
+
approvalStatus: null,
|
|
278
|
+
runId: null,
|
|
279
|
+
approvalType: null,
|
|
280
|
+
agentRunId: null,
|
|
281
|
+
displayToolName: null,
|
|
282
|
+
displayArgs: null,
|
|
283
|
+
},
|
|
284
|
+
});
|
|
285
|
+
if (updates.pendingApprovals.length) {
|
|
286
|
+
await this.setApprovals(runId, updates.pendingApprovals);
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
async getRun(runId) {
|
|
291
|
+
const row = await this.agentRuns.findOne({ _id: runId });
|
|
292
|
+
if (!row)
|
|
293
|
+
return null;
|
|
294
|
+
const approvals = await this.toolCalls
|
|
295
|
+
.find({ runId, approvalStatus: 'pending' })
|
|
296
|
+
.toArray();
|
|
297
|
+
return this.mapRunRow(row, approvals);
|
|
298
|
+
}
|
|
299
|
+
async getRunsByThread(threadId) {
|
|
300
|
+
const result = await this.agentRuns
|
|
301
|
+
.find({ threadId })
|
|
302
|
+
.sort({ createdAt: -1 })
|
|
303
|
+
.toArray();
|
|
304
|
+
const runs = [];
|
|
305
|
+
for (const row of result) {
|
|
306
|
+
const approvals = await this.toolCalls
|
|
307
|
+
.find({ runId: row._id, approvalStatus: 'pending' })
|
|
308
|
+
.toArray();
|
|
309
|
+
runs.push(this.mapRunRow(row, approvals));
|
|
310
|
+
}
|
|
311
|
+
return runs;
|
|
312
|
+
}
|
|
313
|
+
async setApprovals(runId, approvals) {
|
|
314
|
+
for (const a of approvals) {
|
|
315
|
+
if (a.type === 'agent-call') {
|
|
316
|
+
await this.toolCalls.updateOne({ _id: a.toolCallId }, {
|
|
317
|
+
$set: {
|
|
318
|
+
approvalStatus: 'pending',
|
|
319
|
+
runId,
|
|
320
|
+
approvalType: 'agent-call',
|
|
321
|
+
agentRunId: a.agentRunId,
|
|
322
|
+
displayToolName: a.displayToolName,
|
|
323
|
+
displayArgs: a.displayArgs,
|
|
324
|
+
},
|
|
325
|
+
});
|
|
326
|
+
}
|
|
327
|
+
else {
|
|
328
|
+
await this.toolCalls.updateOne({ _id: a.toolCallId }, {
|
|
329
|
+
$set: {
|
|
330
|
+
approvalStatus: 'pending',
|
|
331
|
+
runId,
|
|
332
|
+
approvalType: 'tool-call',
|
|
333
|
+
},
|
|
334
|
+
});
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
mapRunRow(row, approvalRows) {
|
|
339
|
+
const pendingApprovals = approvalRows?.length
|
|
340
|
+
? approvalRows.map((a) => {
|
|
341
|
+
if (a.approvalType === 'agent-call') {
|
|
342
|
+
return {
|
|
343
|
+
type: 'agent-call',
|
|
344
|
+
toolCallId: a._id,
|
|
345
|
+
agentName: a.toolName,
|
|
346
|
+
agentRunId: a.agentRunId,
|
|
347
|
+
displayToolName: a.displayToolName,
|
|
348
|
+
displayArgs: a.displayArgs,
|
|
349
|
+
};
|
|
350
|
+
}
|
|
351
|
+
return {
|
|
352
|
+
type: 'tool-call',
|
|
353
|
+
toolCallId: a._id,
|
|
354
|
+
toolName: a.toolName,
|
|
355
|
+
args: a.args,
|
|
356
|
+
};
|
|
357
|
+
})
|
|
358
|
+
: undefined;
|
|
359
|
+
return {
|
|
360
|
+
runId: row._id,
|
|
361
|
+
agentName: row.agentName,
|
|
362
|
+
threadId: row.threadId,
|
|
363
|
+
resourceId: row.resourceId,
|
|
364
|
+
status: row.status,
|
|
365
|
+
errorMessage: row.errorMessage ?? undefined,
|
|
366
|
+
suspendReason: row.suspendReason,
|
|
367
|
+
missingRpcs: row.missingRpcs ?? undefined,
|
|
368
|
+
pendingApprovals,
|
|
369
|
+
usage: {
|
|
370
|
+
inputTokens: Number(row.usageInputTokens),
|
|
371
|
+
outputTokens: Number(row.usageOutputTokens),
|
|
372
|
+
model: row.usageModel,
|
|
373
|
+
},
|
|
374
|
+
createdAt: new Date(row.createdAt),
|
|
375
|
+
updatedAt: new Date(row.updatedAt),
|
|
376
|
+
};
|
|
377
|
+
}
|
|
378
|
+
async findRunByToolCallId(toolCallId) {
|
|
379
|
+
const tc = await this.toolCalls.findOne({
|
|
380
|
+
_id: toolCallId,
|
|
381
|
+
approvalStatus: 'pending',
|
|
382
|
+
});
|
|
383
|
+
if (!tc || !tc.runId)
|
|
384
|
+
return null;
|
|
385
|
+
const run = await this.getRun(tc.runId);
|
|
386
|
+
if (!run)
|
|
387
|
+
return null;
|
|
388
|
+
let approval;
|
|
389
|
+
if (tc.approvalType === 'agent-call') {
|
|
390
|
+
approval = {
|
|
391
|
+
type: 'agent-call',
|
|
392
|
+
toolCallId: tc._id,
|
|
393
|
+
agentName: tc.toolName,
|
|
394
|
+
agentRunId: tc.agentRunId,
|
|
395
|
+
displayToolName: tc.displayToolName,
|
|
396
|
+
displayArgs: tc.displayArgs,
|
|
397
|
+
};
|
|
398
|
+
}
|
|
399
|
+
else {
|
|
400
|
+
approval = {
|
|
401
|
+
type: 'tool-call',
|
|
402
|
+
toolCallId: tc._id,
|
|
403
|
+
toolName: tc.toolName,
|
|
404
|
+
args: tc.args,
|
|
405
|
+
};
|
|
406
|
+
}
|
|
407
|
+
return { run, approval };
|
|
408
|
+
}
|
|
409
|
+
async resolveApproval(toolCallId, status) {
|
|
410
|
+
// Only the caller that moves the tool call off 'pending' has claimed it.
|
|
411
|
+
const result = await this.toolCalls.updateOne({ _id: toolCallId, approvalStatus: 'pending' }, { $set: { approvalStatus: status } });
|
|
412
|
+
return result.modifiedCount > 0;
|
|
413
|
+
}
|
|
414
|
+
async saveScore(score) {
|
|
415
|
+
await this.agentRunScores.insertOne({
|
|
416
|
+
_id: crypto.randomUUID(),
|
|
417
|
+
runId: score.runId,
|
|
418
|
+
scorerName: score.scorerName,
|
|
419
|
+
score: score.score,
|
|
420
|
+
reason: score.reason ?? null,
|
|
421
|
+
metadata: score.metadata ?? null,
|
|
422
|
+
createdAt: new Date(),
|
|
423
|
+
});
|
|
424
|
+
}
|
|
425
|
+
async getScores(runId) {
|
|
426
|
+
const rows = await this.agentRunScores
|
|
427
|
+
.find({ runId })
|
|
428
|
+
.sort({ createdAt: 1 })
|
|
429
|
+
.toArray();
|
|
430
|
+
return rows.map((row) => ({
|
|
431
|
+
runId: row.runId,
|
|
432
|
+
scorerName: row.scorerName,
|
|
433
|
+
score: row.score,
|
|
434
|
+
reason: row.reason ?? undefined,
|
|
435
|
+
metadata: row.metadata ?? undefined,
|
|
436
|
+
createdAt: row.createdAt,
|
|
437
|
+
}));
|
|
438
|
+
}
|
|
439
|
+
async close() { }
|
|
440
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { DeploymentService, DeploymentServiceConfig, DeploymentConfig } from '@pikku/core/services';
|
|
1
|
+
import type { DeploymentService, DeploymentServiceConfig, DeploymentConfig } from '@pikku/core/ecosystem/services';
|
|
2
2
|
import type { JWTService, SecretService } from '@pikku/core/services';
|
|
3
3
|
import type { Db } from 'mongodb';
|
|
4
4
|
export declare class MongoDBDeploymentService implements DeploymentService {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { buildRemoteHeaders } from '@pikku/core/remote';
|
|
2
|
-
import { getAllFunctionNames } from '@pikku/core/function';
|
|
1
|
+
import { buildRemoteHeaders } from '@pikku/core/ecosystem/remote';
|
|
2
|
+
import { getAllFunctionNames } from '@pikku/core/ecosystem/function';
|
|
3
3
|
export class MongoDBDeploymentService {
|
|
4
4
|
db;
|
|
5
5
|
jwt;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { WorkflowRun, StepState, WorkflowRunService } from '@pikku/core/workflow';
|
|
1
|
+
import type { WorkflowRun, StepState, WorkflowRunService } from '@pikku/core/ecosystem/workflow';
|
|
2
2
|
import type { Db } from 'mongodb';
|
|
3
3
|
export declare class MongoDBWorkflowRunService implements WorkflowRunService {
|
|
4
4
|
private runs;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import type { SerializedError } from '@pikku/core';
|
|
2
|
-
import { PikkuWorkflowService
|
|
1
|
+
import type { SerializedError } from '@pikku/core/ecosystem/types';
|
|
2
|
+
import { PikkuWorkflowService } from '@pikku/core/workflow';
|
|
3
|
+
import type { WorkflowPlannedStep, WorkflowQueueOptions, WorkflowRun, WorkflowRunWire, StepState, StepStatus, WorkflowStatus, WorkflowVersionStatus } from '@pikku/core/ecosystem/workflow';
|
|
3
4
|
import type { Db } from 'mongodb';
|
|
4
5
|
export declare class MongoDBWorkflowService extends PikkuWorkflowService {
|
|
5
6
|
private initialized;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { PikkuWorkflowService
|
|
1
|
+
import { PikkuWorkflowService } from '@pikku/core/workflow';
|
|
2
2
|
import { MongoDBWorkflowRunService } from './mongodb-workflow-run-service.js';
|
|
3
3
|
export class MongoDBWorkflowService extends PikkuWorkflowService {
|
|
4
4
|
initialized = false;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"root":["../src/index.ts","../src/mongodb-agent-run-service.ts","../src/mongodb-
|
|
1
|
+
{"root":["../src/index.ts","../src/mongodb-agent-run-service.ts","../src/mongodb-agent-storage-service.ts","../src/mongodb-channel-store.ts","../src/mongodb-deployment-service.ts","../src/mongodb-eventhub-store.ts","../src/mongodb-secret-service.ts","../src/mongodb-session-store.ts","../src/mongodb-workflow-run-service.ts","../src/mongodb-workflow-service.ts","../src/pikku-mongodb.ts"],"version":"6.0.3"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pikku/mongodb",
|
|
3
|
-
"version": "0.12.
|
|
3
|
+
"version": "0.12.18",
|
|
4
4
|
"description": "MongoDB services for Pikku — workflow state, agent runs, secrets and channel stores",
|
|
5
5
|
"author": "yasser.fadl@gmail.com",
|
|
6
6
|
"license": "MIT",
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
"prepublishOnly": "yarn build"
|
|
19
19
|
},
|
|
20
20
|
"peerDependencies": {
|
|
21
|
-
"@pikku/core": "^0.12.
|
|
21
|
+
"@pikku/core": "^0.12.84"
|
|
22
22
|
},
|
|
23
23
|
"dependencies": {
|
|
24
24
|
"mongodb": "^6.12.0"
|
package/src/index.ts
CHANGED
|
@@ -5,10 +5,13 @@ export { MongoDBEventHubStore } from './mongodb-eventhub-store.js'
|
|
|
5
5
|
export { MongoDBWorkflowService } from './mongodb-workflow-service.js'
|
|
6
6
|
export { MongoDBWorkflowRunService } from './mongodb-workflow-run-service.js'
|
|
7
7
|
export { MongoDBDeploymentService } from './mongodb-deployment-service.js'
|
|
8
|
-
export {
|
|
8
|
+
export { MongoDBAgentStorageService } from './mongodb-agent-storage-service.js'
|
|
9
9
|
export { MongoDBAgentRunService } from './mongodb-agent-run-service.js'
|
|
10
10
|
export { MongoDBSecretService } from './mongodb-secret-service.js'
|
|
11
11
|
|
|
12
|
-
export type { WorkflowRunService } from '@pikku/core/workflow'
|
|
13
|
-
export type {
|
|
12
|
+
export type { WorkflowRunService } from '@pikku/core/ecosystem/workflow'
|
|
13
|
+
export type {
|
|
14
|
+
AgentRunService,
|
|
15
|
+
AgentRunRow,
|
|
16
|
+
} from '@pikku/core/ecosystem/agent'
|
|
14
17
|
export { MongoDBSessionStore } from './mongodb-session-store.js'
|
|
@@ -1,9 +1,8 @@
|
|
|
1
|
+
import type { AgentThread, AgentMessage } from '@pikku/core/agent'
|
|
1
2
|
import type {
|
|
2
|
-
AIThread,
|
|
3
|
-
AIMessage,
|
|
4
3
|
AgentRunRow,
|
|
5
4
|
AgentRunService,
|
|
6
|
-
} from '@pikku/core/
|
|
5
|
+
} from '@pikku/core/ecosystem/agent'
|
|
7
6
|
import type { Db, Collection } from 'mongodb'
|
|
8
7
|
|
|
9
8
|
// Owner ids are untrusted input to the regex, so metacharacters must not be
|
|
@@ -11,7 +10,7 @@ import type { Db, Collection } from 'mongodb'
|
|
|
11
10
|
const escapeRegExp = (value: string) =>
|
|
12
11
|
value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
|
|
13
12
|
|
|
14
|
-
interface
|
|
13
|
+
interface AgentThreadDoc {
|
|
15
14
|
_id: string
|
|
16
15
|
resourceId: string
|
|
17
16
|
title: string | null
|
|
@@ -20,7 +19,7 @@ interface AIThreadDoc {
|
|
|
20
19
|
updatedAt: Date
|
|
21
20
|
}
|
|
22
21
|
|
|
23
|
-
interface
|
|
22
|
+
interface AgentMessageDoc {
|
|
24
23
|
_id: string
|
|
25
24
|
threadId: string
|
|
26
25
|
role: string
|
|
@@ -28,7 +27,7 @@ interface AIMessageDoc {
|
|
|
28
27
|
createdAt: Date
|
|
29
28
|
}
|
|
30
29
|
|
|
31
|
-
interface
|
|
30
|
+
interface AgentToolCallDoc {
|
|
32
31
|
_id: string
|
|
33
32
|
threadId: string
|
|
34
33
|
messageId: string
|
|
@@ -44,7 +43,7 @@ interface AIToolCallDoc {
|
|
|
44
43
|
createdAt: Date
|
|
45
44
|
}
|
|
46
45
|
|
|
47
|
-
interface
|
|
46
|
+
interface AgentRunDoc {
|
|
48
47
|
_id: string
|
|
49
48
|
agentName: string
|
|
50
49
|
threadId: string
|
|
@@ -61,16 +60,16 @@ interface AIRunDoc {
|
|
|
61
60
|
}
|
|
62
61
|
|
|
63
62
|
export class MongoDBAgentRunService implements AgentRunService {
|
|
64
|
-
private threads: Collection<
|
|
65
|
-
private messages: Collection<
|
|
66
|
-
private toolCalls: Collection<
|
|
67
|
-
private runs: Collection<
|
|
63
|
+
private threads: Collection<AgentThreadDoc>
|
|
64
|
+
private messages: Collection<AgentMessageDoc>
|
|
65
|
+
private toolCalls: Collection<AgentToolCallDoc>
|
|
66
|
+
private runs: Collection<AgentRunDoc>
|
|
68
67
|
|
|
69
68
|
constructor(db: Db) {
|
|
70
|
-
this.threads = db.collection<
|
|
71
|
-
this.messages = db.collection<
|
|
72
|
-
this.toolCalls = db.collection<
|
|
73
|
-
this.runs = db.collection<
|
|
69
|
+
this.threads = db.collection<AgentThreadDoc>('agent_threads')
|
|
70
|
+
this.messages = db.collection<AgentMessageDoc>('agent_message')
|
|
71
|
+
this.toolCalls = db.collection<AgentToolCallDoc>('agent_tool_call')
|
|
72
|
+
this.runs = db.collection<AgentRunDoc>('agent_run')
|
|
74
73
|
}
|
|
75
74
|
|
|
76
75
|
async listThreads(options?: {
|
|
@@ -79,7 +78,7 @@ export class MongoDBAgentRunService implements AgentRunService {
|
|
|
79
78
|
owners?: string[]
|
|
80
79
|
limit?: number
|
|
81
80
|
offset?: number
|
|
82
|
-
}): Promise<
|
|
81
|
+
}): Promise<AgentThread[]> {
|
|
83
82
|
const {
|
|
84
83
|
agentName,
|
|
85
84
|
resourceId,
|
|
@@ -122,13 +121,13 @@ export class MongoDBAgentRunService implements AgentRunService {
|
|
|
122
121
|
return result.map((row) => this.mapThreadRow(row))
|
|
123
122
|
}
|
|
124
123
|
|
|
125
|
-
async getThread(threadId: string): Promise<
|
|
124
|
+
async getThread(threadId: string): Promise<AgentThread | null> {
|
|
126
125
|
const row = await this.threads.findOne({ _id: threadId })
|
|
127
126
|
if (!row) return null
|
|
128
127
|
return this.mapThreadRow(row)
|
|
129
128
|
}
|
|
130
129
|
|
|
131
|
-
async getThreadMessages(threadId: string): Promise<
|
|
130
|
+
async getThreadMessages(threadId: string): Promise<AgentMessage[]> {
|
|
132
131
|
const [msgResult, tcResult] = await Promise.all([
|
|
133
132
|
this.messages.find({ threadId }).sort({ createdAt: 1 }).toArray(),
|
|
134
133
|
this.toolCalls.find({ threadId }).sort({ createdAt: 1 }).toArray(),
|
|
@@ -141,11 +140,11 @@ export class MongoDBAgentRunService implements AgentRunService {
|
|
|
141
140
|
tcByMessage.get(msgId)!.push(tc)
|
|
142
141
|
}
|
|
143
142
|
|
|
144
|
-
const messages:
|
|
143
|
+
const messages: AgentMessage[] = []
|
|
145
144
|
for (const row of msgResult) {
|
|
146
|
-
const msg:
|
|
145
|
+
const msg: AgentMessage = {
|
|
147
146
|
id: row._id,
|
|
148
|
-
role: row.role as
|
|
147
|
+
role: row.role as AgentMessage['role'],
|
|
149
148
|
content: row.content ?? undefined,
|
|
150
149
|
createdAt: new Date(row.createdAt),
|
|
151
150
|
}
|
|
@@ -203,7 +202,7 @@ export class MongoDBAgentRunService implements AgentRunService {
|
|
|
203
202
|
return result.sort()
|
|
204
203
|
}
|
|
205
204
|
|
|
206
|
-
private mapThreadRow(row:
|
|
205
|
+
private mapThreadRow(row: AgentThreadDoc): AgentThread {
|
|
207
206
|
return {
|
|
208
207
|
id: row._id,
|
|
209
208
|
resourceId: row.resourceId,
|
|
@@ -214,7 +213,7 @@ export class MongoDBAgentRunService implements AgentRunService {
|
|
|
214
213
|
}
|
|
215
214
|
}
|
|
216
215
|
|
|
217
|
-
private mapRunRow(row:
|
|
216
|
+
private mapRunRow(row: AgentRunDoc): AgentRunRow {
|
|
218
217
|
return {
|
|
219
218
|
runId: row._id,
|
|
220
219
|
agentName: row.agentName,
|
|
@@ -1,14 +1,18 @@
|
|
|
1
1
|
import type {
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
AgentStorageService,
|
|
3
|
+
AgentRunStateService,
|
|
4
4
|
CreateRunInput,
|
|
5
5
|
SaveScoreInput,
|
|
6
6
|
} from '@pikku/core/services'
|
|
7
|
-
import type {
|
|
8
|
-
|
|
7
|
+
import type {
|
|
8
|
+
AgentThread,
|
|
9
|
+
AgentMessage,
|
|
10
|
+
AgentRunState,
|
|
11
|
+
} from '@pikku/core/agent'
|
|
12
|
+
import type { AgentRunScore } from '@pikku/core/agent-scorer'
|
|
9
13
|
import type { Db, Collection } from 'mongodb'
|
|
10
14
|
|
|
11
|
-
interface
|
|
15
|
+
interface AgentThreadDoc {
|
|
12
16
|
_id: string
|
|
13
17
|
resourceId: string
|
|
14
18
|
title: string | null
|
|
@@ -17,7 +21,7 @@ interface AIThreadDoc {
|
|
|
17
21
|
updatedAt: Date
|
|
18
22
|
}
|
|
19
23
|
|
|
20
|
-
interface
|
|
24
|
+
interface AgentMessageDoc {
|
|
21
25
|
_id: string
|
|
22
26
|
threadId: string
|
|
23
27
|
role: string
|
|
@@ -25,7 +29,7 @@ interface AIMessageDoc {
|
|
|
25
29
|
createdAt: Date
|
|
26
30
|
}
|
|
27
31
|
|
|
28
|
-
interface
|
|
32
|
+
interface AgentToolCallDoc {
|
|
29
33
|
_id: string
|
|
30
34
|
threadId: string
|
|
31
35
|
messageId: string
|
|
@@ -41,14 +45,14 @@ interface AIToolCallDoc {
|
|
|
41
45
|
createdAt: Date
|
|
42
46
|
}
|
|
43
47
|
|
|
44
|
-
interface
|
|
48
|
+
interface AgentWorkingMemoryDoc {
|
|
45
49
|
id: string
|
|
46
50
|
scope: string
|
|
47
51
|
data: any
|
|
48
52
|
updatedAt: Date
|
|
49
53
|
}
|
|
50
54
|
|
|
51
|
-
interface
|
|
55
|
+
interface AgentRunScoreDoc {
|
|
52
56
|
_id: string
|
|
53
57
|
runId: string
|
|
54
58
|
scorerName: string
|
|
@@ -58,7 +62,7 @@ interface AIRunScoreDoc {
|
|
|
58
62
|
createdAt: Date
|
|
59
63
|
}
|
|
60
64
|
|
|
61
|
-
interface
|
|
65
|
+
interface AgentRunDoc {
|
|
62
66
|
_id: string
|
|
63
67
|
agentName: string
|
|
64
68
|
threadId: string
|
|
@@ -74,42 +78,44 @@ interface AIRunDoc {
|
|
|
74
78
|
updatedAt: Date
|
|
75
79
|
}
|
|
76
80
|
|
|
77
|
-
export class
|
|
78
|
-
implements
|
|
81
|
+
export class MongoDBAgentStorageService
|
|
82
|
+
implements AgentStorageService, AgentRunStateService
|
|
79
83
|
{
|
|
80
84
|
private initialized = false
|
|
81
|
-
private threads!: Collection<
|
|
82
|
-
private
|
|
83
|
-
private toolCalls!: Collection<
|
|
84
|
-
private workingMemory!: Collection<
|
|
85
|
-
private
|
|
86
|
-
private
|
|
85
|
+
private threads!: Collection<AgentThreadDoc>
|
|
86
|
+
private agentMessages!: Collection<AgentMessageDoc>
|
|
87
|
+
private toolCalls!: Collection<AgentToolCallDoc>
|
|
88
|
+
private workingMemory!: Collection<AgentWorkingMemoryDoc>
|
|
89
|
+
private agentRuns!: Collection<AgentRunDoc>
|
|
90
|
+
private agentRunScores!: Collection<AgentRunScoreDoc>
|
|
87
91
|
|
|
88
92
|
constructor(private db: Db) {}
|
|
89
93
|
|
|
90
94
|
public async init(): Promise<void> {
|
|
91
95
|
if (this.initialized) return
|
|
92
96
|
|
|
93
|
-
this.threads = this.db.collection<
|
|
94
|
-
this.
|
|
95
|
-
this.toolCalls = this.db.collection<
|
|
96
|
-
this.workingMemory =
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
this.
|
|
97
|
+
this.threads = this.db.collection<AgentThreadDoc>('agent_threads')
|
|
98
|
+
this.agentMessages = this.db.collection<AgentMessageDoc>('agent_message')
|
|
99
|
+
this.toolCalls = this.db.collection<AgentToolCallDoc>('agent_tool_call')
|
|
100
|
+
this.workingMemory = this.db.collection<AgentWorkingMemoryDoc>(
|
|
101
|
+
'agent_working_memory'
|
|
102
|
+
)
|
|
103
|
+
this.agentRuns = this.db.collection<AgentRunDoc>('agent_run')
|
|
104
|
+
this.agentRunScores =
|
|
105
|
+
this.db.collection<AgentRunScoreDoc>('agent_run_score')
|
|
100
106
|
|
|
101
107
|
await this.threads.createIndex({ resourceId: 1 })
|
|
102
108
|
|
|
103
|
-
await this.
|
|
109
|
+
await this.agentMessages.createIndex({ threadId: 1, createdAt: 1 })
|
|
104
110
|
|
|
105
111
|
await this.toolCalls.createIndex({ threadId: 1 })
|
|
106
112
|
await this.toolCalls.createIndex({ messageId: 1 })
|
|
107
113
|
|
|
108
114
|
await this.workingMemory.createIndex({ id: 1, scope: 1 }, { unique: true })
|
|
109
115
|
|
|
110
|
-
await this.
|
|
116
|
+
await this.agentRuns.createIndex({ threadId: 1, createdAt: 1 })
|
|
111
117
|
|
|
112
|
-
await this.
|
|
118
|
+
await this.agentRunScores.createIndex({ runId: 1, createdAt: 1 })
|
|
113
119
|
|
|
114
120
|
this.initialized = true
|
|
115
121
|
}
|
|
@@ -121,7 +127,7 @@ export class MongoDBAIStorageService
|
|
|
121
127
|
title?: string
|
|
122
128
|
metadata?: Record<string, unknown>
|
|
123
129
|
}
|
|
124
|
-
): Promise<
|
|
130
|
+
): Promise<AgentThread> {
|
|
125
131
|
const id = options?.threadId ?? crypto.randomUUID()
|
|
126
132
|
const now = new Date()
|
|
127
133
|
|
|
@@ -144,7 +150,7 @@ export class MongoDBAIStorageService
|
|
|
144
150
|
}
|
|
145
151
|
}
|
|
146
152
|
|
|
147
|
-
async getThread(threadId: string): Promise<
|
|
153
|
+
async getThread(threadId: string): Promise<AgentThread> {
|
|
148
154
|
const row = await this.threads.findOne({ _id: threadId })
|
|
149
155
|
|
|
150
156
|
if (!row) {
|
|
@@ -161,7 +167,7 @@ export class MongoDBAIStorageService
|
|
|
161
167
|
}
|
|
162
168
|
}
|
|
163
169
|
|
|
164
|
-
async getThreads(resourceId: string): Promise<
|
|
170
|
+
async getThreads(resourceId: string): Promise<AgentThread[]> {
|
|
165
171
|
const result = await this.threads
|
|
166
172
|
.find({ resourceId })
|
|
167
173
|
.sort({ updatedAt: -1 })
|
|
@@ -179,19 +185,21 @@ export class MongoDBAIStorageService
|
|
|
179
185
|
|
|
180
186
|
async deleteThread(threadId: string): Promise<void> {
|
|
181
187
|
await this.toolCalls.deleteMany({ threadId })
|
|
182
|
-
await this.
|
|
183
|
-
await this.
|
|
188
|
+
await this.agentMessages.deleteMany({ threadId })
|
|
189
|
+
await this.agentRuns.deleteMany({ threadId })
|
|
184
190
|
await this.threads.deleteOne({ _id: threadId })
|
|
185
191
|
}
|
|
186
192
|
|
|
187
193
|
async getMessages(
|
|
188
194
|
threadId: string,
|
|
189
195
|
options?: { lastN?: number; cursor?: string }
|
|
190
|
-
): Promise<
|
|
196
|
+
): Promise<AgentMessage[]> {
|
|
191
197
|
let filter: Record<string, any> = { threadId }
|
|
192
198
|
|
|
193
199
|
if (options?.cursor) {
|
|
194
|
-
const cursorRow = await this.
|
|
200
|
+
const cursorRow = await this.agentMessages.findOne({
|
|
201
|
+
_id: options.cursor,
|
|
202
|
+
})
|
|
195
203
|
if (cursorRow) {
|
|
196
204
|
filter.createdAt = { $lt: cursorRow.createdAt }
|
|
197
205
|
}
|
|
@@ -199,7 +207,7 @@ export class MongoDBAIStorageService
|
|
|
199
207
|
|
|
200
208
|
let msgResult
|
|
201
209
|
if (options?.cursor || options?.lastN) {
|
|
202
|
-
const innerResult = await this.
|
|
210
|
+
const innerResult = await this.agentMessages
|
|
203
211
|
.find(filter)
|
|
204
212
|
.sort({ createdAt: -1 })
|
|
205
213
|
.limit(options?.lastN ?? 50)
|
|
@@ -207,7 +215,7 @@ export class MongoDBAIStorageService
|
|
|
207
215
|
innerResult.reverse()
|
|
208
216
|
msgResult = innerResult
|
|
209
217
|
} else {
|
|
210
|
-
msgResult = await this.
|
|
218
|
+
msgResult = await this.agentMessages
|
|
211
219
|
.find(filter)
|
|
212
220
|
.sort({ createdAt: 1 })
|
|
213
221
|
.toArray()
|
|
@@ -225,9 +233,9 @@ export class MongoDBAIStorageService
|
|
|
225
233
|
tcByMessage.get(msgId)!.push(tc)
|
|
226
234
|
}
|
|
227
235
|
|
|
228
|
-
const messages:
|
|
236
|
+
const messages: AgentMessage[] = []
|
|
229
237
|
for (const row of msgResult) {
|
|
230
|
-
let parsedContent:
|
|
238
|
+
let parsedContent: AgentMessage['content'] = row.content ?? undefined
|
|
231
239
|
if (typeof row.content === 'string') {
|
|
232
240
|
try {
|
|
233
241
|
const parsed = JSON.parse(row.content)
|
|
@@ -241,9 +249,9 @@ export class MongoDBAIStorageService
|
|
|
241
249
|
}
|
|
242
250
|
}
|
|
243
251
|
|
|
244
|
-
const msg:
|
|
252
|
+
const msg: AgentMessage = {
|
|
245
253
|
id: row._id,
|
|
246
|
-
role: row.role as
|
|
254
|
+
role: row.role as AgentMessage['role'],
|
|
247
255
|
content: parsedContent,
|
|
248
256
|
createdAt: new Date(row.createdAt),
|
|
249
257
|
}
|
|
@@ -279,14 +287,17 @@ export class MongoDBAIStorageService
|
|
|
279
287
|
return messages
|
|
280
288
|
}
|
|
281
289
|
|
|
282
|
-
async saveMessages(
|
|
290
|
+
async saveMessages(
|
|
291
|
+
threadId: string,
|
|
292
|
+
messages: AgentMessage[]
|
|
293
|
+
): Promise<void> {
|
|
283
294
|
if (messages.length === 0) return
|
|
284
295
|
|
|
285
296
|
const toolMessages = messages.filter((m) => m.role === 'tool')
|
|
286
297
|
const nonToolMessages = messages.filter((m) => m.role !== 'tool')
|
|
287
298
|
|
|
288
299
|
if (nonToolMessages.length > 0) {
|
|
289
|
-
await this.
|
|
300
|
+
await this.agentMessages.insertMany(
|
|
290
301
|
nonToolMessages.map((msg) => ({
|
|
291
302
|
_id: msg.id,
|
|
292
303
|
threadId,
|
|
@@ -369,7 +380,7 @@ export class MongoDBAIStorageService
|
|
|
369
380
|
async createRun(run: CreateRunInput): Promise<string> {
|
|
370
381
|
const runId = crypto.randomUUID()
|
|
371
382
|
|
|
372
|
-
await this.
|
|
383
|
+
await this.agentRuns.insertOne({
|
|
373
384
|
_id: runId,
|
|
374
385
|
agentName: run.agentName,
|
|
375
386
|
threadId: run.threadId,
|
|
@@ -416,7 +427,7 @@ export class MongoDBAIStorageService
|
|
|
416
427
|
setValues.usageModel = updates.usage.model
|
|
417
428
|
}
|
|
418
429
|
|
|
419
|
-
await this.
|
|
430
|
+
await this.agentRuns.updateOne({ _id: runId }, { $set: setValues })
|
|
420
431
|
|
|
421
432
|
if (updates.pendingApprovals !== undefined) {
|
|
422
433
|
await this.toolCalls.updateMany(
|
|
@@ -440,7 +451,7 @@ export class MongoDBAIStorageService
|
|
|
440
451
|
}
|
|
441
452
|
|
|
442
453
|
async getRun(runId: string): Promise<AgentRunState | null> {
|
|
443
|
-
const row = await this.
|
|
454
|
+
const row = await this.agentRuns.findOne({ _id: runId })
|
|
444
455
|
if (!row) return null
|
|
445
456
|
|
|
446
457
|
const approvals = await this.toolCalls
|
|
@@ -451,7 +462,7 @@ export class MongoDBAIStorageService
|
|
|
451
462
|
}
|
|
452
463
|
|
|
453
464
|
async getRunsByThread(threadId: string): Promise<AgentRunState[]> {
|
|
454
|
-
const result = await this.
|
|
465
|
+
const result = await this.agentRuns
|
|
455
466
|
.find({ threadId })
|
|
456
467
|
.sort({ createdAt: -1 })
|
|
457
468
|
.toArray()
|
|
@@ -591,7 +602,7 @@ export class MongoDBAIStorageService
|
|
|
591
602
|
}
|
|
592
603
|
|
|
593
604
|
async saveScore(score: SaveScoreInput): Promise<void> {
|
|
594
|
-
await this.
|
|
605
|
+
await this.agentRunScores.insertOne({
|
|
595
606
|
_id: crypto.randomUUID(),
|
|
596
607
|
runId: score.runId,
|
|
597
608
|
scorerName: score.scorerName,
|
|
@@ -602,8 +613,8 @@ export class MongoDBAIStorageService
|
|
|
602
613
|
})
|
|
603
614
|
}
|
|
604
615
|
|
|
605
|
-
async getScores(runId: string): Promise<
|
|
606
|
-
const rows = await this.
|
|
616
|
+
async getScores(runId: string): Promise<AgentRunScore[]> {
|
|
617
|
+
const rows = await this.agentRunScores
|
|
607
618
|
.find({ runId })
|
|
608
619
|
.sort({ createdAt: 1 })
|
|
609
620
|
.toArray()
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { buildRemoteHeaders } from '@pikku/core/remote'
|
|
1
|
+
import { buildRemoteHeaders } from '@pikku/core/ecosystem/remote'
|
|
2
2
|
import type {
|
|
3
3
|
DeploymentService,
|
|
4
4
|
DeploymentServiceConfig,
|
|
5
5
|
DeploymentConfig,
|
|
6
|
-
} from '@pikku/core/services'
|
|
6
|
+
} from '@pikku/core/ecosystem/services'
|
|
7
7
|
import type { JWTService, SecretService } from '@pikku/core/services'
|
|
8
|
-
import { getAllFunctionNames } from '@pikku/core/function'
|
|
8
|
+
import { getAllFunctionNames } from '@pikku/core/ecosystem/function'
|
|
9
9
|
import type { Db, Collection } from 'mongodb'
|
|
10
10
|
|
|
11
11
|
interface DeploymentDoc {
|
|
@@ -2,14 +2,14 @@ import { describe, test, before, after } from 'node:test'
|
|
|
2
2
|
import assert from 'node:assert/strict'
|
|
3
3
|
import { MongoClient, type Db } from 'mongodb'
|
|
4
4
|
import { MongoMemoryServer } from 'mongodb-memory-server'
|
|
5
|
-
import { defineServiceTests } from '@pikku/core/testing'
|
|
5
|
+
import { defineServiceTests } from '@pikku/core/ecosystem/testing'
|
|
6
6
|
|
|
7
7
|
import { MongoDBChannelStore } from './mongodb-channel-store.js'
|
|
8
8
|
import { MongoDBEventHubStore } from './mongodb-eventhub-store.js'
|
|
9
9
|
import { MongoDBWorkflowService } from './mongodb-workflow-service.js'
|
|
10
10
|
import { MongoDBWorkflowRunService } from './mongodb-workflow-run-service.js'
|
|
11
11
|
import { MongoDBDeploymentService } from './mongodb-deployment-service.js'
|
|
12
|
-
import {
|
|
12
|
+
import { MongoDBAgentStorageService } from './mongodb-agent-storage-service.js'
|
|
13
13
|
import { MongoDBAgentRunService } from './mongodb-agent-run-service.js'
|
|
14
14
|
import { MongoDBSecretService } from './mongodb-secret-service.js'
|
|
15
15
|
import { MongoDBSessionStore } from './mongodb-session-store.js'
|
|
@@ -42,8 +42,8 @@ function registerTests(name: string, getDb: () => Db) {
|
|
|
42
42
|
await s.init()
|
|
43
43
|
return s
|
|
44
44
|
},
|
|
45
|
-
|
|
46
|
-
const s = new
|
|
45
|
+
agentStorageService: async () => {
|
|
46
|
+
const s = new MongoDBAgentStorageService(getDb())
|
|
47
47
|
await s.init()
|
|
48
48
|
return s
|
|
49
49
|
},
|
|
@@ -1,15 +1,6 @@
|
|
|
1
|
-
import type { SerializedError } from '@pikku/core'
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
type WorkflowPlannedStep,
|
|
5
|
-
type WorkflowQueueOptions,
|
|
6
|
-
type WorkflowRun,
|
|
7
|
-
type WorkflowRunWire,
|
|
8
|
-
type StepState,
|
|
9
|
-
type StepStatus,
|
|
10
|
-
type WorkflowStatus,
|
|
11
|
-
type WorkflowVersionStatus,
|
|
12
|
-
} from '@pikku/core/workflow'
|
|
1
|
+
import type { SerializedError } from '@pikku/core/ecosystem/types'
|
|
2
|
+
import { PikkuWorkflowService } from '@pikku/core/workflow'
|
|
3
|
+
import type { WorkflowPlannedStep, WorkflowQueueOptions, WorkflowRun, WorkflowRunWire, StepState, StepStatus, WorkflowStatus, WorkflowVersionStatus } from '@pikku/core/ecosystem/workflow'
|
|
13
4
|
import type { Db, Collection } from 'mongodb'
|
|
14
5
|
import { MongoDBWorkflowRunService } from './mongodb-workflow-run-service.js'
|
|
15
6
|
|