@sixb/sqlite 0.1.1 → 0.1.3
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/README.md +18 -13
- package/dist/action-run-storage.d.ts +5 -2
- package/dist/action-run-storage.d.ts.map +1 -1
- package/dist/agents/agent-storage.d.ts +9 -5
- package/dist/agents/agent-storage.d.ts.map +1 -1
- package/dist/agents/checkpoints.d.ts +14 -0
- package/dist/agents/checkpoints.d.ts.map +1 -0
- package/dist/agents/index.d.ts +1 -0
- package/dist/agents/index.d.ts.map +1 -1
- package/dist/agents/messages.d.ts +2 -1
- package/dist/agents/messages.d.ts.map +1 -1
- package/dist/agents/rows.d.ts +21 -11
- package/dist/agents/rows.d.ts.map +1 -1
- package/dist/agents/runs.d.ts +3 -2
- package/dist/agents/runs.d.ts.map +1 -1
- package/dist/ai-cost-storage.d.ts +15 -0
- package/dist/ai-cost-storage.d.ts.map +1 -0
- package/dist/ai-usage-storage.d.ts +22 -0
- package/dist/ai-usage-storage.d.ts.map +1 -0
- package/dist/auth-storage/service-accounts.d.ts.map +1 -1
- package/dist/auth-storage/shared.d.ts +1 -10
- package/dist/auth-storage/shared.d.ts.map +1 -1
- package/dist/connector-connection-storage.d.ts +9 -0
- package/dist/connector-connection-storage.d.ts.map +1 -0
- package/dist/execution-storage.d.ts +14 -0
- package/dist/execution-storage.d.ts.map +1 -0
- package/dist/index.d.ts +14 -9
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4633 -1066
- package/dist/index.js.map +33 -28
- package/dist/latest-run-query.d.ts.map +1 -1
- package/dist/migrations.d.ts +0 -1
- package/dist/migrations.d.ts.map +1 -1
- package/dist/ontology-storage/materialization-session.d.ts +50 -8
- package/dist/ontology-storage/materialization-session.d.ts.map +1 -1
- package/dist/ontology-storage/materialization-state.d.ts +4 -5
- package/dist/ontology-storage/materialization-state.d.ts.map +1 -1
- package/dist/ontology-storage/materialization-writer.d.ts.map +1 -1
- package/dist/ontology-storage/materializations.d.ts +0 -2
- package/dist/ontology-storage/materializations.d.ts.map +1 -1
- package/dist/ontology-storage/outbox.d.ts.map +1 -1
- package/dist/ontology-storage/shared.d.ts +3 -3
- package/dist/ontology-storage/shared.d.ts.map +1 -1
- package/dist/ontology-storage/sources.d.ts.map +1 -1
- package/dist/pipeline-run-storage.d.ts +7 -2
- package/dist/pipeline-run-storage.d.ts.map +1 -1
- package/dist/projection-run-storage.d.ts +9 -2
- package/dist/projection-run-storage.d.ts.map +1 -1
- package/dist/run-list-query.d.ts +1 -1
- package/dist/run-list-query.d.ts.map +1 -1
- package/dist/sync-run-storage.d.ts +7 -2
- package/dist/sync-run-storage.d.ts.map +1 -1
- package/dist/testing.d.ts +6 -0
- package/dist/testing.d.ts.map +1 -0
- package/dist/transactions.d.ts +3 -0
- package/dist/transactions.d.ts.map +1 -1
- package/dist/webhook-run-storage.d.ts +9 -2
- package/dist/webhook-run-storage.d.ts.map +1 -1
- package/dist/workflow-run-storage.d.ts +7 -3
- package/dist/workflow-run-storage.d.ts.map +1 -1
- package/package.json +3 -3
- package/src/action-run-storage.ts +51 -74
- package/src/agents/agent-storage.ts +11 -6
- package/src/agents/checkpoints.ts +175 -0
- package/src/agents/index.ts +1 -0
- package/src/agents/messages.ts +59 -0
- package/src/agents/rows.ts +52 -40
- package/src/agents/runs.ts +27 -21
- package/src/ai-cost-storage.ts +744 -0
- package/src/ai-usage-storage.ts +324 -0
- package/src/auth-storage/service-accounts.ts +14 -21
- package/src/auth-storage/shared.ts +0 -22
- package/src/connector-connection-storage.ts +784 -0
- package/src/execution-storage.ts +158 -0
- package/src/index.ts +69 -22
- package/src/latest-run-query.ts +7 -1
- package/src/migrations/004-executions.sql +142 -0
- package/src/migrations/005-workflow-executions.sql +7 -0
- package/src/migrations/006-narrow-ontology-source-root-index.sql +4 -0
- package/src/migrations/007-split-overrides.sql +154 -0
- package/src/migrations/008-action-executions.sql +4 -0
- package/src/migrations/009-agent-executions.sql +115 -0
- package/src/migrations/010-ai-usage-accounting-foundation.sql +74 -0
- package/src/migrations/011-sync-failure-record.sql +22 -0
- package/src/migrations/012-pipeline-failure-record.sql +45 -0
- package/src/migrations/013-workflow-failure-record.sql +45 -0
- package/src/migrations/014-agent-failure-record.sql +59 -0
- package/src/migrations/015-projection-failure-record.sql +20 -0
- package/src/migrations/016-webhook-run-failure-record.sql +19 -0
- package/src/migrations/017-action-failure-record.sql +65 -0
- package/src/migrations/018-ontology-outbox-failure-record.sql +80 -0
- package/src/migrations/019-webhook-delivery-failure-record.sql +62 -0
- package/src/migrations/020-drop-run-usage-projections.sql +7 -0
- package/src/migrations/021-sync-pipeline-executions.sql +101 -0
- package/src/migrations/022-projection-executions.sql +244 -0
- package/src/migrations/023-webhook-executions.sql +51 -0
- package/src/migrations/024-ontology-commit-executions.sql +58 -0
- package/src/migrations/025-connector-connections.sql +257 -0
- package/src/migrations/026-ai-cost-accounting.sql +57 -0
- package/src/migrations/027-agent-context-checkpoints.sql +28 -0
- package/src/migrations/028-object-override-edit-times.sql +3 -0
- package/src/migrations.ts +129 -4
- package/src/ontology-storage/materialization-session.ts +317 -143
- package/src/ontology-storage/materialization-state.ts +323 -112
- package/src/ontology-storage/materialization-writer.ts +145 -67
- package/src/ontology-storage/materializations.ts +67 -141
- package/src/ontology-storage/outbox.ts +10 -3
- package/src/ontology-storage/shared.ts +10 -4
- package/src/ontology-storage/sources.ts +4 -1
- package/src/pipeline-run-storage.ts +128 -43
- package/src/projection-run-storage.ts +209 -97
- package/src/run-list-query.ts +9 -4
- package/src/sync-run-storage.ts +118 -32
- package/src/testing.ts +20 -0
- package/src/transactions.ts +10 -3
- package/src/webhook-run-storage.ts +118 -74
- package/src/workflow-run-storage.ts +117 -131
- package/dist/validation.d.ts +0 -5
- package/dist/validation.d.ts.map +0 -1
- package/dist/webhook-delivery-storage.d.ts +0 -27
- package/dist/webhook-delivery-storage.d.ts.map +0 -1
- package/src/validation.ts +0 -30
- package/src/webhook-delivery-storage.ts +0 -272
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
import type { Database } from "bun:sqlite"
|
|
2
2
|
import type { ActionSubject, JsonValue } from "@sixb/core"
|
|
3
|
+
import {
|
|
4
|
+
parseActionRunFailure,
|
|
5
|
+
serializeActionRunFailure,
|
|
6
|
+
} from "@sixb/core/internal/action-run-storage"
|
|
7
|
+
import { assertActionRunExecution } from "@sixb/core/internal/action-run-storage-provider"
|
|
3
8
|
import type {
|
|
4
9
|
ActionRunEffectsRecord,
|
|
5
10
|
ActionRunFailure,
|
|
@@ -9,6 +14,7 @@ import type {
|
|
|
9
14
|
ActionRunStorage,
|
|
10
15
|
ActionRunWritebackRecord,
|
|
11
16
|
EnterActionRunPhaseInput,
|
|
17
|
+
ExecutionStorage,
|
|
12
18
|
FinishActionRunInput,
|
|
13
19
|
ListActionRunsInput,
|
|
14
20
|
ListActionRunsResult,
|
|
@@ -33,6 +39,8 @@ import {
|
|
|
33
39
|
} from "./transactions"
|
|
34
40
|
|
|
35
41
|
export interface SqliteActionRunStorageOptions {
|
|
42
|
+
/** Execution lookup sharing the same provider transaction. */
|
|
43
|
+
executions: ExecutionStorage
|
|
36
44
|
/** Path to SQLite database file. Defaults to ':memory:' for in-memory database. */
|
|
37
45
|
path?: string
|
|
38
46
|
/** Internal shared connection used by bundled SqliteStorage. */
|
|
@@ -43,9 +51,12 @@ export class SqliteActionRunStorage implements ActionRunStorage {
|
|
|
43
51
|
private readonly connection: SqliteStoreConnection
|
|
44
52
|
private readonly db: Database
|
|
45
53
|
|
|
46
|
-
|
|
54
|
+
private readonly executions: ExecutionStorage
|
|
55
|
+
|
|
56
|
+
constructor(options: SqliteActionRunStorageOptions) {
|
|
47
57
|
this.connection = openSqliteStoreConnection(options)
|
|
48
58
|
this.db = this.connection.db
|
|
59
|
+
this.executions = options.executions
|
|
49
60
|
|
|
50
61
|
if (this.connection.installFreshSchema) {
|
|
51
62
|
installFreshSqliteSchema(this.db)
|
|
@@ -85,6 +96,13 @@ export class SqliteActionRunStorage implements ActionRunStorage {
|
|
|
85
96
|
|
|
86
97
|
async queue(input: QueueActionRunInput): Promise<ActionRunRecord> {
|
|
87
98
|
const queuedAt = input.queuedAt ?? new Date()
|
|
99
|
+
await assertActionRunExecution({
|
|
100
|
+
executions: this.executions,
|
|
101
|
+
projectId: input.projectId,
|
|
102
|
+
executionId: input.executionId,
|
|
103
|
+
runId: input.id,
|
|
104
|
+
actionId: input.actionId,
|
|
105
|
+
})
|
|
88
106
|
|
|
89
107
|
try {
|
|
90
108
|
this.db
|
|
@@ -93,6 +111,7 @@ export class SqliteActionRunStorage implements ActionRunStorage {
|
|
|
93
111
|
INSERT INTO action_runs (
|
|
94
112
|
project_id,
|
|
95
113
|
id,
|
|
114
|
+
execution_id,
|
|
96
115
|
action_id,
|
|
97
116
|
subject_kind,
|
|
98
117
|
object_type_id,
|
|
@@ -107,28 +126,23 @@ export class SqliteActionRunStorage implements ActionRunStorage {
|
|
|
107
126
|
writeback_status,
|
|
108
127
|
writeback_completed_at,
|
|
109
128
|
writeback_result,
|
|
110
|
-
|
|
111
|
-
writeback_error_message,
|
|
112
|
-
writeback_error_phase,
|
|
129
|
+
writeback_error,
|
|
113
130
|
effects_status,
|
|
114
131
|
effects_completed_at,
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
effects_error_phase,
|
|
118
|
-
error_name,
|
|
119
|
-
error_message,
|
|
120
|
-
error_phase
|
|
132
|
+
effects_error,
|
|
133
|
+
error
|
|
121
134
|
) VALUES (
|
|
122
|
-
?, ?, ?, ?, ?, ?, ?, ?, ?, NULL, NULL, ?, ?,
|
|
123
|
-
NULL, NULL, NULL, NULL,
|
|
124
|
-
NULL, NULL, NULL,
|
|
125
|
-
NULL
|
|
135
|
+
?, ?, ?, ?, ?, ?, ?, ?, ?, ?, NULL, NULL, ?, ?,
|
|
136
|
+
NULL, NULL, NULL, NULL,
|
|
137
|
+
NULL, NULL, NULL,
|
|
138
|
+
NULL
|
|
126
139
|
)
|
|
127
140
|
`
|
|
128
141
|
)
|
|
129
142
|
.run(
|
|
130
143
|
input.projectId,
|
|
131
144
|
input.id,
|
|
145
|
+
input.executionId,
|
|
132
146
|
input.actionId,
|
|
133
147
|
input.subject.kind,
|
|
134
148
|
input.subject.kind === "object" ? input.subject.objectTypeId : null,
|
|
@@ -188,17 +202,11 @@ export class SqliteActionRunStorage implements ActionRunStorage {
|
|
|
188
202
|
writeback_status = NULL,
|
|
189
203
|
writeback_completed_at = NULL,
|
|
190
204
|
writeback_result = NULL,
|
|
191
|
-
|
|
192
|
-
writeback_error_message = NULL,
|
|
193
|
-
writeback_error_phase = NULL,
|
|
205
|
+
writeback_error = NULL,
|
|
194
206
|
effects_status = NULL,
|
|
195
207
|
effects_completed_at = NULL,
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
effects_error_phase = NULL,
|
|
199
|
-
error_name = NULL,
|
|
200
|
-
error_message = NULL,
|
|
201
|
-
error_phase = NULL
|
|
208
|
+
effects_error = NULL,
|
|
209
|
+
error = NULL
|
|
202
210
|
WHERE project_id = ? AND id = ?
|
|
203
211
|
`
|
|
204
212
|
)
|
|
@@ -238,9 +246,7 @@ export class SqliteActionRunStorage implements ActionRunStorage {
|
|
|
238
246
|
status = ?,
|
|
239
247
|
phase = ?,
|
|
240
248
|
started_at = ?,
|
|
241
|
-
|
|
242
|
-
error_message = NULL,
|
|
243
|
-
error_phase = NULL
|
|
249
|
+
error = NULL
|
|
244
250
|
WHERE project_id = ? AND id = ?
|
|
245
251
|
`
|
|
246
252
|
)
|
|
@@ -307,9 +313,7 @@ export class SqliteActionRunStorage implements ActionRunStorage {
|
|
|
307
313
|
writeback_status = ?,
|
|
308
314
|
writeback_completed_at = ?,
|
|
309
315
|
writeback_result = ?,
|
|
310
|
-
|
|
311
|
-
writeback_error_message = ?,
|
|
312
|
-
writeback_error_phase = ?
|
|
316
|
+
writeback_error = ?
|
|
313
317
|
WHERE project_id = ? AND id = ?
|
|
314
318
|
`
|
|
315
319
|
)
|
|
@@ -318,9 +322,7 @@ export class SqliteActionRunStorage implements ActionRunStorage {
|
|
|
318
322
|
input.status,
|
|
319
323
|
nextWriteback.completedAt.toISOString(),
|
|
320
324
|
input.status === "succeeded" ? serializeJsonValue(input.result) : null,
|
|
321
|
-
input.status === "failed" ? (input.error
|
|
322
|
-
input.status === "failed" ? input.error.message : null,
|
|
323
|
-
input.status === "failed" ? (input.error.phase ?? "writeback") : null,
|
|
325
|
+
input.status === "failed" ? serializeActionRunFailure(input.error, "writeback") : null,
|
|
324
326
|
input.projectId,
|
|
325
327
|
input.id
|
|
326
328
|
)
|
|
@@ -357,9 +359,7 @@ export class SqliteActionRunStorage implements ActionRunStorage {
|
|
|
357
359
|
phase = ?,
|
|
358
360
|
effects_status = ?,
|
|
359
361
|
effects_completed_at = ?,
|
|
360
|
-
|
|
361
|
-
effects_error_message = ?,
|
|
362
|
-
effects_error_phase = ?
|
|
362
|
+
effects_error = ?
|
|
363
363
|
WHERE project_id = ? AND id = ?
|
|
364
364
|
`
|
|
365
365
|
)
|
|
@@ -367,9 +367,7 @@ export class SqliteActionRunStorage implements ActionRunStorage {
|
|
|
367
367
|
"effects",
|
|
368
368
|
input.status,
|
|
369
369
|
nextEffects.completedAt.toISOString(),
|
|
370
|
-
input.status === "failed" ? (input.error
|
|
371
|
-
input.status === "failed" ? input.error.message : null,
|
|
372
|
-
input.status === "failed" ? (input.error.phase ?? "effects") : null,
|
|
370
|
+
input.status === "failed" ? serializeActionRunFailure(input.error, "effects") : null,
|
|
373
371
|
input.projectId,
|
|
374
372
|
input.id
|
|
375
373
|
)
|
|
@@ -410,9 +408,7 @@ export class SqliteActionRunStorage implements ActionRunStorage {
|
|
|
410
408
|
status = ?,
|
|
411
409
|
phase = ?,
|
|
412
410
|
finished_at = ?,
|
|
413
|
-
|
|
414
|
-
error_message = ?,
|
|
415
|
-
error_phase = ?
|
|
411
|
+
error = ?
|
|
416
412
|
WHERE project_id = ? AND id = ?
|
|
417
413
|
`
|
|
418
414
|
)
|
|
@@ -420,9 +416,7 @@ export class SqliteActionRunStorage implements ActionRunStorage {
|
|
|
420
416
|
input.status,
|
|
421
417
|
phase,
|
|
422
418
|
(input.finishedAt ?? new Date()).toISOString(),
|
|
423
|
-
input.status === "succeeded" ? null : (input.error
|
|
424
|
-
input.status === "succeeded" ? null : (input.error?.message ?? null),
|
|
425
|
-
input.status === "succeeded" ? null : (input.error?.phase ?? phase),
|
|
419
|
+
input.status === "succeeded" ? null : serializeActionRunFailure(input.error),
|
|
426
420
|
input.projectId,
|
|
427
421
|
input.id
|
|
428
422
|
)
|
|
@@ -583,23 +577,14 @@ function serializeJsonValue(value: JsonValue): string {
|
|
|
583
577
|
}
|
|
584
578
|
|
|
585
579
|
function toActionRunFailure(row: DatabaseRow): ActionRunFailure | undefined {
|
|
586
|
-
return
|
|
580
|
+
return row.error === null ? undefined : parseActionRunFailure(row.error)
|
|
587
581
|
}
|
|
588
582
|
|
|
589
|
-
function
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
if (!message) {
|
|
595
|
-
return undefined
|
|
596
|
-
}
|
|
597
|
-
|
|
598
|
-
return {
|
|
599
|
-
name: name ?? undefined,
|
|
600
|
-
message,
|
|
601
|
-
phase: phase ?? undefined,
|
|
602
|
-
}
|
|
583
|
+
function parsePhaseFailure<TPhase extends Extract<ActionRunPhase, "writeback" | "effects">>(
|
|
584
|
+
value: string | null,
|
|
585
|
+
expectedPhase: TPhase
|
|
586
|
+
): ActionRunFailure<TPhase> {
|
|
587
|
+
return parseActionRunFailure(value, expectedPhase)
|
|
603
588
|
}
|
|
604
589
|
|
|
605
590
|
function toActionRunWritebackRecord(row: DatabaseRow): ActionRunWritebackRecord | undefined {
|
|
@@ -623,11 +608,7 @@ function toActionRunWritebackRecord(row: DatabaseRow): ActionRunWritebackRecord
|
|
|
623
608
|
return {
|
|
624
609
|
status: "failed",
|
|
625
610
|
completedAt,
|
|
626
|
-
error:
|
|
627
|
-
row.writeback_error_name,
|
|
628
|
-
row.writeback_error_message,
|
|
629
|
-
row.writeback_error_phase
|
|
630
|
-
),
|
|
611
|
+
error: parsePhaseFailure(row.writeback_error, "writeback"),
|
|
631
612
|
}
|
|
632
613
|
}
|
|
633
614
|
|
|
@@ -650,7 +631,7 @@ function toActionRunEffectsRecord(row: DatabaseRow): ActionRunEffectsRecord | un
|
|
|
650
631
|
return {
|
|
651
632
|
status: "failed",
|
|
652
633
|
completedAt,
|
|
653
|
-
error:
|
|
634
|
+
error: parsePhaseFailure(row.effects_error, "effects"),
|
|
654
635
|
}
|
|
655
636
|
}
|
|
656
637
|
|
|
@@ -695,6 +676,7 @@ function rowToActionRunRecord(row: DatabaseRow): ActionRunRecord {
|
|
|
695
676
|
return {
|
|
696
677
|
id: row.id,
|
|
697
678
|
projectId: row.project_id,
|
|
679
|
+
executionId: row.execution_id,
|
|
698
680
|
actionId: row.action_id,
|
|
699
681
|
subject: rowToActionSubject(row),
|
|
700
682
|
status: row.status,
|
|
@@ -733,6 +715,7 @@ function isUniqueConstraintError(error: unknown): boolean {
|
|
|
733
715
|
interface DatabaseRow {
|
|
734
716
|
project_id: string
|
|
735
717
|
id: string
|
|
718
|
+
execution_id: string
|
|
736
719
|
action_id: string
|
|
737
720
|
subject_kind: ActionSubject["kind"]
|
|
738
721
|
object_type_id: string | null
|
|
@@ -747,15 +730,9 @@ interface DatabaseRow {
|
|
|
747
730
|
writeback_status: ActionRunWritebackRecord["status"] | null
|
|
748
731
|
writeback_completed_at: string | null
|
|
749
732
|
writeback_result: string | null
|
|
750
|
-
|
|
751
|
-
writeback_error_message: string | null
|
|
752
|
-
writeback_error_phase: ActionRunPhase | null
|
|
733
|
+
writeback_error: string | null
|
|
753
734
|
effects_status: ActionRunEffectsRecord["status"] | null
|
|
754
735
|
effects_completed_at: string | null
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
effects_error_phase: ActionRunPhase | null
|
|
758
|
-
error_name: string | null
|
|
759
|
-
error_message: string | null
|
|
760
|
-
error_phase: ActionRunPhase | null
|
|
736
|
+
effects_error: string | null
|
|
737
|
+
error: string | null
|
|
761
738
|
}
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import type { AgentStorage } from "@sixb/core/storage"
|
|
1
|
+
import type { AgentStorage, ExecutionStorage } from "@sixb/core/storage"
|
|
2
2
|
import { installFreshSqliteSchema } from "../migrations"
|
|
3
3
|
import {
|
|
4
4
|
closeSqliteStoreConnection,
|
|
5
5
|
openSqliteStoreConnection,
|
|
6
6
|
type SqliteStoreConnection,
|
|
7
7
|
} from "../transactions"
|
|
8
|
+
import { SqliteAgentContextCheckpointStore } from "./checkpoints"
|
|
8
9
|
import { SqliteAgentMessageStore } from "./messages"
|
|
9
10
|
import { SqliteAgentRunStore } from "./runs"
|
|
10
11
|
import { SqliteAgentThreadStore } from "./threads"
|
|
@@ -14,21 +15,24 @@ export interface SqliteAgentStorageOptions {
|
|
|
14
15
|
path?: string
|
|
15
16
|
/** Internal shared connection used by bundled SqliteStorage. */
|
|
16
17
|
connection?: SqliteStoreConnection
|
|
18
|
+
/** Execution ledger used to validate immutable run ownership. */
|
|
19
|
+
executions: ExecutionStorage
|
|
17
20
|
}
|
|
18
21
|
|
|
19
22
|
/**
|
|
20
|
-
* SQLite-backed agent persistence: thread
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
+
* SQLite-backed agent persistence: thread, run, message, and context-checkpoint sub-stores sharing
|
|
24
|
+
* one connection. Cross-table writes run in SQLite transactions; the bundled {@link SqliteStorage}
|
|
25
|
+
* serializes them for single-flight and checkpoint compare-and-swap safety.
|
|
23
26
|
*/
|
|
24
27
|
export class SqliteAgentStorage implements AgentStorage {
|
|
25
28
|
readonly threads: SqliteAgentThreadStore
|
|
26
29
|
readonly runs: SqliteAgentRunStore
|
|
27
30
|
readonly messages: SqliteAgentMessageStore
|
|
31
|
+
readonly checkpoints: SqliteAgentContextCheckpointStore
|
|
28
32
|
|
|
29
33
|
private readonly connection: SqliteStoreConnection
|
|
30
34
|
|
|
31
|
-
constructor(options: SqliteAgentStorageOptions
|
|
35
|
+
constructor(options: SqliteAgentStorageOptions) {
|
|
32
36
|
this.connection = openSqliteStoreConnection(options)
|
|
33
37
|
|
|
34
38
|
if (this.connection.installFreshSchema) {
|
|
@@ -36,8 +40,9 @@ export class SqliteAgentStorage implements AgentStorage {
|
|
|
36
40
|
}
|
|
37
41
|
|
|
38
42
|
this.threads = new SqliteAgentThreadStore(this.connection.db)
|
|
39
|
-
this.runs = new SqliteAgentRunStore(this.connection.db)
|
|
43
|
+
this.runs = new SqliteAgentRunStore(this.connection.db, options.executions)
|
|
40
44
|
this.messages = new SqliteAgentMessageStore(this.connection.db)
|
|
45
|
+
this.checkpoints = new SqliteAgentContextCheckpointStore(this.connection.db)
|
|
41
46
|
}
|
|
42
47
|
|
|
43
48
|
close(): void {
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
import type { Database } from "bun:sqlite"
|
|
2
|
+
import {
|
|
3
|
+
agentContextCheckpointMatchesCreateInput,
|
|
4
|
+
assertAgentContextCheckpointAnchors,
|
|
5
|
+
assertAgentContextCheckpointAuthority,
|
|
6
|
+
assertAgentContextCheckpointReplayState,
|
|
7
|
+
assertCreateAgentContextCheckpointInput,
|
|
8
|
+
} from "@sixb/core/internal/agent-run-storage-provider"
|
|
9
|
+
import {
|
|
10
|
+
type AgentContextCheckpointRecord,
|
|
11
|
+
type AgentContextCheckpointStore,
|
|
12
|
+
AgentStorageError,
|
|
13
|
+
type CreateAgentContextCheckpointInput,
|
|
14
|
+
} from "@sixb/core/storage"
|
|
15
|
+
import {
|
|
16
|
+
type AgentContextCheckpointRow,
|
|
17
|
+
type AgentMessageRow,
|
|
18
|
+
type AgentRunRow,
|
|
19
|
+
type AgentThreadRow,
|
|
20
|
+
rowToContextCheckpointRecord,
|
|
21
|
+
rowToMessageRecord,
|
|
22
|
+
rowToRunRecord,
|
|
23
|
+
rowToThreadRecord,
|
|
24
|
+
} from "./rows"
|
|
25
|
+
|
|
26
|
+
export class SqliteAgentContextCheckpointStore implements AgentContextCheckpointStore {
|
|
27
|
+
constructor(private readonly db: Database) {}
|
|
28
|
+
|
|
29
|
+
async create(input: CreateAgentContextCheckpointInput): Promise<AgentContextCheckpointRecord> {
|
|
30
|
+
assertCreateAgentContextCheckpointInput(input, "SixbSqlite")
|
|
31
|
+
|
|
32
|
+
return this.db.transaction(() => {
|
|
33
|
+
const runRow = this.db
|
|
34
|
+
.query("SELECT * FROM agent_runs WHERE project_id = ? AND id = ?")
|
|
35
|
+
.get(input.projectId, input.createdByRunId) as AgentRunRow | null
|
|
36
|
+
const threadRow = this.db
|
|
37
|
+
.query("SELECT * FROM agent_threads WHERE project_id = ? AND id = ?")
|
|
38
|
+
.get(input.projectId, input.threadId) as AgentThreadRow | null
|
|
39
|
+
assertAgentContextCheckpointAuthority({
|
|
40
|
+
create: input,
|
|
41
|
+
run: runRow ? rowToRunRecord(runRow) : null,
|
|
42
|
+
thread: threadRow ? rowToThreadRecord(threadRow) : null,
|
|
43
|
+
prefix: "SixbSqlite",
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
const latest = this.findLatest(input.projectId, input.threadId)
|
|
47
|
+
const headRow = this.db
|
|
48
|
+
.query(
|
|
49
|
+
"SELECT COALESCE(MAX(seq), 0) AS seq FROM agent_messages WHERE project_id = ? AND thread_id = ?"
|
|
50
|
+
)
|
|
51
|
+
.get(input.projectId, input.threadId) as { seq: number }
|
|
52
|
+
|
|
53
|
+
const existingForRun = this.db
|
|
54
|
+
.query(
|
|
55
|
+
"SELECT * FROM agent_context_checkpoints WHERE project_id = ? AND created_by_run_id = ?"
|
|
56
|
+
)
|
|
57
|
+
.get(input.projectId, input.createdByRunId) as AgentContextCheckpointRow | null
|
|
58
|
+
if (existingForRun) {
|
|
59
|
+
const record = rowToContextCheckpointRecord(existingForRun)
|
|
60
|
+
if (agentContextCheckpointMatchesCreateInput(record, input)) {
|
|
61
|
+
assertAgentContextCheckpointReplayState({
|
|
62
|
+
create: input,
|
|
63
|
+
existing: record,
|
|
64
|
+
latest,
|
|
65
|
+
headSeq: headRow.seq,
|
|
66
|
+
prefix: "SixbSqlite",
|
|
67
|
+
})
|
|
68
|
+
return record
|
|
69
|
+
}
|
|
70
|
+
throw new AgentStorageError(
|
|
71
|
+
"invalid_state",
|
|
72
|
+
`[SixbSqlite] Agent run '${input.createdByRunId}' already created a different context checkpoint.`
|
|
73
|
+
)
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const duplicateId = this.db
|
|
77
|
+
.query("SELECT 1 FROM agent_context_checkpoints WHERE project_id = ? AND id = ?")
|
|
78
|
+
.get(input.projectId, input.id)
|
|
79
|
+
if (duplicateId) {
|
|
80
|
+
throw new AgentStorageError(
|
|
81
|
+
"duplicate_id",
|
|
82
|
+
`[SixbSqlite] Agent context checkpoint '${input.id}' already exists for project '${input.projectId}'.`
|
|
83
|
+
)
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const firstRetainedRow = this.db
|
|
87
|
+
.query(
|
|
88
|
+
"SELECT * FROM agent_messages WHERE project_id = ? AND thread_id = ? AND seq > ? ORDER BY seq ASC LIMIT 1"
|
|
89
|
+
)
|
|
90
|
+
.get(input.projectId, input.threadId, input.summarizedThroughSeq) as AgentMessageRow | null
|
|
91
|
+
assertAgentContextCheckpointAnchors({
|
|
92
|
+
create: input,
|
|
93
|
+
latest,
|
|
94
|
+
headSeq: headRow.seq,
|
|
95
|
+
firstRetained: firstRetainedRow ? rowToMessageRecord(firstRetainedRow) : null,
|
|
96
|
+
prefix: "SixbSqlite",
|
|
97
|
+
})
|
|
98
|
+
|
|
99
|
+
const createdAt = input.createdAt ?? new Date()
|
|
100
|
+
this.db
|
|
101
|
+
.query(
|
|
102
|
+
`
|
|
103
|
+
INSERT INTO agent_context_checkpoints (
|
|
104
|
+
project_id,
|
|
105
|
+
id,
|
|
106
|
+
thread_id,
|
|
107
|
+
created_by_run_id,
|
|
108
|
+
previous_checkpoint_id,
|
|
109
|
+
reason,
|
|
110
|
+
summary,
|
|
111
|
+
summary_format_version,
|
|
112
|
+
summarized_through_seq,
|
|
113
|
+
observed_head_seq,
|
|
114
|
+
estimated_input_tokens_before,
|
|
115
|
+
estimated_input_tokens_after,
|
|
116
|
+
summary_model_id,
|
|
117
|
+
created_at
|
|
118
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
119
|
+
`
|
|
120
|
+
)
|
|
121
|
+
.run(
|
|
122
|
+
input.projectId,
|
|
123
|
+
input.id,
|
|
124
|
+
input.threadId,
|
|
125
|
+
input.createdByRunId,
|
|
126
|
+
input.expectedPreviousCheckpointId,
|
|
127
|
+
input.reason,
|
|
128
|
+
input.summary,
|
|
129
|
+
input.summaryFormatVersion,
|
|
130
|
+
input.summarizedThroughSeq,
|
|
131
|
+
input.observedHeadSeq,
|
|
132
|
+
input.estimatedInputTokensBefore,
|
|
133
|
+
input.estimatedInputTokensAfter,
|
|
134
|
+
input.summaryModelId,
|
|
135
|
+
createdAt.toISOString()
|
|
136
|
+
)
|
|
137
|
+
|
|
138
|
+
return this.requireById(input.projectId, input.id)
|
|
139
|
+
})()
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
async getLatest(input: {
|
|
143
|
+
readonly projectId: string
|
|
144
|
+
readonly threadId: string
|
|
145
|
+
}): Promise<AgentContextCheckpointRecord | null> {
|
|
146
|
+
return this.findLatest(input.projectId, input.threadId)
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
private findLatest(projectId: string, threadId: string): AgentContextCheckpointRecord | null {
|
|
150
|
+
const row = this.db
|
|
151
|
+
.query(
|
|
152
|
+
`
|
|
153
|
+
SELECT * FROM agent_context_checkpoints
|
|
154
|
+
WHERE project_id = ? AND thread_id = ?
|
|
155
|
+
ORDER BY summarized_through_seq DESC, created_at DESC, id DESC
|
|
156
|
+
LIMIT 1
|
|
157
|
+
`
|
|
158
|
+
)
|
|
159
|
+
.get(projectId, threadId) as AgentContextCheckpointRow | null
|
|
160
|
+
return row ? rowToContextCheckpointRecord(row) : null
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
private requireById(projectId: string, id: string): AgentContextCheckpointRecord {
|
|
164
|
+
const row = this.db
|
|
165
|
+
.query("SELECT * FROM agent_context_checkpoints WHERE project_id = ? AND id = ?")
|
|
166
|
+
.get(projectId, id) as AgentContextCheckpointRow | null
|
|
167
|
+
if (!row) {
|
|
168
|
+
throw new AgentStorageError(
|
|
169
|
+
"invalid_state",
|
|
170
|
+
`[SixbSqlite] Failed to load agent context checkpoint '${id}' for project '${projectId}'.`
|
|
171
|
+
)
|
|
172
|
+
}
|
|
173
|
+
return rowToContextCheckpointRecord(row)
|
|
174
|
+
}
|
|
175
|
+
}
|
package/src/agents/index.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export type { SqliteAgentStorageOptions } from "./agent-storage"
|
|
2
2
|
export { SqliteAgentStorage } from "./agent-storage"
|
|
3
|
+
export { SqliteAgentContextCheckpointStore } from "./checkpoints"
|
|
3
4
|
export { SqliteAgentMessageStore } from "./messages"
|
|
4
5
|
export { SqliteAgentRunStore } from "./runs"
|
|
5
6
|
export { SqliteAgentThreadStore } from "./threads"
|
package/src/agents/messages.ts
CHANGED
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
type AgentMessageStore,
|
|
6
6
|
AgentStorageError,
|
|
7
7
|
type AppendAgentMessageInput,
|
|
8
|
+
type DeleteAgentMessagesByRunInput,
|
|
8
9
|
type ListAgentMessagesInput,
|
|
9
10
|
type ListAgentMessagesResult,
|
|
10
11
|
} from "@sixb/core/storage"
|
|
@@ -110,6 +111,59 @@ export class SqliteAgentMessageStore implements AgentMessageStore {
|
|
|
110
111
|
})()
|
|
111
112
|
}
|
|
112
113
|
|
|
114
|
+
async deleteByRunId(input: DeleteAgentMessagesByRunInput): Promise<number> {
|
|
115
|
+
return this.db.transaction(() => {
|
|
116
|
+
const thread = this.db
|
|
117
|
+
.query("SELECT 1 AS present FROM agent_threads WHERE project_id = ? AND id = ?")
|
|
118
|
+
.get(input.projectId, input.threadId) as { present: number } | null
|
|
119
|
+
|
|
120
|
+
if (!thread) {
|
|
121
|
+
throw new AgentStorageError(
|
|
122
|
+
"thread_not_found",
|
|
123
|
+
`[SixbSqlite] Agent thread '${input.threadId}' not found for project '${input.projectId}'.`
|
|
124
|
+
)
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
const deleted = this.db
|
|
128
|
+
.query("DELETE FROM agent_messages WHERE project_id = ? AND thread_id = ? AND run_id = ?")
|
|
129
|
+
.run(input.projectId, input.threadId, input.runId)
|
|
130
|
+
if (deleted.changes === 0) {
|
|
131
|
+
return 0
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
const updatedAt = new Date().toISOString()
|
|
135
|
+
this.db
|
|
136
|
+
.query(
|
|
137
|
+
`
|
|
138
|
+
UPDATE agent_threads
|
|
139
|
+
SET
|
|
140
|
+
message_count = (
|
|
141
|
+
SELECT COUNT(*) FROM agent_messages WHERE project_id = ? AND thread_id = ?
|
|
142
|
+
),
|
|
143
|
+
last_message_at = (
|
|
144
|
+
SELECT created_at FROM agent_messages
|
|
145
|
+
WHERE project_id = ? AND thread_id = ?
|
|
146
|
+
ORDER BY seq DESC
|
|
147
|
+
LIMIT 1
|
|
148
|
+
),
|
|
149
|
+
updated_at = ?
|
|
150
|
+
WHERE project_id = ? AND id = ?
|
|
151
|
+
`
|
|
152
|
+
)
|
|
153
|
+
.run(
|
|
154
|
+
input.projectId,
|
|
155
|
+
input.threadId,
|
|
156
|
+
input.projectId,
|
|
157
|
+
input.threadId,
|
|
158
|
+
updatedAt,
|
|
159
|
+
input.projectId,
|
|
160
|
+
input.threadId
|
|
161
|
+
)
|
|
162
|
+
|
|
163
|
+
return deleted.changes
|
|
164
|
+
})()
|
|
165
|
+
}
|
|
166
|
+
|
|
113
167
|
async getById(params: { projectId: string; id: string }): Promise<AgentMessageRecord | null> {
|
|
114
168
|
const row = this.db
|
|
115
169
|
.query("SELECT * FROM agent_messages WHERE project_id = ? AND id = ?")
|
|
@@ -126,6 +180,11 @@ export class SqliteAgentMessageStore implements AgentMessageStore {
|
|
|
126
180
|
const whereClauses = ["project_id = ?", "thread_id = ?"]
|
|
127
181
|
const args: SqliteValue[] = [input.projectId, input.threadId]
|
|
128
182
|
|
|
183
|
+
if (input.afterSeq !== undefined) {
|
|
184
|
+
whereClauses.push("seq > ?")
|
|
185
|
+
args.push(input.afterSeq)
|
|
186
|
+
}
|
|
187
|
+
|
|
129
188
|
if (input.roles) {
|
|
130
189
|
whereClauses.push(`role IN (${input.roles.map(() => "?").join(", ")})`)
|
|
131
190
|
args.push(...input.roles)
|