@pikku/mongodb 0.12.21 → 0.12.23

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/run-tests.sh CHANGED
@@ -34,20 +34,35 @@ files=($(find src -type f -name "*.test.ts"))
34
34
  # Check if any files matched the pattern
35
35
  if [ ${#files[@]} -eq 0 ]; then
36
36
  echo "No test files found matching pattern: $pattern"
37
+ if [ "${STRICT_TEST_DISCOVERY}" = "1" ]; then
38
+ exit 1
39
+ fi
37
40
  exit 0
38
41
  fi
39
42
 
40
- # Construct the node command
41
- node_cmd=(node --import tsx --test)
43
+ # Construct the bun command
44
+ #
45
+ # --parallel gives every test file its own worker process, which is what node's
46
+ # `--test` did. Several suites keep module-level caches (a TypeScript program, a
47
+ # temp fixture directory) that a shared process would leak between files.
48
+ #
49
+ # --timeout because bun caps a test at 5s by default where node had no cap, and
50
+ # the suites that build real TypeScript programs run well past that.
51
+ bun_cmd=(bun test --parallel --timeout 120000)
42
52
 
43
53
  # Append options based on flags
44
54
  if [ "$watch_mode" = true ]; then
45
- node_cmd+=(--watch)
55
+ # --watch reruns in one process; parallel workers have nothing to watch.
56
+ bun_cmd=(bun test --watch --timeout 120000)
46
57
  fi
47
58
 
48
59
  if [ "$coverage_mode" = true ]; then
49
- node_cmd+=(--test-coverage-include="src/**/*.{ts,js}" --test-coverage-exclude="**/dist/**" --experimental-test-coverage --test-reporter=lcov --test-reporter-destination=lcov.info)
60
+ # --coverage-dir=. keeps lcov.info at the package root: CI merges every
61
+ # package's report by prefixing its SF paths with the file's own directory,
62
+ # so a nested coverage/ directory would re-root them one level too deep.
63
+ bun_cmd+=(--coverage --coverage-reporter=lcov --coverage-reporter=text --coverage-dir=.)
64
+ export PIKKU_TEST_COVERAGE=1
50
65
  fi
51
66
 
52
- # Execute the node command with the expanded list of files
53
- "${node_cmd[@]}" "${files[@]}"
67
+ # Execute the bun command with the expanded list of files
68
+ "${bun_cmd[@]}" "${files[@]}"
@@ -1 +0,0 @@
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/src/index.ts DELETED
@@ -1,14 +0,0 @@
1
- export { PikkuMongoDB } from './pikku-mongodb.js'
2
-
3
- export { MongoDBChannelStore } from './mongodb-channel-store.js'
4
- export { MongoDBEventHubStore } from './mongodb-eventhub-store.js'
5
- export { MongoDBWorkflowService } from './mongodb-workflow-service.js'
6
- export { MongoDBWorkflowRunService } from './mongodb-workflow-run-service.js'
7
- export { MongoDBDeploymentService } from './mongodb-deployment-service.js'
8
- export { MongoDBAgentStorageService } from './mongodb-agent-storage-service.js'
9
- export { MongoDBAgentRunService } from './mongodb-agent-run-service.js'
10
- export { MongoDBSecretService } from './mongodb-secret-service.js'
11
-
12
- export type { WorkflowRunService } from '@pikku/core/workflow'
13
- export type { AgentRunService, AgentRunRow } from '@pikku/core/agent'
14
- export { MongoDBSessionStore } from './mongodb-session-store.js'
@@ -1,234 +0,0 @@
1
- import type {
2
- AgentThread,
3
- AgentMessage,
4
- AgentRunRow,
5
- AgentRunService,
6
- } from '@pikku/core/agent'
7
- import type { Db, Collection } from 'mongodb'
8
-
9
- // Owner ids are untrusted input to the regex, so metacharacters must not be
10
- // able to widen the prefix match.
11
- const escapeRegExp = (value: string) =>
12
- value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
13
-
14
- interface AgentThreadDoc {
15
- _id: string
16
- resourceId: string
17
- title: string | null
18
- metadata: any | null
19
- createdAt: Date
20
- updatedAt: Date
21
- }
22
-
23
- interface AgentMessageDoc {
24
- _id: string
25
- threadId: string
26
- role: string
27
- content: string | null
28
- createdAt: Date
29
- }
30
-
31
- interface AgentToolCallDoc {
32
- _id: string
33
- threadId: string
34
- messageId: string
35
- runId: string | null
36
- toolName: string
37
- args: any
38
- result: string | null
39
- approvalStatus: string | null
40
- approvalType: string | null
41
- agentRunId: string | null
42
- displayToolName: string | null
43
- displayArgs: any | null
44
- createdAt: Date
45
- }
46
-
47
- interface AgentRunDoc {
48
- _id: string
49
- agentName: string
50
- threadId: string
51
- resourceId: string
52
- status: string
53
- errorMessage: string | null
54
- suspendReason: string | null
55
- missingRpcs: any | null
56
- usageInputTokens: number
57
- usageOutputTokens: number
58
- usageModel: string
59
- createdAt: Date
60
- updatedAt: Date
61
- }
62
-
63
- export class MongoDBAgentRunService implements AgentRunService {
64
- private threads: Collection<AgentThreadDoc>
65
- private messages: Collection<AgentMessageDoc>
66
- private toolCalls: Collection<AgentToolCallDoc>
67
- private runs: Collection<AgentRunDoc>
68
-
69
- constructor(db: Db) {
70
- this.threads = db.collection<AgentThreadDoc>('agent_threads')
71
- this.messages = db.collection<AgentMessageDoc>('agent_message')
72
- this.toolCalls = db.collection<AgentToolCallDoc>('agent_tool_call')
73
- this.runs = db.collection<AgentRunDoc>('agent_run')
74
- }
75
-
76
- async listThreads(options?: {
77
- agentName?: string
78
- resourceId?: string
79
- owners?: string[]
80
- limit?: number
81
- offset?: number
82
- }): Promise<AgentThread[]> {
83
- const {
84
- agentName,
85
- resourceId,
86
- owners,
87
- limit = 50,
88
- offset = 0,
89
- } = options ?? {}
90
-
91
- // An owners constraint is an authorization boundary, so an empty list must
92
- // match nothing rather than degrade to "no filter".
93
- if (owners && owners.length === 0) return []
94
-
95
- let filter: Record<string, any> = {}
96
-
97
- if (resourceId) {
98
- filter.resourceId = resourceId
99
- }
100
-
101
- if (owners) {
102
- filter.$or = owners.flatMap((owner) => [
103
- { resourceId: owner },
104
- { resourceId: { $regex: `^${escapeRegExp(owner)}:` } },
105
- ])
106
- }
107
-
108
- if (agentName) {
109
- const threadIds = await this.runs.distinct('threadId', {
110
- agentName,
111
- })
112
- filter._id = { $in: threadIds }
113
- }
114
-
115
- const result = await this.threads
116
- .find(filter)
117
- .sort({ updatedAt: -1 })
118
- .skip(offset)
119
- .limit(limit)
120
- .toArray()
121
-
122
- return result.map((row) => this.mapThreadRow(row))
123
- }
124
-
125
- async getThread(threadId: string): Promise<AgentThread | null> {
126
- const row = await this.threads.findOne({ _id: threadId })
127
- if (!row) return null
128
- return this.mapThreadRow(row)
129
- }
130
-
131
- async getThreadMessages(threadId: string): Promise<AgentMessage[]> {
132
- const [msgResult, tcResult] = await Promise.all([
133
- this.messages.find({ threadId }).sort({ createdAt: 1 }).toArray(),
134
- this.toolCalls.find({ threadId }).sort({ createdAt: 1 }).toArray(),
135
- ])
136
-
137
- const tcByMessage = new Map<string, (typeof tcResult)[number][]>()
138
- for (const tc of tcResult) {
139
- const msgId = tc.messageId
140
- if (!tcByMessage.has(msgId)) tcByMessage.set(msgId, [])
141
- tcByMessage.get(msgId)!.push(tc)
142
- }
143
-
144
- const messages: AgentMessage[] = []
145
- for (const row of msgResult) {
146
- const msg: AgentMessage = {
147
- id: row._id,
148
- role: row.role as AgentMessage['role'],
149
- content: row.content ?? undefined,
150
- createdAt: new Date(row.createdAt),
151
- }
152
-
153
- const tcs = tcByMessage.get(msg.id)
154
- if (tcs?.length) {
155
- msg.toolCalls = tcs.map((tc) => ({
156
- id: tc._id,
157
- name: tc.toolName,
158
- args: tc.args as Record<string, unknown>,
159
- }))
160
-
161
- const completed = tcs.filter((tc) => tc.result != null)
162
- if (completed.length) {
163
- messages.push(msg)
164
- messages.push({
165
- id: `tool-results-${msg.id}`,
166
- role: 'tool',
167
- toolResults: completed.map((tc) => ({
168
- id: tc._id,
169
- name: tc.toolName,
170
- result: tc.result!,
171
- })),
172
- createdAt: msg.createdAt,
173
- })
174
- continue
175
- }
176
- }
177
-
178
- messages.push(msg)
179
- }
180
-
181
- return messages
182
- }
183
-
184
- async getThreadRuns(threadId: string): Promise<AgentRunRow[]> {
185
- const result = await this.runs
186
- .find({ threadId })
187
- .sort({ createdAt: -1 })
188
- .toArray()
189
-
190
- return result.map((row) => this.mapRunRow(row))
191
- }
192
-
193
- async deleteThread(threadId: string): Promise<boolean> {
194
- await this.toolCalls.deleteMany({ threadId })
195
- await this.messages.deleteMany({ threadId })
196
- await this.runs.deleteMany({ threadId })
197
- const result = await this.threads.deleteOne({ _id: threadId })
198
- return result.deletedCount > 0
199
- }
200
-
201
- async getDistinctAgentNames(): Promise<string[]> {
202
- const result = await this.runs.distinct('agentName')
203
- return result.sort()
204
- }
205
-
206
- private mapThreadRow(row: AgentThreadDoc): AgentThread {
207
- return {
208
- id: row._id,
209
- resourceId: row.resourceId,
210
- title: row.title ?? undefined,
211
- metadata: row.metadata ?? undefined,
212
- createdAt: new Date(row.createdAt),
213
- updatedAt: new Date(row.updatedAt),
214
- }
215
- }
216
-
217
- private mapRunRow(row: AgentRunDoc): AgentRunRow {
218
- return {
219
- runId: row._id,
220
- agentName: row.agentName,
221
- threadId: row.threadId,
222
- resourceId: row.resourceId,
223
- status: row.status,
224
- errorMessage: row.errorMessage ?? undefined,
225
- suspendReason: row.suspendReason ?? undefined,
226
- missingRpcs: row.missingRpcs ?? undefined,
227
- usageInputTokens: Number(row.usageInputTokens),
228
- usageOutputTokens: Number(row.usageOutputTokens),
229
- usageModel: row.usageModel,
230
- createdAt: new Date(row.createdAt),
231
- updatedAt: new Date(row.updatedAt),
232
- }
233
- }
234
- }