@sixb/core 0.1.2 → 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/dist/actions/index.js +16 -13
- package/dist/actions/index.js.map +1 -1
- package/dist/agents/adapters.d.ts +11 -1
- package/dist/agents/adapters.d.ts.map +1 -1
- package/dist/agents/context.js +1 -1
- package/dist/agents/errors.d.ts +1 -1
- package/dist/agents/errors.d.ts.map +1 -1
- package/dist/agents/execution.d.ts +3 -0
- package/dist/agents/execution.d.ts.map +1 -1
- package/dist/agents/index.d.ts +6 -3
- package/dist/agents/index.d.ts.map +1 -1
- package/dist/agents/index.js +33 -22
- package/dist/agents/index.js.map +1 -1
- package/dist/agents/prompt.d.ts +8 -2
- package/dist/agents/prompt.d.ts.map +1 -1
- package/dist/agents/request.d.ts.map +1 -1
- package/dist/agents/streams.js +2 -2
- package/dist/agents/thread-context-projection.d.ts +19 -0
- package/dist/agents/thread-context-projection.d.ts.map +1 -0
- package/dist/agents/tool-definition.d.ts.map +1 -1
- package/dist/agents/tool-result.d.ts +6 -0
- package/dist/agents/tool-result.d.ts.map +1 -0
- package/dist/agents/types.d.ts +37 -1
- package/dist/agents/types.d.ts.map +1 -1
- package/dist/agents/validation.d.ts +1 -1
- package/dist/agents/validation.d.ts.map +1 -1
- package/dist/auth/index.js +7 -5
- package/dist/auth/index.js.map +1 -1
- package/dist/authorization/index.js +1 -1
- package/dist/bootstrap/index.js +27 -24
- package/dist/bootstrap/index.js.map +1 -1
- package/dist/{chunk-0mbx247x.js → chunk-177ed2mp.js} +241 -45
- package/dist/chunk-177ed2mp.js.map +46 -0
- package/dist/{chunk-sa4340y1.js → chunk-1ywq4hzk.js} +7 -7
- package/dist/{chunk-zg9yryhz.js → chunk-261ag4t4.js} +3 -3
- package/dist/{chunk-k9pts48t.js → chunk-3rsf30p4.js} +5 -5
- package/dist/{chunk-8ryen3p3.js → chunk-4aw0jwk0.js} +1 -1
- package/dist/{chunk-bh6k3nc6.js → chunk-4p9rh7jj.js} +1 -1
- package/dist/{chunk-34bqh420.js → chunk-4z3n1dzt.js} +59 -21
- package/dist/{chunk-34bqh420.js.map → chunk-4z3n1dzt.js.map} +4 -4
- package/dist/chunk-96swp2wd.js +47 -0
- package/dist/chunk-96swp2wd.js.map +10 -0
- package/dist/{chunk-n8herkry.js → chunk-bv41fmjn.js} +11 -11
- package/dist/{chunk-7pc8b818.js → chunk-c6cfqydk.js} +1 -1
- package/dist/{chunk-0k4avqr2.js → chunk-c8bw2b6c.js} +2 -2
- package/dist/{chunk-jaj13078.js → chunk-d2adj15j.js} +3 -33
- package/dist/{chunk-jaj13078.js.map → chunk-d2adj15j.js.map} +3 -4
- package/dist/{chunk-c6qd89g5.js → chunk-d6y2wsfg.js} +3 -3
- package/dist/chunk-dysw7nsm.js.map +1 -1
- package/dist/{chunk-st4xgxey.js → chunk-ettb0cy4.js} +150 -23
- package/dist/chunk-ettb0cy4.js.map +45 -0
- package/dist/{chunk-nnyp53zt.js → chunk-f1cyvnrk.js} +1 -1
- package/dist/chunk-fmx1sz2h.js.map +2 -2
- package/dist/{chunk-bct7hmfc.js → chunk-km4rkj4t.js} +3 -3
- package/dist/chunk-kqxgf6kv.js +898 -0
- package/dist/chunk-kqxgf6kv.js.map +15 -0
- package/dist/{chunk-qvybnnpe.js → chunk-n5x5y80a.js} +2 -2
- package/dist/{chunk-4x43bkbp.js → chunk-pxtrxm3p.js} +1 -1
- package/dist/chunk-qer6am8w.js +133 -0
- package/dist/chunk-qer6am8w.js.map +11 -0
- package/dist/{chunk-85j5ybfj.js → chunk-rdeagz6b.js} +2 -2
- package/dist/{chunk-85j5ybfj.js.map → chunk-rdeagz6b.js.map} +3 -3
- package/dist/chunk-rhrbz7d4.js +36 -0
- package/dist/chunk-rhrbz7d4.js.map +10 -0
- package/dist/{chunk-663csy96.js → chunk-t0jjkep3.js} +2 -1
- package/dist/chunk-t0jjkep3.js.map +10 -0
- package/dist/{chunk-5egfka8j.js → chunk-ttba8x6z.js} +2 -2
- package/dist/{chunk-nten49ta.js → chunk-wb4051cx.js} +3 -3
- package/dist/{chunk-nten49ta.js.map → chunk-wb4051cx.js.map} +1 -1
- package/dist/{chunk-57r1cpxx.js → chunk-xc7hq65b.js} +3 -2
- package/dist/{chunk-57r1cpxx.js.map → chunk-xc7hq65b.js.map} +3 -3
- package/dist/{chunk-ys1nse2v.js → chunk-xmggaxg4.js} +256 -231
- package/dist/{chunk-ys1nse2v.js.map → chunk-xmggaxg4.js.map} +8 -10
- package/dist/{chunk-g9t3kdtx.js → chunk-z8j83gzd.js} +1 -1
- package/dist/{chunk-57zpb99z.js → chunk-zpw39qhj.js} +1 -1
- package/dist/execution/agent.js +23 -20
- package/dist/execution/agent.js.map +1 -1
- package/dist/execution/primitive.js +23 -20
- package/dist/execution/primitive.js.map +2 -2
- package/dist/execution/request.js +24 -21
- package/dist/execution/request.js.map +2 -2
- package/dist/index.d.ts +3 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +32 -29
- package/dist/index.js.map +1 -1
- package/dist/materialization/model.d.ts +4 -0
- package/dist/materialization/model.d.ts.map +1 -1
- package/dist/materializer/edits/apply.d.ts +6 -1
- package/dist/materializer/edits/apply.d.ts.map +1 -1
- package/dist/materializer/edits/working-state.d.ts +2 -0
- package/dist/materializer/edits/working-state.d.ts.map +1 -1
- package/dist/materializer/effective/resolve.d.ts +3 -1
- package/dist/materializer/effective/resolve.d.ts.map +1 -1
- package/dist/materializer/execution/work-records.d.ts.map +1 -1
- package/dist/materializer/index.js +14 -11
- package/dist/materializer/index.js.map +1 -1
- package/dist/materializer/projections/replacement-plan.d.ts.map +1 -1
- package/dist/materializer/shared/normalize.d.ts.map +1 -1
- package/dist/objects/index.js +17 -14
- package/dist/objects/index.js.map +1 -1
- package/dist/objects/query/index.js +2 -2
- package/dist/pipelines/index.js +14 -12
- package/dist/pipelines/index.js.map +1 -1
- package/dist/projections/builders.d.ts +19 -6
- package/dist/projections/builders.d.ts.map +1 -1
- package/dist/projections/index.d.ts +2 -1
- package/dist/projections/index.d.ts.map +1 -1
- package/dist/projections/internal.d.ts +4 -1
- package/dist/projections/internal.d.ts.map +1 -1
- package/dist/projections/internal.js +17 -11
- package/dist/projections/internal.js.map +1 -1
- package/dist/projections/timestamp.d.ts +3 -0
- package/dist/projections/timestamp.d.ts.map +1 -0
- package/dist/projections/types.d.ts +9 -0
- package/dist/projections/types.d.ts.map +1 -1
- package/dist/projections/validation.d.ts.map +1 -1
- package/dist/queues/index.d.ts +1 -1
- package/dist/queues/index.d.ts.map +1 -1
- package/dist/queues/types.d.ts +7 -0
- package/dist/queues/types.d.ts.map +1 -1
- package/dist/runtime/ai-cost.d.ts +8 -0
- package/dist/runtime/ai-cost.d.ts.map +1 -0
- package/dist/storage/agents/in-memory.d.ts +18 -4
- package/dist/storage/agents/in-memory.d.ts.map +1 -1
- package/dist/storage/agents/index.d.ts +1 -1
- package/dist/storage/agents/index.d.ts.map +1 -1
- package/dist/storage/agents/provider.d.ts +31 -0
- package/dist/storage/agents/provider.d.ts.map +1 -1
- package/dist/storage/agents/provider.js +18 -7
- package/dist/storage/agents/provider.js.map +1 -1
- package/dist/storage/agents/types.d.ts +70 -4
- package/dist/storage/agents/types.d.ts.map +1 -1
- package/dist/storage/ai-cost/analytics.d.ts +61 -0
- package/dist/storage/ai-cost/analytics.d.ts.map +1 -0
- package/dist/storage/ai-cost/codec.d.ts +14 -0
- package/dist/storage/ai-cost/codec.d.ts.map +1 -0
- package/dist/storage/ai-cost/errors.d.ts +7 -0
- package/dist/storage/ai-cost/errors.d.ts.map +1 -0
- package/dist/storage/ai-cost/in-memory.d.ts +32 -0
- package/dist/storage/ai-cost/in-memory.d.ts.map +1 -0
- package/dist/storage/ai-cost/index.d.ts +6 -0
- package/dist/storage/ai-cost/index.d.ts.map +1 -0
- package/dist/storage/ai-cost/provider.d.ts +7 -0
- package/dist/storage/ai-cost/provider.d.ts.map +1 -0
- package/dist/storage/ai-cost/provider.js +132 -0
- package/dist/storage/ai-cost/provider.js.map +10 -0
- package/dist/storage/ai-cost/types.d.ts +154 -0
- package/dist/storage/ai-cost/types.d.ts.map +1 -0
- package/dist/storage/ai-cost/validation.d.ts +7 -0
- package/dist/storage/ai-cost/validation.d.ts.map +1 -0
- package/dist/storage/in-memory/index.d.ts +5 -0
- package/dist/storage/in-memory/index.d.ts.map +1 -1
- package/dist/storage/index.d.ts +3 -1
- package/dist/storage/index.d.ts.map +1 -1
- package/dist/storage/index.js +22 -15
- package/dist/storage/index.js.map +1 -1
- package/dist/storage/ontology/in-memory/materializations.d.ts.map +1 -1
- package/dist/storage/ontology/materializations.d.ts +3 -0
- package/dist/storage/ontology/materializations.d.ts.map +1 -1
- package/dist/storage/operation-scope.d.ts.map +1 -1
- package/dist/storage/operation-scope.js +1 -1
- package/dist/storage/types.d.ts +2 -0
- package/dist/storage/types.d.ts.map +1 -1
- package/dist/storage/workflow-runs/provider.js +6 -5
- package/dist/storage/workflow-runs/provider.js.map +1 -1
- package/dist/syncs/index.js +14 -12
- package/dist/syncs/index.js.map +1 -1
- package/dist/testing/agent-storage-contract.d.ts +3 -2
- package/dist/testing/agent-storage-contract.d.ts.map +1 -1
- package/dist/testing/ai-cost-storage-contract.d.ts +12 -0
- package/dist/testing/ai-cost-storage-contract.d.ts.map +1 -0
- package/dist/testing/index.d.ts +1 -0
- package/dist/testing/index.d.ts.map +1 -1
- package/dist/testing/index.js +2098 -1468
- package/dist/testing/index.js.map +6 -5
- package/dist/testing/materializer-storage-contract.d.ts.map +1 -1
- package/dist/webhooks/internal.js +12 -10
- package/dist/webhooks/internal.js.map +2 -2
- package/dist/workers/index.js +12 -2
- package/dist/workers/index.js.map +3 -3
- package/dist/workers/queue-worker.d.ts +2 -0
- package/dist/workers/queue-worker.d.ts.map +1 -1
- package/dist/workflows/execution.d.ts +3 -0
- package/dist/workflows/execution.d.ts.map +1 -1
- package/dist/workflows/index.js +24 -21
- package/dist/workflows/index.js.map +1 -1
- package/package.json +7 -1
- package/src/agents/adapters.ts +64 -23
- package/src/agents/errors.ts +2 -2
- package/src/agents/execution.ts +14 -2
- package/src/agents/index.ts +18 -1
- package/src/agents/prompt.ts +33 -5
- package/src/agents/request.ts +5 -0
- package/src/agents/thread-context-projection.ts +93 -0
- package/src/agents/tool-definition.ts +17 -2
- package/src/agents/tool-result.ts +61 -0
- package/src/agents/types.ts +47 -1
- package/src/agents/validation.ts +1 -1
- package/src/index.ts +13 -0
- package/src/materialization/model.ts +4 -0
- package/src/materializer/edits/apply.ts +55 -2
- package/src/materializer/edits/operations.ts +8 -1
- package/src/materializer/edits/working-state.ts +7 -0
- package/src/materializer/effective/resolve.ts +78 -9
- package/src/materializer/execution/work-records.ts +3 -1
- package/src/materializer/projections/entry-validator.ts +23 -1
- package/src/materializer/projections/replacement-plan.ts +2 -0
- package/src/materializer/shared/normalize.ts +16 -0
- package/src/projections/builders.ts +100 -35
- package/src/projections/index.ts +6 -0
- package/src/projections/internal.ts +4 -1
- package/src/projections/registry.ts +7 -0
- package/src/projections/revision.ts +4 -0
- package/src/projections/timestamp.ts +66 -0
- package/src/projections/types.ts +7 -0
- package/src/projections/validation.ts +24 -0
- package/src/queues/index.ts +1 -0
- package/src/queues/types.ts +8 -0
- package/src/runtime/ai-cost.ts +15 -0
- package/src/storage/agents/in-memory.ts +171 -4
- package/src/storage/agents/index.ts +5 -0
- package/src/storage/agents/provider.ts +225 -0
- package/src/storage/agents/types.ts +77 -3
- package/src/storage/ai-cost/analytics.ts +602 -0
- package/src/storage/ai-cost/codec.ts +136 -0
- package/src/storage/ai-cost/errors.ts +12 -0
- package/src/storage/ai-cost/in-memory.ts +164 -0
- package/src/storage/ai-cost/index.ts +35 -0
- package/src/storage/ai-cost/provider.ts +20 -0
- package/src/storage/ai-cost/types.ts +193 -0
- package/src/storage/ai-cost/validation.ts +337 -0
- package/src/storage/in-memory/index.ts +50 -0
- package/src/storage/index.ts +37 -0
- package/src/storage/ontology/in-memory/materializations.ts +1 -0
- package/src/storage/ontology/materializations.ts +3 -0
- package/src/storage/operation-scope.ts +1 -0
- package/src/storage/types.ts +2 -0
- package/src/testing/agent-storage-contract.ts +341 -2
- package/src/testing/ai-cost-storage-contract.ts +320 -0
- package/src/testing/index.ts +5 -0
- package/src/testing/materializer-storage-contract.ts +120 -2
- package/src/workers/queue-worker.ts +14 -1
- package/src/workflows/execution.ts +31 -10
- package/dist/chunk-0mbx247x.js.map +0 -43
- package/dist/chunk-663csy96.js.map +0 -10
- package/dist/chunk-st4xgxey.js.map +0 -45
- package/dist/chunk-vp1vc6ee.js +0 -35
- package/dist/chunk-vp1vc6ee.js.map +0 -11
- /package/dist/{chunk-sa4340y1.js.map → chunk-1ywq4hzk.js.map} +0 -0
- /package/dist/{chunk-zg9yryhz.js.map → chunk-261ag4t4.js.map} +0 -0
- /package/dist/{chunk-k9pts48t.js.map → chunk-3rsf30p4.js.map} +0 -0
- /package/dist/{chunk-8ryen3p3.js.map → chunk-4aw0jwk0.js.map} +0 -0
- /package/dist/{chunk-bh6k3nc6.js.map → chunk-4p9rh7jj.js.map} +0 -0
- /package/dist/{chunk-n8herkry.js.map → chunk-bv41fmjn.js.map} +0 -0
- /package/dist/{chunk-7pc8b818.js.map → chunk-c6cfqydk.js.map} +0 -0
- /package/dist/{chunk-0k4avqr2.js.map → chunk-c8bw2b6c.js.map} +0 -0
- /package/dist/{chunk-c6qd89g5.js.map → chunk-d6y2wsfg.js.map} +0 -0
- /package/dist/{chunk-nnyp53zt.js.map → chunk-f1cyvnrk.js.map} +0 -0
- /package/dist/{chunk-bct7hmfc.js.map → chunk-km4rkj4t.js.map} +0 -0
- /package/dist/{chunk-qvybnnpe.js.map → chunk-n5x5y80a.js.map} +0 -0
- /package/dist/{chunk-4x43bkbp.js.map → chunk-pxtrxm3p.js.map} +0 -0
- /package/dist/{chunk-5egfka8j.js.map → chunk-ttba8x6z.js.map} +0 -0
- /package/dist/{chunk-g9t3kdtx.js.map → chunk-z8j83gzd.js.map} +0 -0
- /package/dist/{chunk-57zpb99z.js.map → chunk-zpw39qhj.js.map} +0 -0
package/src/queues/types.ts
CHANGED
|
@@ -4,6 +4,7 @@ import type { ProjectionRunFailureCode } from "../projections/types"
|
|
|
4
4
|
import type { ProviderScope } from "../provider-scope"
|
|
5
5
|
import type { ActionRunFailureCode } from "../storage/action-runs/types"
|
|
6
6
|
import type { AgentRunFailureCode } from "../storage/agents/types"
|
|
7
|
+
import type { AiPricingContext } from "../storage/ai-cost/types"
|
|
7
8
|
import type { RecordAiModelCallInput } from "../storage/ai-usage"
|
|
8
9
|
import type { PipelineRunFailureCode } from "../storage/pipeline-runs/types"
|
|
9
10
|
import type { SyncRunFailureCode } from "../storage/sync-runs/types"
|
|
@@ -209,11 +210,18 @@ export type AgentAiUsageRecordPayload = Omit<
|
|
|
209
210
|
readonly occurredAt: string
|
|
210
211
|
}
|
|
211
212
|
|
|
213
|
+
export interface AgentAiUsageAccountingPayload {
|
|
214
|
+
readonly pricingContext: AiPricingContext
|
|
215
|
+
readonly ratedAt: string
|
|
216
|
+
}
|
|
217
|
+
|
|
212
218
|
export interface AgentAiUsageRecordRequestedQueueJob
|
|
213
219
|
extends QueueJob<
|
|
214
220
|
"agent.ai-usage.record.requested",
|
|
215
221
|
{
|
|
216
222
|
readonly record: AgentAiUsageRecordPayload
|
|
223
|
+
/** Absent on Phase 1 jobs; recovery then uses an empty pricing context. */
|
|
224
|
+
readonly accounting?: AgentAiUsageAccountingPayload
|
|
217
225
|
}
|
|
218
226
|
> {}
|
|
219
227
|
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { AiCostStorage, AiCostSummary } from "../storage/ai-cost"
|
|
2
|
+
|
|
3
|
+
/** Resolve preferred cost summaries in input order without inventing unavailable accounting. */
|
|
4
|
+
export async function resolveExecutionCosts(input: {
|
|
5
|
+
readonly storage: AiCostStorage | undefined
|
|
6
|
+
readonly projectId: string
|
|
7
|
+
readonly executionIds: readonly string[]
|
|
8
|
+
}): Promise<readonly (AiCostSummary | undefined)[]> {
|
|
9
|
+
if (input.executionIds.length === 0) return []
|
|
10
|
+
if (!input.storage) return input.executionIds.map(() => undefined)
|
|
11
|
+
return input.storage.summarizeExecutions({
|
|
12
|
+
projectId: input.projectId,
|
|
13
|
+
executionIds: input.executionIds,
|
|
14
|
+
})
|
|
15
|
+
}
|
|
@@ -5,8 +5,17 @@ import { parseSixbFailure } from "../../errors/internal"
|
|
|
5
5
|
import type { SixbFailure } from "../../errors/types"
|
|
6
6
|
import type { ExecutionStorage } from "../executions"
|
|
7
7
|
import { AgentStorageError } from "./errors"
|
|
8
|
-
import {
|
|
8
|
+
import {
|
|
9
|
+
agentContextCheckpointMatchesCreateInput,
|
|
10
|
+
assertAgentContextCheckpointAnchors,
|
|
11
|
+
assertAgentContextCheckpointAuthority,
|
|
12
|
+
assertAgentContextCheckpointReplayState,
|
|
13
|
+
assertAgentRunExecution,
|
|
14
|
+
assertCreateAgentContextCheckpointInput,
|
|
15
|
+
} from "./provider"
|
|
9
16
|
import type {
|
|
17
|
+
AgentContextCheckpointRecord,
|
|
18
|
+
AgentContextCheckpointStore,
|
|
10
19
|
AgentMessageRecord,
|
|
11
20
|
AgentMessageStore,
|
|
12
21
|
AgentRunFailureCode,
|
|
@@ -17,8 +26,10 @@ import type {
|
|
|
17
26
|
AgentThreadStore,
|
|
18
27
|
AppendAgentMessageInput,
|
|
19
28
|
ConfirmAgentRunExecutionOwnershipInput,
|
|
29
|
+
CreateAgentContextCheckpointInput,
|
|
20
30
|
CreateAgentRunInput,
|
|
21
31
|
CreateAgentThreadInput,
|
|
32
|
+
DeleteAgentMessagesByRunInput,
|
|
22
33
|
FinishAgentRunInput,
|
|
23
34
|
FinishQueuedAgentRunInput,
|
|
24
35
|
ListAgentMessagesInput,
|
|
@@ -77,21 +88,23 @@ function applyWindow<T>(rows: T[], offset = 0, limit?: number): Window<T> {
|
|
|
77
88
|
}
|
|
78
89
|
|
|
79
90
|
/**
|
|
80
|
-
* Shared in-memory state behind the
|
|
91
|
+
* Shared in-memory state behind the four sub-stores. They are tiered for ergonomics
|
|
81
92
|
* (`storage.runs.create(...)`), but several operations span tables — creating/finishing a run
|
|
82
|
-
* updates the thread anchor, appending a message bumps thread stats
|
|
83
|
-
* same maps through this object.
|
|
93
|
+
* updates the thread anchor, appending a message bumps thread stats, and checkpoint creation reads
|
|
94
|
+
* run/thread/message anchors — so they all read and write the same maps through this object.
|
|
84
95
|
*/
|
|
85
96
|
interface AgentStoreState {
|
|
86
97
|
readonly threads: Map<string, AgentThreadRecord>
|
|
87
98
|
readonly runs: Map<string, AgentRunRecord>
|
|
88
99
|
readonly messages: Map<string, AgentMessageRecord>
|
|
100
|
+
readonly checkpoints: Map<string, AgentContextCheckpointRecord>
|
|
89
101
|
}
|
|
90
102
|
|
|
91
103
|
export interface InMemoryAgentStorageSnapshot {
|
|
92
104
|
readonly threads: Map<string, AgentThreadRecord>
|
|
93
105
|
readonly runs: Map<string, AgentRunRecord>
|
|
94
106
|
readonly messages: Map<string, AgentMessageRecord>
|
|
107
|
+
readonly checkpoints: Map<string, AgentContextCheckpointRecord>
|
|
95
108
|
}
|
|
96
109
|
|
|
97
110
|
// ── threads ───────────────────────────────────────────────────────────────────────────────────
|
|
@@ -466,6 +479,50 @@ class InMemoryAgentMessageStore implements AgentMessageStore {
|
|
|
466
479
|
return clone(message)
|
|
467
480
|
}
|
|
468
481
|
|
|
482
|
+
async deleteByRunId(input: DeleteAgentMessagesByRunInput): Promise<number> {
|
|
483
|
+
const threadKey = key(input.projectId, input.threadId)
|
|
484
|
+
const thread = this.state.threads.get(threadKey)
|
|
485
|
+
if (!thread) {
|
|
486
|
+
throw new AgentStorageError(
|
|
487
|
+
"thread_not_found",
|
|
488
|
+
`[Sixb] Agent thread '${input.threadId}' not found for project '${input.projectId}'.`
|
|
489
|
+
)
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
const messages = [...this.state.messages.entries()].filter(
|
|
493
|
+
([, message]) =>
|
|
494
|
+
message.projectId === input.projectId &&
|
|
495
|
+
message.threadId === input.threadId &&
|
|
496
|
+
message.runId === input.runId
|
|
497
|
+
)
|
|
498
|
+
if (messages.length === 0) {
|
|
499
|
+
return 0
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
for (const [messageKey] of messages) {
|
|
503
|
+
this.state.messages.delete(messageKey)
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
const remainingMessages = [...this.state.messages.values()]
|
|
507
|
+
.filter(
|
|
508
|
+
(message) => message.projectId === input.projectId && message.threadId === input.threadId
|
|
509
|
+
)
|
|
510
|
+
.sort((left, right) => right.seq - left.seq)
|
|
511
|
+
const latestMessage = remainingMessages[0]
|
|
512
|
+
const updatedAt = new Date()
|
|
513
|
+
this.state.threads.set(
|
|
514
|
+
threadKey,
|
|
515
|
+
clone({
|
|
516
|
+
...thread,
|
|
517
|
+
messageCount: remainingMessages.length,
|
|
518
|
+
lastMessageAt: latestMessage?.createdAt,
|
|
519
|
+
updatedAt,
|
|
520
|
+
})
|
|
521
|
+
)
|
|
522
|
+
|
|
523
|
+
return messages.length
|
|
524
|
+
}
|
|
525
|
+
|
|
469
526
|
async getById(params: { projectId: string; id: string }): Promise<AgentMessageRecord | null> {
|
|
470
527
|
const record = this.state.messages.get(key(params.projectId, params.id))
|
|
471
528
|
return record ? clone(record) : null
|
|
@@ -478,6 +535,7 @@ class InMemoryAgentMessageStore implements AgentMessageStore {
|
|
|
478
535
|
const filtered = [...this.state.messages.values()]
|
|
479
536
|
.filter((message) => message.projectId === input.projectId)
|
|
480
537
|
.filter((message) => message.threadId === input.threadId)
|
|
538
|
+
.filter((message) => (input.afterSeq === undefined ? true : message.seq > input.afterSeq))
|
|
481
539
|
.filter((message) => (roles ? roles.has(message.role) : true))
|
|
482
540
|
.sort((a, b) => (order === "asc" ? a.seq - b.seq : b.seq - a.seq))
|
|
483
541
|
|
|
@@ -496,21 +554,128 @@ class InMemoryAgentMessageStore implements AgentMessageStore {
|
|
|
496
554
|
}
|
|
497
555
|
}
|
|
498
556
|
|
|
557
|
+
// ── context checkpoints ──────────────────────────────────────────────────────────────────────
|
|
558
|
+
|
|
559
|
+
class InMemoryAgentContextCheckpointStore implements AgentContextCheckpointStore {
|
|
560
|
+
constructor(private readonly state: AgentStoreState) {}
|
|
561
|
+
|
|
562
|
+
async create(input: CreateAgentContextCheckpointInput): Promise<AgentContextCheckpointRecord> {
|
|
563
|
+
assertCreateAgentContextCheckpointInput(input)
|
|
564
|
+
|
|
565
|
+
// No `await` between authority checks and append: this is one in-memory critical section.
|
|
566
|
+
const run = this.state.runs.get(key(input.projectId, input.createdByRunId)) ?? null
|
|
567
|
+
const thread = this.state.threads.get(key(input.projectId, input.threadId)) ?? null
|
|
568
|
+
assertAgentContextCheckpointAuthority({ create: input, run, thread })
|
|
569
|
+
|
|
570
|
+
const messages = [...this.state.messages.values()].filter(
|
|
571
|
+
(message) => message.projectId === input.projectId && message.threadId === input.threadId
|
|
572
|
+
)
|
|
573
|
+
const headSeq = messages.reduce((head, message) => Math.max(head, message.seq), 0)
|
|
574
|
+
const latest = this.findLatest(input.projectId, input.threadId)
|
|
575
|
+
|
|
576
|
+
const existingForRun = [...this.state.checkpoints.values()].find(
|
|
577
|
+
(checkpoint) =>
|
|
578
|
+
checkpoint.projectId === input.projectId &&
|
|
579
|
+
checkpoint.createdByRunId === input.createdByRunId
|
|
580
|
+
)
|
|
581
|
+
if (existingForRun) {
|
|
582
|
+
if (agentContextCheckpointMatchesCreateInput(existingForRun, input)) {
|
|
583
|
+
assertAgentContextCheckpointReplayState({
|
|
584
|
+
create: input,
|
|
585
|
+
existing: existingForRun,
|
|
586
|
+
latest,
|
|
587
|
+
headSeq,
|
|
588
|
+
})
|
|
589
|
+
return clone(existingForRun)
|
|
590
|
+
}
|
|
591
|
+
throw new AgentStorageError(
|
|
592
|
+
"invalid_state",
|
|
593
|
+
`[Sixb] Agent run '${input.createdByRunId}' already created a different context checkpoint.`
|
|
594
|
+
)
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
if (this.state.checkpoints.has(key(input.projectId, input.id))) {
|
|
598
|
+
throw new AgentStorageError(
|
|
599
|
+
"duplicate_id",
|
|
600
|
+
`[Sixb] Agent context checkpoint '${input.id}' already exists for project '${input.projectId}'.`
|
|
601
|
+
)
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
const firstRetained =
|
|
605
|
+
messages
|
|
606
|
+
.filter((message) => message.seq > input.summarizedThroughSeq)
|
|
607
|
+
.sort((left, right) => left.seq - right.seq)[0] ?? null
|
|
608
|
+
assertAgentContextCheckpointAnchors({
|
|
609
|
+
create: input,
|
|
610
|
+
latest,
|
|
611
|
+
headSeq,
|
|
612
|
+
firstRetained,
|
|
613
|
+
})
|
|
614
|
+
|
|
615
|
+
const record: AgentContextCheckpointRecord = {
|
|
616
|
+
id: input.id,
|
|
617
|
+
projectId: input.projectId,
|
|
618
|
+
threadId: input.threadId,
|
|
619
|
+
createdByRunId: input.createdByRunId,
|
|
620
|
+
...(input.expectedPreviousCheckpointId === null
|
|
621
|
+
? {}
|
|
622
|
+
: { previousCheckpointId: input.expectedPreviousCheckpointId }),
|
|
623
|
+
reason: input.reason,
|
|
624
|
+
summary: input.summary,
|
|
625
|
+
summaryFormatVersion: input.summaryFormatVersion,
|
|
626
|
+
summarizedThroughSeq: input.summarizedThroughSeq,
|
|
627
|
+
observedHeadSeq: input.observedHeadSeq,
|
|
628
|
+
estimatedInputTokensBefore: input.estimatedInputTokensBefore,
|
|
629
|
+
estimatedInputTokensAfter: input.estimatedInputTokensAfter,
|
|
630
|
+
summaryModelId: input.summaryModelId,
|
|
631
|
+
createdAt: new Date(input.createdAt ?? new Date()),
|
|
632
|
+
}
|
|
633
|
+
this.state.checkpoints.set(key(input.projectId, input.id), clone(record))
|
|
634
|
+
return clone(record)
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
async getLatest(input: {
|
|
638
|
+
readonly projectId: string
|
|
639
|
+
readonly threadId: string
|
|
640
|
+
}): Promise<AgentContextCheckpointRecord | null> {
|
|
641
|
+
const record = this.findLatest(input.projectId, input.threadId)
|
|
642
|
+
return record ? clone(record) : null
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
private findLatest(projectId: string, threadId: string): AgentContextCheckpointRecord | null {
|
|
646
|
+
return (
|
|
647
|
+
[...this.state.checkpoints.values()]
|
|
648
|
+
.filter(
|
|
649
|
+
(checkpoint) => checkpoint.projectId === projectId && checkpoint.threadId === threadId
|
|
650
|
+
)
|
|
651
|
+
.sort(
|
|
652
|
+
(left, right) =>
|
|
653
|
+
right.summarizedThroughSeq - left.summarizedThroughSeq ||
|
|
654
|
+
right.createdAt.getTime() - left.createdAt.getTime() ||
|
|
655
|
+
right.id.localeCompare(left.id)
|
|
656
|
+
)[0] ?? null
|
|
657
|
+
)
|
|
658
|
+
}
|
|
659
|
+
}
|
|
660
|
+
|
|
499
661
|
export class InMemoryAgentStorage implements AgentStorage {
|
|
500
662
|
private readonly state: AgentStoreState = {
|
|
501
663
|
threads: new Map(),
|
|
502
664
|
runs: new Map(),
|
|
503
665
|
messages: new Map(),
|
|
666
|
+
checkpoints: new Map(),
|
|
504
667
|
}
|
|
505
668
|
|
|
506
669
|
readonly threads: InMemoryAgentThreadStore
|
|
507
670
|
readonly runs: InMemoryAgentRunStore
|
|
508
671
|
readonly messages: InMemoryAgentMessageStore
|
|
672
|
+
readonly checkpoints: InMemoryAgentContextCheckpointStore
|
|
509
673
|
|
|
510
674
|
constructor(executions: ExecutionStorage) {
|
|
511
675
|
this.threads = new InMemoryAgentThreadStore(this.state)
|
|
512
676
|
this.runs = new InMemoryAgentRunStore(this.state, executions)
|
|
513
677
|
this.messages = new InMemoryAgentMessageStore(this.state)
|
|
678
|
+
this.checkpoints = new InMemoryAgentContextCheckpointStore(this.state)
|
|
514
679
|
}
|
|
515
680
|
|
|
516
681
|
snapshot(): InMemoryAgentStorageSnapshot {
|
|
@@ -518,6 +683,7 @@ export class InMemoryAgentStorage implements AgentStorage {
|
|
|
518
683
|
threads: structuredClone(this.state.threads),
|
|
519
684
|
runs: structuredClone(this.state.runs),
|
|
520
685
|
messages: structuredClone(this.state.messages),
|
|
686
|
+
checkpoints: structuredClone(this.state.checkpoints),
|
|
521
687
|
}
|
|
522
688
|
}
|
|
523
689
|
|
|
@@ -525,6 +691,7 @@ export class InMemoryAgentStorage implements AgentStorage {
|
|
|
525
691
|
replace(this.state.threads, snapshot.threads)
|
|
526
692
|
replace(this.state.runs, snapshot.runs)
|
|
527
693
|
replace(this.state.messages, snapshot.messages)
|
|
694
|
+
replace(this.state.checkpoints, snapshot.checkpoints)
|
|
528
695
|
}
|
|
529
696
|
}
|
|
530
697
|
|
|
@@ -3,6 +3,9 @@ export { AgentStorageError } from "./errors"
|
|
|
3
3
|
export type { InMemoryAgentStorageSnapshot } from "./in-memory"
|
|
4
4
|
export { InMemoryAgentStorage } from "./in-memory"
|
|
5
5
|
export type {
|
|
6
|
+
AgentContextCheckpointReason,
|
|
7
|
+
AgentContextCheckpointRecord,
|
|
8
|
+
AgentContextCheckpointStore,
|
|
6
9
|
AgentExecutionStatus,
|
|
7
10
|
AgentMessageRecord,
|
|
8
11
|
AgentMessageRole,
|
|
@@ -22,8 +25,10 @@ export type {
|
|
|
22
25
|
AgentThreadStore,
|
|
23
26
|
AppendAgentMessageInput,
|
|
24
27
|
ConfirmAgentRunExecutionOwnershipInput,
|
|
28
|
+
CreateAgentContextCheckpointInput,
|
|
25
29
|
CreateAgentRunInput,
|
|
26
30
|
CreateAgentThreadInput,
|
|
31
|
+
DeleteAgentMessagesByRunInput,
|
|
27
32
|
FinishAgentRunInput,
|
|
28
33
|
FinishQueuedAgentRunInput,
|
|
29
34
|
ListAgentMessagesInput,
|
|
@@ -2,6 +2,13 @@ import { agentServiceAccountId } from "../../agents/authority"
|
|
|
2
2
|
import type { ExecutionStorage } from "../executions"
|
|
3
3
|
import { findAgentRunExecution } from "../executions/run-link"
|
|
4
4
|
import { AgentStorageError } from "./errors"
|
|
5
|
+
import type {
|
|
6
|
+
AgentContextCheckpointRecord,
|
|
7
|
+
AgentMessageRecord,
|
|
8
|
+
AgentRunRecord,
|
|
9
|
+
AgentThreadRecord,
|
|
10
|
+
CreateAgentContextCheckpointInput,
|
|
11
|
+
} from "./types"
|
|
5
12
|
|
|
6
13
|
/** Validate the semantic link between a conversational Agent run and its immutable execution. */
|
|
7
14
|
export async function assertAgentRunExecution(input: {
|
|
@@ -25,3 +32,221 @@ export async function assertAgentRunExecution(input: {
|
|
|
25
32
|
)
|
|
26
33
|
}
|
|
27
34
|
}
|
|
35
|
+
|
|
36
|
+
/** Validate provider-independent checkpoint fields before entering a storage critical section. */
|
|
37
|
+
export function assertCreateAgentContextCheckpointInput(
|
|
38
|
+
input: CreateAgentContextCheckpointInput,
|
|
39
|
+
prefix = "Sixb"
|
|
40
|
+
): void {
|
|
41
|
+
for (const [name, value] of [
|
|
42
|
+
["id", input.id],
|
|
43
|
+
["projectId", input.projectId],
|
|
44
|
+
["threadId", input.threadId],
|
|
45
|
+
["createdByRunId", input.createdByRunId],
|
|
46
|
+
["executionToken", input.executionToken],
|
|
47
|
+
["summary", input.summary],
|
|
48
|
+
["summaryModelId", input.summaryModelId],
|
|
49
|
+
] as const) {
|
|
50
|
+
if (value.trim().length === 0) {
|
|
51
|
+
throw new AgentStorageError(
|
|
52
|
+
"invalid_input",
|
|
53
|
+
`[${prefix}] Agent context checkpoint '${name}' must not be empty.`
|
|
54
|
+
)
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if (input.summaryFormatVersion !== 1) {
|
|
59
|
+
throw new AgentStorageError(
|
|
60
|
+
"invalid_input",
|
|
61
|
+
`[${prefix}] Agent context checkpoint summary format version must be 1.`
|
|
62
|
+
)
|
|
63
|
+
}
|
|
64
|
+
if (input.reason !== "threshold" && input.reason !== "overflow") {
|
|
65
|
+
throw new AgentStorageError(
|
|
66
|
+
"invalid_input",
|
|
67
|
+
`[${prefix}] Agent context checkpoint reason must be 'threshold' or 'overflow'.`
|
|
68
|
+
)
|
|
69
|
+
}
|
|
70
|
+
if (
|
|
71
|
+
input.expectedPreviousCheckpointId !== null &&
|
|
72
|
+
input.expectedPreviousCheckpointId.trim().length === 0
|
|
73
|
+
) {
|
|
74
|
+
throw new AgentStorageError(
|
|
75
|
+
"invalid_input",
|
|
76
|
+
`[${prefix}] Agent context checkpoint expected previous id must not be empty.`
|
|
77
|
+
)
|
|
78
|
+
}
|
|
79
|
+
if (input.createdAt && !Number.isFinite(input.createdAt.getTime())) {
|
|
80
|
+
throw new AgentStorageError(
|
|
81
|
+
"invalid_input",
|
|
82
|
+
`[${prefix}] Agent context checkpoint createdAt must be a valid date.`
|
|
83
|
+
)
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
for (const [name, value, minimum] of [
|
|
87
|
+
["expectedHeadSeq", input.expectedHeadSeq, 1],
|
|
88
|
+
["summarizedThroughSeq", input.summarizedThroughSeq, 1],
|
|
89
|
+
["observedHeadSeq", input.observedHeadSeq, 1],
|
|
90
|
+
["estimatedInputTokensBefore", input.estimatedInputTokensBefore, 0],
|
|
91
|
+
["estimatedInputTokensAfter", input.estimatedInputTokensAfter, 0],
|
|
92
|
+
] as const) {
|
|
93
|
+
if (!Number.isSafeInteger(value) || value < minimum) {
|
|
94
|
+
throw new AgentStorageError(
|
|
95
|
+
"invalid_input",
|
|
96
|
+
`[${prefix}] Agent context checkpoint '${name}' must be a safe integer greater than or equal to ${minimum}.`
|
|
97
|
+
)
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
if (input.observedHeadSeq !== input.expectedHeadSeq) {
|
|
102
|
+
throw new AgentStorageError(
|
|
103
|
+
"invalid_input",
|
|
104
|
+
`[${prefix}] Agent context checkpoint observed head must equal its expected message head.`
|
|
105
|
+
)
|
|
106
|
+
}
|
|
107
|
+
if (input.summarizedThroughSeq >= input.observedHeadSeq) {
|
|
108
|
+
throw new AgentStorageError(
|
|
109
|
+
"invalid_input",
|
|
110
|
+
`[${prefix}] Agent context checkpoint must retain the triggering head message.`
|
|
111
|
+
)
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/** Assert that the current delivery still owns the active conversational run. */
|
|
116
|
+
export function assertAgentContextCheckpointAuthority(input: {
|
|
117
|
+
readonly create: CreateAgentContextCheckpointInput
|
|
118
|
+
readonly run: AgentRunRecord | null
|
|
119
|
+
readonly thread: AgentThreadRecord | null
|
|
120
|
+
readonly prefix?: string
|
|
121
|
+
}): asserts input is typeof input & {
|
|
122
|
+
readonly run: AgentRunRecord
|
|
123
|
+
readonly thread: AgentThreadRecord
|
|
124
|
+
} {
|
|
125
|
+
const { create, run, thread } = input
|
|
126
|
+
const prefix = input.prefix ?? "Sixb"
|
|
127
|
+
if (!run) {
|
|
128
|
+
throw new AgentStorageError(
|
|
129
|
+
"run_not_found",
|
|
130
|
+
`[${prefix}] Agent run '${create.createdByRunId}' not found for project '${create.projectId}'.`
|
|
131
|
+
)
|
|
132
|
+
}
|
|
133
|
+
if (!thread) {
|
|
134
|
+
throw new AgentStorageError(
|
|
135
|
+
"thread_not_found",
|
|
136
|
+
`[${prefix}] Agent thread '${create.threadId}' not found for project '${create.projectId}'.`
|
|
137
|
+
)
|
|
138
|
+
}
|
|
139
|
+
if (run.threadId !== create.threadId) {
|
|
140
|
+
throw new AgentStorageError(
|
|
141
|
+
"invalid_input",
|
|
142
|
+
`[${prefix}] Agent run '${run.id}' does not belong to thread '${create.threadId}'.`
|
|
143
|
+
)
|
|
144
|
+
}
|
|
145
|
+
if (run.status !== "running") {
|
|
146
|
+
throw new AgentStorageError(
|
|
147
|
+
"invalid_state",
|
|
148
|
+
`[${prefix}] Agent run '${run.id}' is not running (status '${run.status}').`
|
|
149
|
+
)
|
|
150
|
+
}
|
|
151
|
+
if (!run.execution || run.execution.token !== create.executionToken) {
|
|
152
|
+
throw new AgentStorageError(
|
|
153
|
+
"execution_lost",
|
|
154
|
+
`[${prefix}] Execution token is no longer current on agent run '${run.id}'.`
|
|
155
|
+
)
|
|
156
|
+
}
|
|
157
|
+
if (thread.activeRunId !== run.id) {
|
|
158
|
+
throw new AgentStorageError(
|
|
159
|
+
"invalid_state",
|
|
160
|
+
`[${prefix}] Agent run '${run.id}' no longer owns thread '${thread.id}'.`
|
|
161
|
+
)
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/** Assert both compare-and-swap anchors and the retained-turn boundary. */
|
|
166
|
+
export function assertAgentContextCheckpointAnchors(input: {
|
|
167
|
+
readonly create: CreateAgentContextCheckpointInput
|
|
168
|
+
readonly latest: AgentContextCheckpointRecord | null
|
|
169
|
+
readonly headSeq: number
|
|
170
|
+
readonly firstRetained: AgentMessageRecord | null
|
|
171
|
+
readonly prefix?: string
|
|
172
|
+
}): void {
|
|
173
|
+
const { create, latest, headSeq, firstRetained } = input
|
|
174
|
+
const prefix = input.prefix ?? "Sixb"
|
|
175
|
+
if (headSeq !== create.expectedHeadSeq) {
|
|
176
|
+
throw new AgentStorageError(
|
|
177
|
+
"invalid_state",
|
|
178
|
+
`[${prefix}] Agent thread '${create.threadId}' message head changed from ${create.expectedHeadSeq} to ${headSeq}.`
|
|
179
|
+
)
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
const latestId = latest?.id ?? null
|
|
183
|
+
if (latestId !== create.expectedPreviousCheckpointId) {
|
|
184
|
+
throw new AgentStorageError(
|
|
185
|
+
"invalid_state",
|
|
186
|
+
`[${prefix}] Agent thread '${create.threadId}' checkpoint head changed.`
|
|
187
|
+
)
|
|
188
|
+
}
|
|
189
|
+
if (latest && create.summarizedThroughSeq <= latest.summarizedThroughSeq) {
|
|
190
|
+
throw new AgentStorageError(
|
|
191
|
+
"invalid_input",
|
|
192
|
+
`[${prefix}] Agent context checkpoint boundary must advance beyond sequence ${latest.summarizedThroughSeq}.`
|
|
193
|
+
)
|
|
194
|
+
}
|
|
195
|
+
if (!firstRetained || firstRetained.seq !== create.summarizedThroughSeq + 1) {
|
|
196
|
+
throw new AgentStorageError(
|
|
197
|
+
"invalid_state",
|
|
198
|
+
`[${prefix}] Agent context checkpoint boundary does not align with stored thread messages.`
|
|
199
|
+
)
|
|
200
|
+
}
|
|
201
|
+
if (firstRetained.role !== "user") {
|
|
202
|
+
throw new AgentStorageError(
|
|
203
|
+
"invalid_input",
|
|
204
|
+
`[${prefix}] Agent context checkpoint must retain a complete turn beginning with a user message.`
|
|
205
|
+
)
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/** Validate the mutable anchors again before returning an idempotently created checkpoint. */
|
|
210
|
+
export function assertAgentContextCheckpointReplayState(input: {
|
|
211
|
+
readonly create: CreateAgentContextCheckpointInput
|
|
212
|
+
readonly existing: AgentContextCheckpointRecord
|
|
213
|
+
readonly latest: AgentContextCheckpointRecord | null
|
|
214
|
+
readonly headSeq: number
|
|
215
|
+
readonly prefix?: string
|
|
216
|
+
}): void {
|
|
217
|
+
const prefix = input.prefix ?? "Sixb"
|
|
218
|
+
if (input.headSeq !== input.create.expectedHeadSeq) {
|
|
219
|
+
throw new AgentStorageError(
|
|
220
|
+
"invalid_state",
|
|
221
|
+
`[${prefix}] Agent thread '${input.create.threadId}' message head changed from ${input.create.expectedHeadSeq} to ${input.headSeq}.`
|
|
222
|
+
)
|
|
223
|
+
}
|
|
224
|
+
if (input.latest?.id !== input.existing.id) {
|
|
225
|
+
throw new AgentStorageError(
|
|
226
|
+
"invalid_state",
|
|
227
|
+
`[${prefix}] Agent thread '${input.create.threadId}' checkpoint head changed after '${input.existing.id}'.`
|
|
228
|
+
)
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/** Compare the durable semantic payload; delivery token and generated timestamp are not content. */
|
|
233
|
+
export function agentContextCheckpointMatchesCreateInput(
|
|
234
|
+
record: AgentContextCheckpointRecord,
|
|
235
|
+
input: CreateAgentContextCheckpointInput
|
|
236
|
+
): boolean {
|
|
237
|
+
return (
|
|
238
|
+
record.id === input.id &&
|
|
239
|
+
record.projectId === input.projectId &&
|
|
240
|
+
record.threadId === input.threadId &&
|
|
241
|
+
record.createdByRunId === input.createdByRunId &&
|
|
242
|
+
(record.previousCheckpointId ?? null) === input.expectedPreviousCheckpointId &&
|
|
243
|
+
record.reason === input.reason &&
|
|
244
|
+
record.summary === input.summary &&
|
|
245
|
+
record.summaryFormatVersion === input.summaryFormatVersion &&
|
|
246
|
+
record.summarizedThroughSeq === input.summarizedThroughSeq &&
|
|
247
|
+
record.observedHeadSeq === input.observedHeadSeq &&
|
|
248
|
+
record.estimatedInputTokensBefore === input.estimatedInputTokensBefore &&
|
|
249
|
+
record.estimatedInputTokensAfter === input.estimatedInputTokensAfter &&
|
|
250
|
+
record.summaryModelId === input.summaryModelId
|
|
251
|
+
)
|
|
252
|
+
}
|
|
@@ -69,15 +69,17 @@ export const AGENT_RUN_FAILURE_CODES = [
|
|
|
69
69
|
export type AgentRunFailureCode = (typeof AGENT_RUN_FAILURE_CODES)[number]
|
|
70
70
|
|
|
71
71
|
/**
|
|
72
|
-
* Why a run ended — our own SDK-independent vocabulary
|
|
73
|
-
* reasons
|
|
74
|
-
* catch-alls:
|
|
72
|
+
* Why a run ended — our own SDK-independent vocabulary. It includes the AI SDK's unified finish
|
|
73
|
+
* reasons plus platform-level endings such as `timeout`, so reads are typed and exhaustive without
|
|
74
|
+
* core depending on `ai`. `other`/`unknown` are catch-alls: an unrecognised provider value still
|
|
75
|
+
* records *that* the run ended.
|
|
75
76
|
*/
|
|
76
77
|
export const AGENT_RUN_FINISH_REASONS = [
|
|
77
78
|
"stop",
|
|
78
79
|
"length",
|
|
79
80
|
"content-filter",
|
|
80
81
|
"tool-calls",
|
|
82
|
+
"timeout",
|
|
81
83
|
"error",
|
|
82
84
|
"other",
|
|
83
85
|
"unknown",
|
|
@@ -287,9 +289,17 @@ export interface AppendAgentMessageInput extends AgentMessage {
|
|
|
287
289
|
readonly completedAt?: Date
|
|
288
290
|
}
|
|
289
291
|
|
|
292
|
+
export interface DeleteAgentMessagesByRunInput {
|
|
293
|
+
readonly projectId: string
|
|
294
|
+
readonly threadId: string
|
|
295
|
+
readonly runId: string
|
|
296
|
+
}
|
|
297
|
+
|
|
290
298
|
export interface ListAgentMessagesInput {
|
|
291
299
|
readonly projectId: string
|
|
292
300
|
readonly threadId: string
|
|
301
|
+
/** Return only messages whose per-thread sequence is greater than this retained boundary. */
|
|
302
|
+
readonly afterSeq?: number
|
|
293
303
|
readonly roles?: readonly AgentMessageRole[]
|
|
294
304
|
readonly limit?: number
|
|
295
305
|
readonly offset?: number
|
|
@@ -302,6 +312,55 @@ export interface ListAgentMessagesResult {
|
|
|
302
312
|
readonly total: number
|
|
303
313
|
}
|
|
304
314
|
|
|
315
|
+
// ── agent_context_checkpoints — append-only model-context boundaries ──────────────────────────
|
|
316
|
+
|
|
317
|
+
export type AgentContextCheckpointReason = "threshold" | "overflow"
|
|
318
|
+
|
|
319
|
+
/**
|
|
320
|
+
* A durable summary boundary used only when projecting a thread into model context.
|
|
321
|
+
*
|
|
322
|
+
* Checkpoints never replace or mutate transcript messages. Normal thread reads remain authoritative
|
|
323
|
+
* and complete; the worker reads the latest checkpoint and only the retained message tail.
|
|
324
|
+
*/
|
|
325
|
+
export interface AgentContextCheckpointRecord {
|
|
326
|
+
readonly id: string
|
|
327
|
+
readonly projectId: string
|
|
328
|
+
readonly threadId: string
|
|
329
|
+
readonly createdByRunId: string
|
|
330
|
+
readonly previousCheckpointId?: string
|
|
331
|
+
readonly reason: AgentContextCheckpointReason
|
|
332
|
+
readonly summary: string
|
|
333
|
+
readonly summaryFormatVersion: 1
|
|
334
|
+
readonly summarizedThroughSeq: number
|
|
335
|
+
readonly observedHeadSeq: number
|
|
336
|
+
readonly estimatedInputTokensBefore: number
|
|
337
|
+
readonly estimatedInputTokensAfter: number
|
|
338
|
+
readonly summaryModelId: string
|
|
339
|
+
readonly createdAt: Date
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
export interface CreateAgentContextCheckpointInput {
|
|
343
|
+
readonly id: string
|
|
344
|
+
readonly projectId: string
|
|
345
|
+
readonly threadId: string
|
|
346
|
+
readonly createdByRunId: string
|
|
347
|
+
/** Compare-and-swap anchor. `null` means the thread must not have a prior checkpoint. */
|
|
348
|
+
readonly expectedPreviousCheckpointId: string | null
|
|
349
|
+
/** Compare-and-swap anchor for the complete transcript observed by the summarizer. */
|
|
350
|
+
readonly expectedHeadSeq: number
|
|
351
|
+
/** Current delivery token for `createdByRunId`; stale redeliveries must not write. */
|
|
352
|
+
readonly executionToken: string
|
|
353
|
+
readonly reason: AgentContextCheckpointReason
|
|
354
|
+
readonly summary: string
|
|
355
|
+
readonly summaryFormatVersion: 1
|
|
356
|
+
readonly summarizedThroughSeq: number
|
|
357
|
+
readonly observedHeadSeq: number
|
|
358
|
+
readonly estimatedInputTokensBefore: number
|
|
359
|
+
readonly estimatedInputTokensAfter: number
|
|
360
|
+
readonly summaryModelId: string
|
|
361
|
+
readonly createdAt?: Date
|
|
362
|
+
}
|
|
363
|
+
|
|
305
364
|
// ── Store ───────────────────────────────────────────────────────────────────────────────────────
|
|
306
365
|
|
|
307
366
|
export interface AgentThreadStore {
|
|
@@ -337,12 +396,27 @@ export interface AgentRunStore {
|
|
|
337
396
|
export interface AgentMessageStore {
|
|
338
397
|
/** Insert a message (its `parts` are the canonical content) and bump thread stats. */
|
|
339
398
|
append(input: AppendAgentMessageInput): Promise<AgentMessageRecord>
|
|
399
|
+
/** Delete every message produced by one run and repair the thread's message stats. */
|
|
400
|
+
deleteByRunId(input: DeleteAgentMessagesByRunInput): Promise<number>
|
|
340
401
|
getById(params: { projectId: string; id: string }): Promise<AgentMessageRecord | null>
|
|
341
402
|
list(input: ListAgentMessagesInput): Promise<ListAgentMessagesResult>
|
|
342
403
|
}
|
|
343
404
|
|
|
405
|
+
export interface AgentContextCheckpointStore {
|
|
406
|
+
/**
|
|
407
|
+
* Append one checkpoint after atomically validating run ownership and both transcript anchors.
|
|
408
|
+
* Repeating the same payload for the same creating run is idempotent.
|
|
409
|
+
*/
|
|
410
|
+
create(input: CreateAgentContextCheckpointInput): Promise<AgentContextCheckpointRecord>
|
|
411
|
+
getLatest(input: {
|
|
412
|
+
readonly projectId: string
|
|
413
|
+
readonly threadId: string
|
|
414
|
+
}): Promise<AgentContextCheckpointRecord | null>
|
|
415
|
+
}
|
|
416
|
+
|
|
344
417
|
export interface AgentStorage {
|
|
345
418
|
readonly threads: AgentThreadStore
|
|
346
419
|
readonly runs: AgentRunStore
|
|
347
420
|
readonly messages: AgentMessageStore
|
|
421
|
+
readonly checkpoints: AgentContextCheckpointStore
|
|
348
422
|
}
|