@pikku/kysely 0.13.24 → 0.13.27

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.
Files changed (78) hide show
  1. package/CHANGELOG.md +235 -0
  2. package/dist/src/index.d.ts +4 -1
  3. package/dist/src/index.js +3 -1
  4. package/dist/src/kysely-analytics-service.d.ts +30 -0
  5. package/dist/src/kysely-analytics-service.js +80 -0
  6. package/dist/src/kysely-feature-flag-store.d.ts +37 -0
  7. package/dist/src/kysely-feature-flag-store.js +239 -0
  8. package/dist/src/kysely-tables.d.ts +45 -0
  9. package/dist/src/schema/analytics.schema.d.ts +17 -0
  10. package/dist/src/schema/analytics.schema.js +48 -0
  11. package/dist/src/schema/flag.schema.d.ts +16 -0
  12. package/dist/src/schema/flag.schema.js +62 -0
  13. package/dist/src/schema/index.d.ts +2 -0
  14. package/dist/src/schema/index.js +6 -0
  15. package/package.json +11 -6
  16. package/run-tests.sh +9 -1
  17. package/bin/pikku-kysely-pure.ts +0 -59
  18. package/dist/src/kysely-lock-vault.d.ts +0 -34
  19. package/dist/src/kysely-lock-vault.js +0 -77
  20. package/dist/src/schema/data-lock.schema.d.ts +0 -15
  21. package/dist/src/schema/data-lock.schema.js +0 -27
  22. package/dist/tsconfig.tsbuildinfo +0 -1
  23. package/src/classification-crypto.test.ts +0 -143
  24. package/src/classification-crypto.ts +0 -163
  25. package/src/classification-plugin.pglite.test.ts +0 -226
  26. package/src/classification-plugin.test.ts +0 -265
  27. package/src/classification-plugin.ts +0 -249
  28. package/src/coercion-plugin.test.ts +0 -160
  29. package/src/coercion-plugin.ts +0 -187
  30. package/src/create-audited-kysely.test.ts +0 -560
  31. package/src/create-audited-kysely.ts +0 -254
  32. package/src/index.ts +0 -81
  33. package/src/kysely-agent-run-scores.ts +0 -47
  34. package/src/kysely-agent-run-service.ts +0 -244
  35. package/src/kysely-agent-run-state-service.ts +0 -200
  36. package/src/kysely-agent-storage-service.ts +0 -632
  37. package/src/kysely-audit-service.test.ts +0 -352
  38. package/src/kysely-audit-service.ts +0 -237
  39. package/src/kysely-channel-store.ts +0 -107
  40. package/src/kysely-credential-service.ts +0 -286
  41. package/src/kysely-deployment-service.ts +0 -163
  42. package/src/kysely-eventhub-store.ts +0 -53
  43. package/src/kysely-json.ts +0 -5
  44. package/src/kysely-scope-service.test.ts +0 -418
  45. package/src/kysely-scope-service.ts +0 -425
  46. package/src/kysely-secret-service.ts +0 -242
  47. package/src/kysely-services.test.ts +0 -405
  48. package/src/kysely-session-store.ts +0 -57
  49. package/src/kysely-tables.test.ts +0 -110
  50. package/src/kysely-tables.ts +0 -434
  51. package/src/kysely-virtual-user-run-store.test.ts +0 -369
  52. package/src/kysely-virtual-user-run-store.ts +0 -235
  53. package/src/kysely-virtual-user-schedule-store.test.ts +0 -187
  54. package/src/kysely-virtual-user-schedule-store.ts +0 -187
  55. package/src/kysely-webhook-service.test.ts +0 -153
  56. package/src/kysely-webhook-service.ts +0 -139
  57. package/src/kysely-workflow-mirror.test.ts +0 -259
  58. package/src/kysely-workflow-mirror.ts +0 -374
  59. package/src/kysely-workflow-run-service.ts +0 -305
  60. package/src/kysely-workflow-service.test.ts +0 -544
  61. package/src/kysely-workflow-service.ts +0 -820
  62. package/src/schema/agent.schema.ts +0 -162
  63. package/src/schema/audit.schema.ts +0 -57
  64. package/src/schema/channel.schema.ts +0 -38
  65. package/src/schema/credential.schema.ts +0 -58
  66. package/src/schema/deployment.schema.ts +0 -47
  67. package/src/schema/index.ts +0 -441
  68. package/src/schema/pikku-schema.types.ts +0 -169
  69. package/src/schema/schema.test.ts +0 -591
  70. package/src/schema/scope.schema.ts +0 -110
  71. package/src/schema/secret.schema.ts +0 -49
  72. package/src/schema/session.schema.ts +0 -20
  73. package/src/schema/virtual-user-schedule.schema.ts +0 -48
  74. package/src/schema/virtual-user.schema.ts +0 -106
  75. package/src/schema/webhook.schema.ts +0 -58
  76. package/src/schema/workflow.schema.ts +0 -150
  77. package/src/serialize-plugin.ts +0 -233
  78. package/tsconfig.json +0 -17
