@pikku/kysely 0.13.23 → 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 (80) hide show
  1. package/CHANGELOG.md +248 -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/kysely-webhook-service.d.ts +1 -1
  10. package/dist/src/kysely-webhook-service.js +1 -1
  11. package/dist/src/schema/analytics.schema.d.ts +17 -0
  12. package/dist/src/schema/analytics.schema.js +48 -0
  13. package/dist/src/schema/flag.schema.d.ts +16 -0
  14. package/dist/src/schema/flag.schema.js +62 -0
  15. package/dist/src/schema/index.d.ts +2 -0
  16. package/dist/src/schema/index.js +6 -0
  17. package/package.json +11 -6
  18. package/run-tests.sh +9 -1
  19. package/bin/pikku-kysely-pure.ts +0 -59
  20. package/dist/src/kysely-lock-vault.d.ts +0 -34
  21. package/dist/src/kysely-lock-vault.js +0 -77
  22. package/dist/src/schema/data-lock.schema.d.ts +0 -15
  23. package/dist/src/schema/data-lock.schema.js +0 -27
  24. package/dist/tsconfig.tsbuildinfo +0 -1
  25. package/src/classification-crypto.test.ts +0 -143
  26. package/src/classification-crypto.ts +0 -163
  27. package/src/classification-plugin.pglite.test.ts +0 -226
  28. package/src/classification-plugin.test.ts +0 -265
  29. package/src/classification-plugin.ts +0 -249
  30. package/src/coercion-plugin.test.ts +0 -160
  31. package/src/coercion-plugin.ts +0 -187
  32. package/src/create-audited-kysely.test.ts +0 -560
  33. package/src/create-audited-kysely.ts +0 -254
  34. package/src/index.ts +0 -81
  35. package/src/kysely-agent-run-scores.ts +0 -47
  36. package/src/kysely-agent-run-service.ts +0 -244
  37. package/src/kysely-agent-run-state-service.ts +0 -200
  38. package/src/kysely-agent-storage-service.ts +0 -632
  39. package/src/kysely-audit-service.test.ts +0 -352
  40. package/src/kysely-audit-service.ts +0 -237
  41. package/src/kysely-channel-store.ts +0 -107
  42. package/src/kysely-credential-service.ts +0 -286
  43. package/src/kysely-deployment-service.ts +0 -163
  44. package/src/kysely-eventhub-store.ts +0 -53
  45. package/src/kysely-json.ts +0 -5
  46. package/src/kysely-scope-service.test.ts +0 -418
  47. package/src/kysely-scope-service.ts +0 -425
  48. package/src/kysely-secret-service.ts +0 -242
  49. package/src/kysely-services.test.ts +0 -405
  50. package/src/kysely-session-store.ts +0 -57
  51. package/src/kysely-tables.test.ts +0 -110
  52. package/src/kysely-tables.ts +0 -434
  53. package/src/kysely-virtual-user-run-store.test.ts +0 -369
  54. package/src/kysely-virtual-user-run-store.ts +0 -235
  55. package/src/kysely-virtual-user-schedule-store.test.ts +0 -187
  56. package/src/kysely-virtual-user-schedule-store.ts +0 -187
  57. package/src/kysely-webhook-service.test.ts +0 -124
  58. package/src/kysely-webhook-service.ts +0 -137
  59. package/src/kysely-workflow-mirror.test.ts +0 -259
  60. package/src/kysely-workflow-mirror.ts +0 -374
  61. package/src/kysely-workflow-run-service.ts +0 -305
  62. package/src/kysely-workflow-service.test.ts +0 -544
  63. package/src/kysely-workflow-service.ts +0 -820
  64. package/src/schema/agent.schema.ts +0 -162
  65. package/src/schema/audit.schema.ts +0 -57
  66. package/src/schema/channel.schema.ts +0 -38
  67. package/src/schema/credential.schema.ts +0 -58
  68. package/src/schema/deployment.schema.ts +0 -47
  69. package/src/schema/index.ts +0 -441
  70. package/src/schema/pikku-schema.types.ts +0 -169
  71. package/src/schema/schema.test.ts +0 -591
  72. package/src/schema/scope.schema.ts +0 -110
  73. package/src/schema/secret.schema.ts +0 -49
  74. package/src/schema/session.schema.ts +0 -20
  75. package/src/schema/virtual-user-schedule.schema.ts +0 -48
  76. package/src/schema/virtual-user.schema.ts +0 -106
  77. package/src/schema/webhook.schema.ts +0 -58
  78. package/src/schema/workflow.schema.ts +0 -150
  79. package/src/serialize-plugin.ts +0 -233
  80. package/tsconfig.json +0 -17