@@ -1,632 +0,0 @@
1
- import type {
2
- AgentMessage,
3
- AgentRunState,
4
- AgentThread,
5
- } from '@pikku/core/agent'
6
- import type { AgentRunScore } from '@pikku/core/agent-scorer'
7
- import type {
8
- AgentRunStateService,
9
- AgentStorageService,
10
- CreateRunInput,
11
- SaveScoreInput,
12
- } from '@pikku/core/services'
13
- import type { Kysely } from 'kysely'
14
- import type { KyselyPikkuDB } from './kysely-tables.js'
15
- import { parseJson } from './kysely-json.js'
16
- import { getRunScores, saveRunScore } from './kysely-agent-run-scores.js'
17
- import { requirePikkuSchema } from './schema/index.js'
18
- import { agentSchema } from './schema/agent.schema.js'
19
-
20
- export class KyselyAgentStorageService
21
- implements AgentStorageService, AgentRunStateService
22
- {
23
- private initialized = false
24
-
25
- constructor(private db: Kysely<KyselyPikkuDB>) {}
26
-
27
- public async init(): Promise<void> {
28
- if (this.initialized) return
29
- await requirePikkuSchema(this.db, agentSchema)
30
- this.initialized = true
31
- }
32
-
33
- async createThread(
34
- resourceId: string,
35
- options?: {
36
- threadId?: string
37
- title?: string
38
- metadata?: Record<string, unknown>
39
- }
40
- ): Promise<AgentThread> {
41
- const id = options?.threadId ?? crypto.randomUUID()
42
- const now = new Date()
43
-
44
- await this.db
45
- .insertInto('agentThreads')
46
- .values({
47
- id,
48
- resourceId: resourceId,
49
- title: options?.title ?? null,
50
- metadata: JSON.stringify(options?.metadata ?? null),
51
- createdAt: now,
52
- updatedAt: now,
53
- })
54
- .execute()
55
-
56
- return {
57
- id,
58
- resourceId,
59
- title: options?.title,
60
- metadata: options?.metadata,
61
- createdAt: now,
62
- updatedAt: now,
63
- }
64
- }
65
-
66
- async getThread(threadId: string): Promise<AgentThread> {
67
- const row = await this.db
68
- .selectFrom('agentThreads')
69
- .select([
70
- 'id',
71
- 'resourceId',
72
- 'title',
73
- 'metadata',
74
- 'createdAt',
75
- 'updatedAt',
76
- ])
77
- .where('id', '=', threadId)
78
- .executeTakeFirst()
79
-
80
- if (!row) {
81
- throw new Error(`Thread not found: ${threadId}`)
82
- }
83
-
84
- return {
85
- id: row.id,
86
- resourceId: row.resourceId,
87
- title: row.title ?? undefined,
88
- metadata: parseJson(row.metadata),
89
- createdAt: new Date(row.createdAt),
90
- updatedAt: new Date(row.updatedAt),
91
- }
92
- }
93
-
94
- async getThreads(resourceId: string): Promise<AgentThread[]> {
95
- const result = await this.db
96
- .selectFrom('agentThreads')
97
- .select([
98
- 'id',
99
- 'resourceId',
100
- 'title',
101
- 'metadata',
102
- 'createdAt',
103
- 'updatedAt',
104
- ])
105
- .where('resourceId', '=', resourceId)
106
- .orderBy('updatedAt', 'desc')
107
- .execute()
108
-
109
- return result.map((row) => ({
110
- id: row.id,
111
- resourceId: row.resourceId,
112
- title: row.title ?? undefined,
113
- metadata: parseJson(row.metadata),
114
- createdAt: new Date(row.createdAt),
115
- updatedAt: new Date(row.updatedAt),
116
- }))
117
- }
118
-
119
- async deleteThread(threadId: string): Promise<void> {
120
- await this.db
121
- .deleteFrom('agentThreads')
122
- .where('id', '=', threadId)
123
- .execute()
124
- }
125
-
126
- async getMessages(
127
- threadId: string,
128
- options?: { lastN?: number; cursor?: string }
129
- ): Promise<AgentMessage[]> {
130
- let msgQuery = this.db
131
- .selectFrom('agentMessage')
132
- .select(['id', 'role', 'content', 'createdAt'])
133
- .where('threadId', '=', threadId)
134
-
135
- if (options?.cursor) {
136
- const cursorRow = await this.db
137
- .selectFrom('agentMessage')
138
- .select('createdAt')
139
- .where('id', '=', options.cursor)
140
- .executeTakeFirst()
141
-
142
- if (cursorRow) {
143
- msgQuery = msgQuery.where('createdAt', '<', cursorRow.createdAt)
144
- }
145
- }
146
-
147
- let msgResult
148
- if (options?.cursor || options?.lastN) {
149
- const innerResult = await msgQuery
150
- .orderBy('createdAt', 'desc')
151
- .limit(options?.lastN ?? 50)
152
- .execute()
153
- innerResult.reverse()
154
- msgResult = innerResult
155
- } else {
156
- msgResult = await msgQuery.orderBy('createdAt', 'asc').execute()
157
- }
158
-
159
- const tcResult = await this.db
160
- .selectFrom('agentToolCall')
161
- .select(['id', 'messageId', 'toolName', 'args', 'result'])
162
- .where('threadId', '=', threadId)
163
- .orderBy('createdAt', 'asc')
164
- .execute()
165
-
166
- const tcByMessage = new Map<string, (typeof tcResult)[number][]>()
167
- for (const tc of tcResult) {
168
- const msgId = tc.messageId
169
- if (!tcByMessage.has(msgId)) tcByMessage.set(msgId, [])
170
- tcByMessage.get(msgId)!.push(tc)
171
- }
172
-
173
- const messages: AgentMessage[] = []
174
- for (const row of msgResult) {
175
- const rawContent = row.content as string | undefined
176
- let parsedContent: AgentMessage['content'] = rawContent ?? undefined
177
- if (rawContent) {
178
- try {
179
- const parsed = JSON.parse(rawContent)
180
- if (Array.isArray(parsed)) {
181
- parsedContent = parsed
182
- } else if (typeof parsed === 'string') {
183
- parsedContent = parsed
184
- }
185
- } catch {
186
- // Not JSON, use raw string
187
- }
188
- }
189
- const msg: AgentMessage = {
190
- id: row.id,
191
- role: row.role as AgentMessage['role'],
192
- content: parsedContent,
193
- createdAt: new Date(row.createdAt),
194
- }
195
-
196
- const tcs = tcByMessage.get(msg.id)
197
- if (tcs?.length) {
198
- msg.toolCalls = tcs.map((tc) => ({
199
- id: tc.id,
200
- name: tc.toolName,
201
- args: parseJson(tc.args) as Record<string, unknown>,
202
- }))
203
-
204
- const completed = tcs.filter((tc) => tc.result != null)
205
- if (completed.length) {
206
- messages.push(msg)
207
- messages.push({
208
- id: `tool-results-${msg.id}`,
209
- role: 'tool',
210
- toolResults: completed.map((tc) => ({
211
- id: tc.id,
212
- name: tc.toolName,
213
- result: tc.result!,
214
- })),
215
- createdAt: msg.createdAt,
216
- })
217
- continue
218
- }
219
- }
220
-
221
- messages.push(msg)
222
- }
223
-
224
- return messages
225
- }
226
-
227
- async saveMessages(
228
- threadId: string,
229
- messages: AgentMessage[]
230
- ): Promise<void> {
231
- if (messages.length === 0) return
232
-
233
- const toolMessages = messages.filter((m) => m.role === 'tool')
234
- const nonToolMessages = messages.filter((m) => m.role !== 'tool')
235
-
236
- if (nonToolMessages.length > 0) {
237
- await this.db
238
- .insertInto('agentMessage')
239
- .values(
240
- nonToolMessages.map((msg) => ({
241
- id: msg.id,
242
- threadId: threadId,
243
- role: msg.role,
244
- content: msg.content != null ? JSON.stringify(msg.content) : null,
245
- createdAt: msg.createdAt ?? new Date(),
246
- }))
247
- )
248
- .execute()
249
- }
250
-
251
- const toolCalls = nonToolMessages.flatMap(
252
- (msg) => msg.toolCalls?.map((tc) => ({ ...tc, messageId: msg.id })) ?? []
253
- )
254
- if (toolCalls.length > 0) {
255
- await this.db
256
- .insertInto('agentToolCall')
257
- .values(
258
- toolCalls.map((tc) => ({
259
- id: tc.id,
260
- threadId: threadId,
261
- messageId: tc.messageId,
262
- toolName: tc.name,
263
- args: JSON.stringify(tc.args),
264
- }))
265
- )
266
- .execute()
267
- }
268
-
269
- for (const toolMsg of toolMessages) {
270
- if (!toolMsg.toolResults) continue
271
- for (const tr of toolMsg.toolResults) {
272
- await this.db
273
- .updateTable('agentToolCall')
274
- .set({ result: tr.result })
275
- .where('id', '=', tr.id)
276
- .execute()
277
- }
278
- }
279
-
280
- await this.db
281
- .updateTable('agentThreads')
282
- .set({ updatedAt: new Date() })
283
- .where('id', '=', threadId)
284
- .execute()
285
- }
286
-
287
- async getWorkingMemory(
288
- id: string,
289
- scope: 'resource' | 'thread'
290
- ): Promise<Record<string, unknown> | null> {
291
- const row = await this.db
292
- .selectFrom('agentWorkingMemory')
293
- .select('data')
294
- .where('id', '=', id)
295
- .where('scope', '=', scope)
296
- .executeTakeFirst()
297
-
298
- if (!row) return null
299
- return parseJson(row.data)
300
- }
301
-
302
- async saveWorkingMemory(
303
- id: string,
304
- scope: 'resource' | 'thread',
305
- data: Record<string, unknown>
306
- ): Promise<void> {
307
- await this.db
308
- .insertInto('agentWorkingMemory')
309
- .values({
310
- id,
311
- scope,
312
- data: JSON.stringify(data),
313
- updatedAt: new Date(),
314
- })
315
- .onConflict((oc) =>
316
- oc.columns(['id', 'scope']).doUpdateSet({
317
- data: JSON.stringify(data),
318
- updatedAt: new Date(),
319
- })
320
- )
321
- .execute()
322
- }
323
-
324
- async createRun(run: CreateRunInput): Promise<string> {
325
- const runId = crypto.randomUUID()
326
-
327
- await this.db
328
- .insertInto('agentRun')
329
- .values({
330
- runId: runId,
331
- agentName: run.agentName,
332
- threadId: run.threadId,
333
- resourceId: run.resourceId,
334
- status: run.status,
335
- errorMessage: run.errorMessage ?? null,
336
- suspendReason: run.suspendReason ?? null,
337
- missingRpcs: run.missingRpcs ? JSON.stringify(run.missingRpcs) : null,
338
- usageInputTokens: run.usage.inputTokens,
339
- usageOutputTokens: run.usage.outputTokens,
340
- usageModel: run.usage.model,
341
- createdAt: run.createdAt,
342
- updatedAt: run.updatedAt,
343
- })
344
- .execute()
345
-
346
- if (run.pendingApprovals?.length) {
347
- await this.setApprovals(runId, run.pendingApprovals)
348
- }
349
-
350
- return runId
351
- }
352
-
353
- async updateRun(
354
- runId: string,
355
- updates: Partial<AgentRunState>
356
- ): Promise<void> {
357
- const setValues: Record<string, unknown> = { updatedAt: new Date() }
358
-
359
- if (updates.status !== undefined) {
360
- setValues.status = updates.status
361
- }
362
- if (updates.errorMessage !== undefined) {
363
- setValues.errorMessage = updates.errorMessage
364
- }
365
- if (updates.suspendReason !== undefined) {
366
- setValues.suspendReason = updates.suspendReason
367
- }
368
- if (updates.missingRpcs !== undefined) {
369
- setValues.missingRpcs = JSON.stringify(updates.missingRpcs)
370
- }
371
- if (updates.usage !== undefined) {
372
- setValues.usageInputTokens = updates.usage.inputTokens
373
- setValues.usageOutputTokens = updates.usage.outputTokens
374
- setValues.usageModel = updates.usage.model
375
- }
376
-
377
- await this.db
378
- .updateTable('agentRun')
379
- .set(setValues)
380
- .where('runId', '=', runId)
381
- .execute()
382
-
383
- if (updates.pendingApprovals !== undefined) {
384
- await this.db
385
- .updateTable('agentToolCall')
386
- .set({
387
- approvalStatus: null,
388
- runId: null,
389
- approvalType: null,
390
- agentRunId: null,
391
- displayToolName: null,
392
- displayArgs: null,
393
- })
394
- .where('runId', '=', runId)
395
- .where('approvalStatus', 'is not', null)
396
- .execute()
397
-
398
- if (updates.pendingApprovals.length) {
399
- await this.setApprovals(runId, updates.pendingApprovals)
400
- }
401
- }
402
- }
403
-
404
- async getRun(runId: string): Promise<AgentRunState | null> {
405
- const row = await this.db
406
- .selectFrom('agentRun')
407
- .select([
408
- 'runId',
409
- 'agentName',
410
- 'threadId',
411
- 'resourceId',
412
- 'status',
413
- 'errorMessage',
414
- 'suspendReason',
415
- 'missingRpcs',
416
- 'usageInputTokens',
417
- 'usageOutputTokens',
418
- 'usageModel',
419
- 'createdAt',
420
- 'updatedAt',
421
- ])
422
- .where('runId', '=', runId)
423
- .executeTakeFirst()
424
-
425
- if (!row) return null
426
-
427
- const approvals = await this.db
428
- .selectFrom('agentToolCall')
429
- .select([
430
- 'id',
431
- 'toolName',
432
- 'args',
433
- 'approvalType',
434
- 'agentRunId',
435
- 'displayToolName',
436
- 'displayArgs',
437
- ])
438
- .where('runId', '=', runId)
439
- .where('approvalStatus', '=', 'pending')
440
- .execute()
441
-
442
- return this.mapRunRow(row, approvals)
443
- }
444
-
445
- async getRunsByThread(threadId: string): Promise<AgentRunState[]> {
446
- const result = await this.db
447
- .selectFrom('agentRun')
448
- .select([
449
- 'runId',
450
- 'agentName',
451
- 'threadId',
452
- 'resourceId',
453
- 'status',
454
- 'errorMessage',
455
- 'suspendReason',
456
- 'missingRpcs',
457
- 'usageInputTokens',
458
- 'usageOutputTokens',
459
- 'usageModel',
460
- 'createdAt',
461
- 'updatedAt',
462
- ])
463
- .where('threadId', '=', threadId)
464
- .orderBy('createdAt', 'desc')
465
- .execute()
466
-
467
- const runs: AgentRunState[] = []
468
- for (const row of result) {
469
- const approvals = await this.db
470
- .selectFrom('agentToolCall')
471
- .select([
472
- 'id',
473
- 'toolName',
474
- 'args',
475
- 'approvalType',
476
- 'agentRunId',
477
- 'displayToolName',
478
- 'displayArgs',
479
- ])
480
- .where('runId', '=', row.runId)
481
- .where('approvalStatus', '=', 'pending')
482
- .execute()
483
- runs.push(this.mapRunRow(row, approvals))
484
- }
485
- return runs
486
- }
487
-
488
- private async setApprovals(
489
- runId: string,
490
- approvals: NonNullable<AgentRunState['pendingApprovals']>
491
- ): Promise<void> {
492
- for (const a of approvals) {
493
- if (a.type === 'agent-call') {
494
- await this.db
495
- .updateTable('agentToolCall')
496
- .set({
497
- approvalStatus: 'pending',
498
- runId: runId,
499
- approvalType: 'agent-call',
500
- agentRunId: a.agentRunId,
501
- displayToolName: a.displayToolName,
502
- displayArgs: JSON.stringify(a.displayArgs),
503
- })
504
- .where('id', '=', a.toolCallId)
505
- .execute()
506
- } else {
507
- await this.db
508
- .updateTable('agentToolCall')
509
- .set({
510
- approvalStatus: 'pending',
511
- runId: runId,
512
- approvalType: 'tool-call',
513
- })
514
- .where('id', '=', a.toolCallId)
515
- .execute()
516
- }
517
- }
518
- }
519
-
520
- private mapRunRow(row: any, approvalRows?: any[]): AgentRunState {
521
- const pendingApprovals = approvalRows?.length
522
- ? approvalRows.map((a: any) => {
523
- if (a.approvalType === 'agent-call') {
524
- return {
525
- type: 'agent-call' as const,
526
- toolCallId: a.id as string,
527
- agentName: a.toolName as string,
528
- agentRunId: a.agentRunId as string,
529
- displayToolName: a.displayToolName as string,
530
- displayArgs: parseJson(a.displayArgs) as unknown,
531
- }
532
- }
533
- return {
534
- type: 'tool-call' as const,
535
- toolCallId: a.id as string,
536
- toolName: a.toolName as string,
537
- args: parseJson(a.args) as unknown,
538
- }
539
- })
540
- : undefined
541
-
542
- return {
543
- runId: row.runId as string,
544
- agentName: row.agentName as string,
545
- threadId: row.threadId as string,
546
- resourceId: row.resourceId as string,
547
- status: row.status as AgentRunState['status'],
548
- errorMessage: row.errorMessage ?? undefined,
549
- suspendReason: row.suspendReason as AgentRunState['suspendReason'],
550
- missingRpcs: parseJson(row.missingRpcs),
551
- pendingApprovals,
552
- usage: {
553
- inputTokens: Number(row.usageInputTokens),
554
- outputTokens: Number(row.usageOutputTokens),
555
- model: row.usageModel as string,
556
- },
557
- createdAt: new Date(row.createdAt as string),
558
- updatedAt: new Date(row.updatedAt as string),
559
- }
560
- }
561
-
562
- async findRunByToolCallId(toolCallId: string): Promise<{
563
- run: AgentRunState
564
- approval: NonNullable<AgentRunState['pendingApprovals']>[number]
565
- } | null> {
566
- const tc = await this.db
567
- .selectFrom('agentToolCall')
568
- .select([
569
- 'id',
570
- 'toolName',
571
- 'args',
572
- 'runId',
573
- 'approvalType',
574
- 'agentRunId',
575
- 'displayToolName',
576
- 'displayArgs',
577
- ])
578
- .where('id', '=', toolCallId)
579
- .where('approvalStatus', '=', 'pending')
580
- .executeTakeFirst()
581
-
582
- if (!tc || !tc.runId) return null
583
-
584
- const run = await this.getRun(tc.runId)
585
- if (!run) return null
586
-
587
- let approval: NonNullable<AgentRunState['pendingApprovals']>[number]
588
- if (tc.approvalType === 'agent-call') {
589
- approval = {
590
- type: 'agent-call',
591
- toolCallId: tc.id,
592
- agentName: tc.toolName,
593
- agentRunId: tc.agentRunId!,
594
- displayToolName: tc.displayToolName!,
595
- displayArgs: parseJson(tc.displayArgs) as unknown,
596
- }
597
- } else {
598
- approval = {
599
- type: 'tool-call',
600
- toolCallId: tc.id,
601
- toolName: tc.toolName,
602
- args: parseJson(tc.args) as unknown,
603
- }
604
- }
605
-
606
- return { run, approval }
607
- }
608
-
609
- async resolveApproval(
610
- toolCallId: string,
611
- status: 'approved' | 'denied'
612
- ): Promise<boolean> {
613
- // Only the caller that moves the tool call off 'pending' has claimed it.
614
- const result = await this.db
615
- .updateTable('agentToolCall')
616
- .set({ approvalStatus: status })
617
- .where('id', '=', toolCallId)
618
- .where('approvalStatus', '=', 'pending')
619
- .executeTakeFirst()
620
- return Number(result?.numUpdatedRows ?? 0) > 0
621
- }
622
-
623
- async saveScore(score: SaveScoreInput): Promise<void> {
624
- await saveRunScore(this.db, score)
625
- }
626
-
627
- async getScores(runId: string): Promise<AgentRunScore[]> {
628
- return getRunScores(this.db, runId)
629
- }
630
-
631
- public async close(): Promise<void> {}
632
- }