@@ -1,254 +0,0 @@
1
- import type { AuditLog } from '@pikku/core/services'
2
- import type {
3
- Kysely,
4
- KyselyPlugin,
5
- PluginTransformQueryArgs,
6
- PluginTransformResultArgs,
7
- QueryResult,
8
- RootOperationNode,
9
- UnknownRow,
10
- } from 'kysely'
11
-
12
- export interface CreateAuditedKyselyOptions {
13
- audit: AuditLog
14
- auditReads?: boolean
15
- eventType?: string
16
- transactionId?: string | null
17
- queryIdPrefix?: string
18
- }
19
-
20
- type AuditedQuery = {
21
- queryKind: 'select' | 'insert' | 'update' | 'delete'
22
- queryId: string
23
- tables: string[]
24
- changedColumns?: string[]
25
- changes?: unknown
26
- }
27
-
28
- const QUERY_KIND_BY_NODE: Record<
29
- string,
30
- AuditedQuery['queryKind'] | undefined
31
- > = {
32
- SelectQueryNode: 'select',
33
- InsertQueryNode: 'insert',
34
- UpdateQueryNode: 'update',
35
- DeleteQueryNode: 'delete',
36
- }
37
-
38
- function getIdentifierName(node: unknown): string | undefined {
39
- if (!node || typeof node !== 'object') return undefined
40
- const candidate = node as {
41
- name?: string
42
- column?: { name?: string }
43
- identifier?: { name?: string }
44
- table?: { identifier?: { name?: string } }
45
- }
46
- return (
47
- candidate.name ??
48
- candidate.column?.name ??
49
- candidate.identifier?.name ??
50
- candidate.table?.identifier?.name
51
- )
52
- }
53
-
54
- function collectTableNames(node: unknown, out: Set<string>): void {
55
- if (!node || typeof node !== 'object') return
56
-
57
- const candidate = node as {
58
- kind?: string
59
- table?: { identifier?: { name?: string } }
60
- }
61
-
62
- if (
63
- candidate.kind === 'TableNode' &&
64
- typeof candidate.table?.identifier?.name === 'string'
65
- ) {
66
- out.add(candidate.table.identifier.name)
67
- }
68
-
69
- for (const value of Object.values(node as Record<string, unknown>)) {
70
- if (Array.isArray(value)) {
71
- for (const item of value) collectTableNames(item, out)
72
- continue
73
- }
74
- collectTableNames(value, out)
75
- }
76
- }
77
-
78
- function extractValue(node: unknown): unknown {
79
- if (!node || typeof node !== 'object') return node
80
-
81
- const candidate = node as {
82
- kind?: string
83
- value?: unknown
84
- values?: unknown[]
85
- left?: unknown
86
- right?: unknown
87
- }
88
-
89
- switch (candidate.kind) {
90
- case 'ValueNode':
91
- return candidate.value
92
- case 'PrimitiveValueListNode':
93
- case 'ValueListNode':
94
- return (candidate.values ?? []).map(extractValue)
95
- case 'DefaultInsertValueNode':
96
- return '[default]'
97
- case 'ColumnNode':
98
- case 'ReferenceNode':
99
- return `[${candidate.kind}]`
100
- case 'RawNode':
101
- return '[raw]'
102
- case 'SelectQueryNode':
103
- return '[subquery]'
104
- case 'ParensNode':
105
- return extractValue((candidate as { node?: unknown }).node)
106
- case 'BinaryOperationNode':
107
- return {
108
- left: extractValue(candidate.left),
109
- right: extractValue(candidate.right),
110
- }
111
- default:
112
- return `[${candidate.kind ?? 'expression'}]`
113
- }
114
- }
115
-
116
- function extractInsertChanges(node: any): {
117
- changedColumns?: string[]
118
- changes?: unknown
119
- } {
120
- const columns = Array.isArray(node.columns)
121
- ? node.columns
122
- .map((column: unknown) => getIdentifierName(column))
123
- .filter(Boolean)
124
- : []
125
- const values = Array.isArray(node.values?.values) ? node.values.values : []
126
- if (columns.length === 0 || values.length === 0) {
127
- return {
128
- changedColumns: columns.length > 0 ? columns : undefined,
129
- }
130
- }
131
-
132
- const rows = values.map((row: any) => {
133
- const rowValues = Array.isArray(row?.values)
134
- ? row.values.map(extractValue)
135
- : []
136
- return Object.fromEntries(
137
- columns.map((column, index) => [column, rowValues[index]])
138
- )
139
- })
140
-
141
- return {
142
- changedColumns: columns,
143
- changes: rows.length === 1 ? rows[0] : rows,
144
- }
145
- }
146
-
147
- function extractUpdateChanges(node: any): {
148
- changedColumns?: string[]
149
- changes?: unknown
150
- } {
151
- const updates = Array.isArray(node.updates) ? node.updates : []
152
- const entries = updates
153
- .map((update: any) => {
154
- const column = getIdentifierName(update.column)
155
- if (!column) return null
156
- return [column, extractValue(update.value)] as const
157
- })
158
- .filter(Boolean) as Array<readonly [string, unknown]>
159
-
160
- if (entries.length === 0) {
161
- return {}
162
- }
163
-
164
- return {
165
- changedColumns: entries.map(([column]) => column),
166
- changes: Object.fromEntries(entries),
167
- }
168
- }
169
-
170
- function extractChangeSet(
171
- node: RootOperationNode,
172
- queryKind: AuditedQuery['queryKind']
173
- ) {
174
- if (queryKind === 'insert') {
175
- return extractInsertChanges(node as any)
176
- }
177
- if (queryKind === 'update') {
178
- return extractUpdateChanges(node as any)
179
- }
180
- return {}
181
- }
182
-
183
- class AuditedKyselyPlugin implements KyselyPlugin {
184
- private readonly pending = new Map<unknown, AuditedQuery>()
185
- private queryCounter = 0
186
-
187
- constructor(private readonly options: CreateAuditedKyselyOptions) {}
188
-
189
- transformQuery(args: PluginTransformQueryArgs): RootOperationNode {
190
- const queryKind =
191
- QUERY_KIND_BY_NODE[(args.node as { kind?: string }).kind ?? '']
192
- if (!queryKind) {
193
- return args.node
194
- }
195
-
196
- if (queryKind === 'select' && this.options.auditReads === false) {
197
- return args.node
198
- }
199
-
200
- const tables = new Set<string>()
201
- collectTableNames(args.node, tables)
202
- const queryId = `${this.options.queryIdPrefix ?? 'q'}-${++this.queryCounter}`
203
- this.pending.set(args.queryId, {
204
- queryKind,
205
- queryId,
206
- tables: [...tables].sort(),
207
- ...extractChangeSet(args.node, queryKind),
208
- })
209
- return args.node
210
- }
211
-
212
- async transformResult(
213
- args: PluginTransformResultArgs
214
- ): Promise<QueryResult<UnknownRow>> {
215
- const pending = this.pending.get(args.queryId)
216
- if (!pending) {
217
- return args.result
218
- }
219
-
220
- this.pending.delete(args.queryId)
221
- const rawResult = args.result as QueryResult<UnknownRow> & {
222
- numAffectedRows?: bigint
223
- numUpdatedOrDeletedRows?: bigint
224
- }
225
- const rowCount =
226
- rawResult.rows.length > 0
227
- ? rawResult.rows.length
228
- : Number(
229
- rawResult.numUpdatedOrDeletedRows ?? rawResult.numAffectedRows ?? 0n
230
- )
231
-
232
- await this.options.audit.write({
233
- type: this.options.eventType ?? 'db.query',
234
- source: 'auto',
235
- transactionId: this.options.transactionId ?? null,
236
- queryId: pending.queryId,
237
- metadata: {
238
- queryKind: pending.queryKind,
239
- tables: pending.tables,
240
- changedColumns: pending.changedColumns,
241
- changes: pending.changes,
242
- rowCount,
243
- },
244
- })
245
- return rawResult
246
- }
247
- }
248
-
249
- export function createAuditedKysely<DB>(
250
- db: Kysely<DB>,
251
- options: CreateAuditedKyselyOptions
252
- ): Kysely<DB> {
253
- return db.withPlugin(new AuditedKyselyPlugin(options))
254
- }
package/src/index.ts DELETED
@@ -1,81 +0,0 @@
1
- export { KyselyChannelStore } from './kysely-channel-store.js'
2
- export { KyselyEventHubStore } from './kysely-eventhub-store.js'
3
- export { KyselyWorkflowService } from './kysely-workflow-service.js'
4
- export { KyselyWorkflowRunService } from './kysely-workflow-run-service.js'
5
- export { KyselyWorkflowMirror } from './kysely-workflow-mirror.js'
6
- export { KyselyDeploymentService } from './kysely-deployment-service.js'
7
- export { KyselyAgentStorageService } from './kysely-agent-storage-service.js'
8
- export { KyselyAgentRunService } from './kysely-agent-run-service.js'
9
- export { KyselyAgentRunStateService } from './kysely-agent-run-state-service.js'
10
- export { KyselySecretService } from './kysely-secret-service.js'
11
- export { KyselyCredentialService } from './kysely-credential-service.js'
12
- export { KyselySessionStore } from './kysely-session-store.js'
13
- export { KyselyScopeService } from './kysely-scope-service.js'
14
- export { KyselyWebhookService } from './kysely-webhook-service.js'
15
- export {
16
- createAuditedKysely,
17
- type CreateAuditedKyselyOptions,
18
- } from './create-audited-kysely.js'
19
- export { KyselyAuditService } from './kysely-audit-service.js'
20
- export { KyselyVirtualUserRunStore } from './kysely-virtual-user-run-store.js'
21
- export { KyselyVirtualUserScheduleStore } from './kysely-virtual-user-schedule-store.js'
22
-
23
- export {
24
- SerializePlugin,
25
- BaseSerializePlugin,
26
- type Serializer,
27
- type Deserializer,
28
- } from './serialize-plugin.js'
29
- export {
30
- createCoercionPlugin,
31
- type ColumnKind,
32
- type CoercionMap,
33
- type CreateCoercionPluginOptions,
34
- } from './coercion-plugin.js'
35
- export {
36
- createClassificationPlugin,
37
- type CreateClassificationPluginOptions,
38
- } from './classification-plugin.js'
39
- export {
40
- ClassificationCrypto,
41
- DEFAULT_KEY_ID,
42
- isColumnEnvelope,
43
- parseColumnEnvelope,
44
- type ClassificationCryptoOptions,
45
- type ColumnEnvelope,
46
- type KEKResolver,
47
- type ResolvedKEK,
48
- } from './classification-crypto.js'
49
- export {
50
- agentSchema,
51
- auditSchema,
52
- channelSchema,
53
- credentialSchema,
54
- deploymentSchema,
55
- scopeSchema,
56
- secretSchema,
57
- sessionSchema,
58
- virtualUserSchema,
59
- webhookSchema,
60
- workflowSchema,
61
- pikkuSchemas,
62
- requiredPikkuSchemas,
63
- applyPikkuSchemas,
64
- compilePikkuSchemas,
65
- requirePikkuSchema,
66
- resolveRequirements,
67
- type PikkuSchema,
68
- type RequiredTypes,
69
- type UnmetRequirement,
70
- type SchemaStatementFactory,
71
- } from './schema/index.js'
72
-
73
- export type { KyselyPikkuDB } from './kysely-tables.js'
74
- export type { WorkflowRunService } from '@pikku/core/workflow'
75
- export type { AgentRunService, AgentRunRow } from '@pikku/core/agent'
76
- export type {
77
- VirtualUserRunStore,
78
- VirtualUserRunRecord,
79
- VirtualUserScheduleStore,
80
- VirtualUserScheduleRecord,
81
- } from '@pikku/core/virtual-user'
@@ -1,47 +0,0 @@
1
- import type { Kysely } from 'kysely'
2
- import type { KyselyPikkuDB } from './kysely-tables.js'
3
- import type { AgentRunScore } from '@pikku/core/agent-scorer'
4
- import type { SaveScoreInput } from '@pikku/core/services'
5
- import { parseJson } from './kysely-json.js'
6
-
7
- /**
8
- * Shared by the two Kysely services that implement `AgentRunStateService` — they
9
- * differ in how they store approvals, not in how they store grades.
10
- */
11
- export const saveRunScore = async (
12
- db: Kysely<KyselyPikkuDB>,
13
- score: SaveScoreInput
14
- ): Promise<void> => {
15
- await db
16
- .insertInto('agentRunScore')
17
- .values({
18
- id: crypto.randomUUID(),
19
- runId: score.runId,
20
- scorerName: score.scorerName,
21
- score: score.score,
22
- reason: score.reason ?? null,
23
- metadata: score.metadata ? JSON.stringify(score.metadata) : null,
24
- })
25
- .execute()
26
- }
27
-
28
- export const getRunScores = async (
29
- db: Kysely<KyselyPikkuDB>,
30
- runId: string
31
- ): Promise<AgentRunScore[]> => {
32
- const rows = await db
33
- .selectFrom('agentRunScore')
34
- .selectAll()
35
- .where('runId', '=', runId)
36
- .orderBy('createdAt', 'asc')
37
- .execute()
38
-
39
- return rows.map((row) => ({
40
- runId: row.runId,
41
- scorerName: row.scorerName,
42
- score: Number(row.score),
43
- reason: row.reason ?? undefined,
44
- metadata: parseJson(row.metadata),
45
- createdAt: new Date(row.createdAt),
46
- }))
47
- }
@@ -1,244 +0,0 @@
1
- import type {
2
- AgentThread,
3
- AgentMessage,
4
- AgentRunRow,
5
- AgentRunService,
6
- } from '@pikku/core/agent'
7
- import type { Kysely } from 'kysely'
8
- import { sql } from 'kysely'
9
- import type { KyselyPikkuDB } from './kysely-tables.js'
10
- import { parseJson } from './kysely-json.js'
11
-
12
- // Owner ids routinely contain `_` (e.g. `user_123`), which LIKE treats as a
13
- // single-character wildcard — so a raw prefix would match a foreign owner.
14
- const escapeLikePattern = (value: string) =>
15
- value.replace(/[\\%_]/g, (char) => `\\${char}`)
16
-
17
- export class KyselyAgentRunService implements AgentRunService {
18
- constructor(private db: Kysely<KyselyPikkuDB>) {}
19
-
20
- async listThreads(options?: {
21
- agentName?: string
22
- resourceId?: string
23
- owners?: string[]
24
- limit?: number
25
- offset?: number
26
- }): Promise<AgentThread[]> {
27
- const {
28
- agentName,
29
- resourceId,
30
- owners,
31
- limit = 50,
32
- offset = 0,
33
- } = options ?? {}
34
-
35
- // An owners constraint is an authorization boundary, so an empty list must
36
- // match nothing rather than degrade to "no filter".
37
- if (owners && owners.length === 0) return []
38
-
39
- let query = this.db
40
- .selectFrom('agentThreads as t')
41
- .select([
42
- 't.id',
43
- 't.resourceId',
44
- 't.title',
45
- 't.metadata',
46
- 't.createdAt',
47
- 't.updatedAt',
48
- ])
49
-
50
- if (agentName) {
51
- query = query.where(
52
- 't.id',
53
- 'in',
54
- this.db
55
- .selectFrom('agentRun')
56
- .select('threadId')
57
- .where('agentName', '=', agentName)
58
- .distinct()
59
- )
60
- }
61
-
62
- if (resourceId) {
63
- query = query.where('t.resourceId', '=', resourceId)
64
- }
65
-
66
- if (owners) {
67
- query = query.where((eb) =>
68
- eb.or(
69
- owners.flatMap((owner) => [
70
- eb('t.resourceId', '=', owner),
71
- eb(
72
- 't.resourceId',
73
- 'like',
74
- sql<string>`${`${escapeLikePattern(owner)}:%`} escape '\\'`
75
- ),
76
- ])
77
- )
78
- )
79
- }
80
-
81
- const result = await query
82
- .orderBy('t.updatedAt', 'desc')
83
- .limit(limit)
84
- .offset(offset)
85
- .execute()
86
-
87
- return result.map((row) => this.mapThreadRow(row))
88
- }
89
-
90
- async getThread(threadId: string): Promise<AgentThread | null> {
91
- const row = await this.db
92
- .selectFrom('agentThreads')
93
- .select([
94
- 'id',
95
- 'resourceId',
96
- 'title',
97
- 'metadata',
98
- 'createdAt',
99
- 'updatedAt',
100
- ])
101
- .where('id', '=', threadId)
102
- .executeTakeFirst()
103
-
104
- if (!row) return null
105
- return this.mapThreadRow(row)
106
- }
107
-
108
- async getThreadMessages(threadId: string): Promise<AgentMessage[]> {
109
- const [msgResult, tcResult] = await Promise.all([
110
- this.db
111
- .selectFrom('agentMessage')
112
- .select(['id', 'role', 'content', 'createdAt'])
113
- .where('threadId', '=', threadId)
114
- .orderBy('createdAt', 'asc')
115
- .execute(),
116
- this.db
117
- .selectFrom('agentToolCall')
118
- .select(['id', 'messageId', 'toolName', 'args', 'result'])
119
- .where('threadId', '=', threadId)
120
- .orderBy('createdAt', 'asc')
121
- .execute(),
122
- ])
123
-
124
- const tcByMessage = new Map<string, (typeof tcResult)[number][]>()
125
- for (const tc of tcResult) {
126
- const msgId = tc.messageId
127
- if (!tcByMessage.has(msgId)) tcByMessage.set(msgId, [])
128
- tcByMessage.get(msgId)!.push(tc)
129
- }
130
-
131
- const messages: AgentMessage[] = []
132
- for (const row of msgResult) {
133
- const msg: AgentMessage = {
134
- id: row.id,
135
- role: row.role as AgentMessage['role'],
136
- content: row.content ?? undefined,
137
- createdAt: new Date(row.createdAt as unknown as string),
138
- }
139
-
140
- const tcs = tcByMessage.get(msg.id)
141
- if (tcs?.length) {
142
- msg.toolCalls = tcs.map((tc) => ({
143
- id: tc.id,
144
- name: tc.toolName,
145
- args: parseJson(tc.args) as Record<string, unknown>,
146
- }))
147
-
148
- const completed = tcs.filter((tc) => tc.result != null)
149
- if (completed.length) {
150
- messages.push(msg)
151
- messages.push({
152
- id: `tool-results-${msg.id}`,
153
- role: 'tool',
154
- toolResults: completed.map((tc) => ({
155
- id: tc.id,
156
- name: tc.toolName,
157
- result: tc.result!,
158
- })),
159
- createdAt: msg.createdAt,
160
- })
161
- continue
162
- }
163
- }
164
-
165
- messages.push(msg)
166
- }
167
-
168
- return messages
169
- }
170
-
171
- async getThreadRuns(threadId: string): Promise<AgentRunRow[]> {
172
- const result = await this.db
173
- .selectFrom('agentRun')
174
- .select([
175
- 'runId',
176
- 'agentName',
177
- 'threadId',
178
- 'resourceId',
179
- 'status',
180
- 'errorMessage',
181
- 'suspendReason',
182
- 'missingRpcs',
183
- 'usageInputTokens',
184
- 'usageOutputTokens',
185
- 'usageModel',
186
- 'createdAt',
187
- 'updatedAt',
188
- ])
189
- .where('threadId', '=', threadId)
190
- .orderBy('createdAt', 'desc')
191
- .execute()
192
-
193
- return result.map((row) => this.mapRunRow(row))
194
- }
195
-
196
- async deleteThread(threadId: string): Promise<boolean> {
197
- const result = await this.db
198
- .deleteFrom('agentThreads')
199
- .where('id', '=', threadId)
200
- .executeTakeFirst()
201
-
202
- return BigInt(result.numDeletedRows) > 0n
203
- }
204
-
205
- async getDistinctAgentNames(): Promise<string[]> {
206
- const result = await this.db
207
- .selectFrom('agentRun')
208
- .select('agentName')
209
- .distinct()
210
- .orderBy('agentName')
211
- .execute()
212
-
213
- return result.map((row) => row.agentName)
214
- }
215
-
216
- private mapThreadRow(row: any): AgentThread {
217
- return {
218
- id: row.id as string,
219
- resourceId: row.resourceId as string,
220
- title: (row.title as string) ?? undefined,
221
- metadata: parseJson(row.metadata),
222
- createdAt: new Date(row.createdAt as string),
223
- updatedAt: new Date(row.updatedAt as string),
224
- }
225
- }
226
-
227
- private mapRunRow(row: any): AgentRunRow {
228
- return {
229
- runId: row.runId as string,
230
- agentName: row.agentName as string,
231
- threadId: row.threadId as string,
232
- resourceId: row.resourceId as string,
233
- status: row.status as string,
234
- errorMessage: (row.errorMessage as string) ?? undefined,
235
- suspendReason: (row.suspendReason as string) ?? undefined,
236
- missingRpcs: parseJson(row.missingRpcs),
237
- usageInputTokens: Number(row.usageInputTokens),
238
- usageOutputTokens: Number(row.usageOutputTokens),
239
- usageModel: row.usageModel as string,
240
- createdAt: new Date(row.createdAt as string),
241
- updatedAt: new Date(row.updatedAt as string),
242
- }
243
- }
244
- }