@truefoundry/trueforge-core 0.2.0-rc.0 → 0.2.0-rc.2
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/agent-session/SessionHandle.d.ts +1 -0
- package/dist/agent-session/SessionHandle.d.ts.map +1 -1
- package/dist/agent-session/SessionHandle.js +3 -0
- package/dist/agent-session/SessionHandle.js.map +1 -1
- package/dist/agent-session/SessionHandle.mjs +3 -0
- package/dist/agent-session/SessionHandle.mjs.map +1 -1
- package/dist/agent-session/Sessions.d.ts +21 -6
- package/dist/agent-session/Sessions.d.ts.map +1 -1
- package/dist/agent-session/Sessions.js +46 -1
- package/dist/agent-session/Sessions.js.map +1 -1
- package/dist/agent-session/Sessions.mjs +46 -1
- package/dist/agent-session/Sessions.mjs.map +1 -1
- package/dist/agent-session/index.d.ts +6 -4
- package/dist/agent-session/index.d.ts.map +1 -1
- package/dist/agent-session/index.js +15 -0
- package/dist/agent-session/index.js.map +1 -1
- package/dist/agent-session/index.mjs +17 -1
- package/dist/agent-session/index.mjs.map +1 -1
- package/dist/agent-session/models/SessionRecord.d.ts +14 -2
- package/dist/agent-session/models/SessionRecord.d.ts.map +1 -1
- package/dist/agent-session/models/SessionRecord.js.map +1 -1
- package/dist/agent-session/schemas/session.d.ts +43 -1
- package/dist/agent-session/schemas/session.d.ts.map +1 -1
- package/dist/agent-session/schemas/session.js +43 -5
- package/dist/agent-session/schemas/session.js.map +1 -1
- package/dist/agent-session/schemas/session.mjs +37 -4
- package/dist/agent-session/schemas/session.mjs.map +1 -1
- package/dist/agent-session/schemas/subject.d.ts +9 -0
- package/dist/agent-session/schemas/subject.d.ts.map +1 -0
- package/dist/agent-session/schemas/subject.js +36 -0
- package/dist/agent-session/schemas/subject.js.map +1 -0
- package/dist/agent-session/schemas/subject.mjs +11 -0
- package/dist/agent-session/schemas/subject.mjs.map +1 -0
- package/dist/agent-session/store/ISessionStore.d.ts +44 -20
- package/dist/agent-session/store/ISessionStore.d.ts.map +1 -1
- package/dist/agent-session/store/ISessionStore.js.map +1 -1
- package/dist/agent-session/store/InMemorySessionStore.d.ts +4 -1
- package/dist/agent-session/store/InMemorySessionStore.d.ts.map +1 -1
- package/dist/agent-session/store/InMemorySessionStore.js +66 -2
- package/dist/agent-session/store/InMemorySessionStore.js.map +1 -1
- package/dist/agent-session/store/InMemorySessionStore.mjs +67 -2
- package/dist/agent-session/store/InMemorySessionStore.mjs.map +1 -1
- package/dist/agent-session/store/SessionStoreErrors.d.ts +4 -0
- package/dist/agent-session/store/SessionStoreErrors.d.ts.map +1 -1
- package/dist/agent-session/store/SessionStoreErrors.js +10 -0
- package/dist/agent-session/store/SessionStoreErrors.js.map +1 -1
- package/dist/agent-session/store/SessionStoreErrors.mjs +9 -0
- package/dist/agent-session/store/SessionStoreErrors.mjs.map +1 -1
- package/dist/core/llm/VercelAILLM.d.ts +1 -1
- package/dist/core/llm/VercelAILLM.d.ts.map +1 -1
- package/dist/core/llm/VercelAILLM.js +4 -2
- package/dist/core/llm/VercelAILLM.js.map +1 -1
- package/dist/core/llm/VercelAILLM.mjs +4 -2
- package/dist/core/llm/VercelAILLM.mjs.map +1 -1
- package/dist/core/mcp/remoteMcpClient.js +1 -1
- package/dist/core/mcp/remoteMcpClient.js.map +1 -1
- package/dist/core/mcp/remoteMcpClient.mjs +1 -1
- package/dist/core/mcp/remoteMcpClient.mjs.map +1 -1
- package/dist/core/sandbox/Sandbox.js +5 -5
- package/dist/core/sandbox/Sandbox.js.map +1 -1
- package/dist/core/sandbox/Sandbox.mjs +1 -1
- package/dist/core/sandbox/Sandbox.mjs.map +1 -1
- package/package.json +1 -1
|
@@ -7,28 +7,35 @@ import type { SessionRecord } from '../models/SessionRecord';
|
|
|
7
7
|
import type { TurnRecord } from '../models/TurnRecord';
|
|
8
8
|
import type { PersistedTurnEvent, SessionEventItem } from '../schemas/events';
|
|
9
9
|
import type { TokenPagination } from '../schemas/pagination';
|
|
10
|
+
import type { SessionMetadata } from '../schemas/session';
|
|
10
11
|
import type { CancellationReason, TerminalTurnState } from '../schemas/turn';
|
|
11
12
|
/**
|
|
12
13
|
* Caller-supplied fields for creating a session; the store owns timestamps and tip state.
|
|
13
14
|
* `agent` is a discriminated reference | inline binding.
|
|
14
15
|
*/
|
|
15
|
-
export type CreateSessionInput<TSessionCustom extends object = Record<string, never>> = Pick<SessionRecord<TSessionCustom>, 'tenant_id' | 'session_id' | 'agent' | '
|
|
16
|
+
export type CreateSessionInput<TSessionCustom extends object = Record<string, never>> = Pick<SessionRecord<TSessionCustom>, 'tenant_id' | 'session_id' | 'agent' | 'created_by_subject' | 'external_id' | 'metadata' | 'source'> & {
|
|
16
17
|
custom: TSessionCustom | null;
|
|
17
18
|
};
|
|
18
19
|
/**
|
|
19
20
|
* PATCH fields for an existing session; `undefined` fields are left unchanged.
|
|
20
21
|
* `agent` may be set only on inline sessions, and only as an inline arm (`{ type: 'inline', spec }`).
|
|
22
|
+
* `metadata` when set fully replaces the stored map (`{}` clears).
|
|
21
23
|
*/
|
|
22
24
|
export type UpdateSessionInput<TSessionCustom extends object = Record<string, never>> = Pick<SessionRecord<TSessionCustom>, 'tenant_id' | 'session_id'> & {
|
|
23
25
|
agent: Extract<SessionRecord<TSessionCustom>['agent'], {
|
|
24
26
|
type: 'inline';
|
|
25
27
|
}> | undefined;
|
|
26
28
|
title: SessionRecord<TSessionCustom>['title'] | undefined;
|
|
29
|
+
metadata: SessionRecord<TSessionCustom>['metadata'] | undefined;
|
|
27
30
|
};
|
|
28
31
|
export interface GetSessionInput {
|
|
29
32
|
tenant_id: string;
|
|
30
33
|
session_id: string;
|
|
31
34
|
}
|
|
35
|
+
export interface GetSessionByExternalIdInput {
|
|
36
|
+
tenant_id: string;
|
|
37
|
+
external_id: string;
|
|
38
|
+
}
|
|
32
39
|
export interface DeleteSessionInput {
|
|
33
40
|
tenant_id: string;
|
|
34
41
|
session_id: string;
|
|
@@ -44,8 +51,24 @@ export interface ListSessionsInput {
|
|
|
44
51
|
end_timestamp: Date | undefined;
|
|
45
52
|
/** When set, only sessions bound to this named agent id. */
|
|
46
53
|
agent_id: string | undefined;
|
|
47
|
-
/** When set,
|
|
48
|
-
|
|
54
|
+
/** When set, match creator or named-agent binding. Empty `agent_ids` means creator-only. */
|
|
55
|
+
created_by_or_agent_ids: {
|
|
56
|
+
created_by_subject_id: string;
|
|
57
|
+
agent_ids: readonly string[];
|
|
58
|
+
} | undefined;
|
|
59
|
+
/**
|
|
60
|
+
* When set, only sessions whose metadata contains all key/value pairs
|
|
61
|
+
* (exact string equality; extra session keys are allowed).
|
|
62
|
+
* `undefined` means no metadata filter; `{}` matches only sessions with empty metadata.
|
|
63
|
+
*/
|
|
64
|
+
metadata: SessionMetadata | undefined;
|
|
65
|
+
/** When set, only sessions whose `source.type` matches. */
|
|
66
|
+
source_type: string | undefined;
|
|
67
|
+
/**
|
|
68
|
+
* When set, only sessions whose `source.id` matches.
|
|
69
|
+
* Requires `source_type`.
|
|
70
|
+
*/
|
|
71
|
+
source_id: string | undefined;
|
|
49
72
|
}
|
|
50
73
|
/** Turn row fields without assembled snapshot (create input / listTurns). */
|
|
51
74
|
export type TurnRecordWithoutSnapshot<TTurnCustom extends object = Record<string, never>> = Omit<TurnRecord<TTurnCustom>, 'snapshot'>;
|
|
@@ -173,7 +196,7 @@ export interface ISessionStore<TSessionCustom extends object = Record<string, ne
|
|
|
173
196
|
/**
|
|
174
197
|
* Persists a discriminated `agent` (ref | value). SQL backends may flatten to columns.
|
|
175
198
|
* `session_id` is globally unique across tenants.
|
|
176
|
-
* Persists caller-supplied `
|
|
199
|
+
* Persists caller-supplied `created_by_subject` (immutable after create).
|
|
177
200
|
* Sets `last_activity_timestamp_ms` (= now) on create.
|
|
178
201
|
*/
|
|
179
202
|
createSession(input: CreateSessionInput<TSessionCustom>): Promise<void>;
|
|
@@ -184,10 +207,16 @@ export interface ISessionStore<TSessionCustom extends object = Record<string, ne
|
|
|
184
207
|
* Does **not** bump `last_activity_timestamp_ms` (read path).
|
|
185
208
|
*/
|
|
186
209
|
getSession(input: GetSessionInput): Promise<SessionRecord<TSessionCustom> | undefined>;
|
|
210
|
+
/**
|
|
211
|
+
* Lookup by tenant-scoped `external_id`. Missing or null external ids are not found.
|
|
212
|
+
* Does **not** bump `last_activity_timestamp_ms` (read path).
|
|
213
|
+
*/
|
|
214
|
+
getSessionByExternalId(input: GetSessionByExternalIdInput): Promise<SessionRecord<TSessionCustom> | undefined>;
|
|
187
215
|
/**
|
|
188
216
|
* PATCH semantics — update only the provided fields:
|
|
189
217
|
* - agent: replace inline binding (inline sessions only; reference → invariant error).
|
|
190
218
|
* - title: set/replace the session title.
|
|
219
|
+
* - metadata: full replace of the caller-owned string map when set.
|
|
191
220
|
* Bumps `last_activity_timestamp_ms` (= now) in the same update.
|
|
192
221
|
*/
|
|
193
222
|
updateSession(input: UpdateSessionInput<TSessionCustom>): Promise<void>;
|
|
@@ -196,8 +225,10 @@ export interface ISessionStore<TSessionCustom extends object = Record<string, ne
|
|
|
196
225
|
* (`order` defaults to `desc`, `session_id` tie-break). `page_token` is a
|
|
197
226
|
* keyset cursor on `(updated_at, session_id)`. `start_timestamp` /
|
|
198
227
|
* `end_timestamp` are inclusive instant bounds on `created_at`. Optional
|
|
199
|
-
* `agent_id` filters ref-bound sessions
|
|
200
|
-
*
|
|
228
|
+
* `agent_id` filters ref-bound sessions. `created_by_or_agent_ids` matches
|
|
229
|
+
* rows created by its subject OR bound to one of its agent ids; optional
|
|
230
|
+
* `source_type` / `source_id` filter by JSON `source` (expression-indexed,
|
|
231
|
+
* no scalar columns). Does **not** bump `last_activity_timestamp_ms` (read path).
|
|
201
232
|
*/
|
|
202
233
|
listSessions(input: ListSessionsInput): Promise<{
|
|
203
234
|
data: SessionRecord<TSessionCustom>[];
|
|
@@ -216,7 +247,8 @@ export interface ISessionStore<TSessionCustom extends object = Record<string, ne
|
|
|
216
247
|
* row or leave `last_turn_id` pointing at a turn that was never created.
|
|
217
248
|
* The implementation supplies the mechanism (session lock, row lock/tx, …).
|
|
218
249
|
*
|
|
219
|
-
* Also bumps `session.last_activity_timestamp_ms`
|
|
250
|
+
* Also bumps `session.last_activity_timestamp_ms` and increments
|
|
251
|
+
* `session.metrics.total_turns` in that same atomic unit.
|
|
220
252
|
*
|
|
221
253
|
* Fork semantics for `turn.previous_turn_id`:
|
|
222
254
|
* - `null` — new root turn (no parent); always allowed.
|
|
@@ -234,10 +266,8 @@ export interface ISessionStore<TSessionCustom extends object = Record<string, ne
|
|
|
234
266
|
*/
|
|
235
267
|
createTurn(input: CreateTurnInput<TTurnCustom>): Promise<void>;
|
|
236
268
|
/**
|
|
237
|
-
*
|
|
238
|
-
*
|
|
239
|
-
* turns skip the event insert; (c) return the now-immutable turn record.
|
|
240
|
-
* Missing turn → {@link TurnNotFoundError}.
|
|
269
|
+
* Cancel if still running (persist `turn_done` and fold cost/duration into
|
|
270
|
+
* `session.metrics`); already-terminal turns are a read. Missing → {@link TurnNotFoundError}.
|
|
241
271
|
*/
|
|
242
272
|
freezeAndGetTurn(input: FreezeAndGetTurnInput): Promise<TurnRecord<TTurnCustom>>;
|
|
243
273
|
/** Returns the turn record, or undefined if not found in this session. */
|
|
@@ -248,15 +278,9 @@ export interface ISessionStore<TSessionCustom extends object = Record<string, ne
|
|
|
248
278
|
pagination: TokenPagination;
|
|
249
279
|
}>;
|
|
250
280
|
/**
|
|
251
|
-
*
|
|
252
|
-
*
|
|
253
|
-
*
|
|
254
|
-
* - Rejected with **409** (or equivalent conflict): any write when status is already
|
|
255
|
-
* terminal — including done→cancelled, cancelled→done, error→*, terminal→running.
|
|
256
|
-
* - Missing turn → 404 / not-found.
|
|
257
|
-
*
|
|
258
|
-
* Check under the same concurrency control as other turn mutations (lock/CAS) —
|
|
259
|
-
* not a racy read-then-write outside the critical section.
|
|
281
|
+
* First terminal write wins (`running` → done/cancelled/error); otherwise 409.
|
|
282
|
+
* Winning write also folds cost/duration into `session.metrics`. Missing → 404.
|
|
283
|
+
* Must use the same lock/CAS as other turn mutations.
|
|
260
284
|
*/
|
|
261
285
|
updateTurnState(input: UpdateTurnStateInput): Promise<void>;
|
|
262
286
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ISessionStore.d.ts","sourceRoot":"","sources":["../../../src/agent-session/store/ISessionStore.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACzE,OAAO,KAAK,EAAE,iBAAiB,EAAE,2BAA2B,EAAE,MAAM,0BAA0B,CAAC;AAC/F,OAAO,KAAK,EACV,mBAAmB,EACnB,cAAc,EACd,wBAAwB,EACzB,MAAM,sCAAsC,CAAC;AAC9C,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,iCAAiC,CAAC;AAC3E,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AAC9D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAC7D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,KAAK,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAC9E,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAC7D,OAAO,KAAK,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAE7E;;;GAGG;AACH,MAAM,MAAM,kBAAkB,CAAC,cAAc,SAAS,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,IAAI,IAAI,CAC1F,aAAa,CAAC,cAAc,CAAC,EAC7B,WAAW,GAAG,YAAY,GAAG,OAAO,GAAG,
|
|
1
|
+
{"version":3,"file":"ISessionStore.d.ts","sourceRoot":"","sources":["../../../src/agent-session/store/ISessionStore.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/agent-session/store/ISessionStore.ts"],"sourcesContent":["import type { JsonValue } from '../../core/capabilities/AgentCapability';\nimport type { MCPServerInitInfo, ThreadOverwriteContextEvent } from '../../core/events/schema';\nimport type {\n AgentThreadSnapshot,\n ContextMessage,\n SubAgentCompletionMarker,\n} from '../../core/runtime/AgentThread.types';\nimport type { CurrentContextUsage } from '../../core/runtime/contextUsage';\nimport type { SandboxInfo } from '../../core/sandbox/Sandbox';\nimport type { SessionRecord } from '../models/SessionRecord';\nimport type { TurnRecord } from '../models/TurnRecord';\nimport type { PersistedTurnEvent, SessionEventItem } from '../schemas/events';\nimport type { TokenPagination } from '../schemas/pagination';\nimport type { CancellationReason, TerminalTurnState } from '../schemas/turn';\n\n/**\n * Caller-supplied fields for creating a session; the store owns timestamps and tip state.\n * `agent` is a discriminated reference | inline binding.\n */\nexport type CreateSessionInput<TSessionCustom extends object = Record<string, never>> = Pick<\n SessionRecord<TSessionCustom>,\n 'tenant_id' | 'session_id' | 'agent' | 'created_by'\n> & {\n custom: TSessionCustom | null;\n};\n\n/**\n * PATCH fields for an existing session; `undefined` fields are left unchanged.\n * `agent` may be set only on inline sessions, and only as an inline arm (`{ type: 'inline', spec }`).\n */\nexport type UpdateSessionInput<TSessionCustom extends object = Record<string, never>> = Pick<\n SessionRecord<TSessionCustom>,\n 'tenant_id' | 'session_id'\n> & {\n agent: Extract<SessionRecord<TSessionCustom>['agent'], { type: 'inline' }> | undefined;\n title: SessionRecord<TSessionCustom>['title'] | undefined;\n};\n\nexport interface GetSessionInput {\n tenant_id: string;\n session_id: string;\n}\n\nexport interface DeleteSessionInput {\n tenant_id: string;\n session_id: string;\n}\n\nexport interface ListSessionsInput {\n tenant_id: string;\n limit: number;\n page_token: string | undefined;\n order: 'asc' | 'desc' | undefined;\n /** Inclusive lower bound on `created_at` (instant). */\n start_timestamp: Date | undefined;\n /** Inclusive upper bound on `created_at` (instant). */\n end_timestamp: Date | undefined;\n /** When set, only sessions bound to this named agent id. */\n agent_id: string | undefined;\n /** When set, only sessions created by this identity. */\n created_by: string | undefined;\n}\n\n/** Turn row fields without assembled snapshot (create input / listTurns). */\nexport type TurnRecordWithoutSnapshot<TTurnCustom extends object = Record<string, never>> = Omit<\n TurnRecord<TTurnCustom>,\n 'snapshot'\n>;\n\n/** Thread registration; mutable per-turn data arrives through dedicated createTurn fields. */\nexport type NewThreadInit = Omit<\n AgentThreadSnapshot,\n 'context' | 'current_context_usage' | 'completion' | 'capability_state'\n>;\n\n/** Full post-send capability map for one thread. */\nexport type ThreadCapabilityStateInit = Pick<AgentThreadSnapshot, 'thread_id' | 'capability_state'>;\n\n/** One drained send() append batch for one thread; writer = the new turn. */\nexport interface TurnContextAppend {\n thread_id: string;\n context: ContextMessage[];\n current_context_usage: CurrentContextUsage | null;\n}\n\nexport interface CreateTurnInput<TTurnCustom extends object = Record<string, never>> {\n turn: TurnRecordWithoutSnapshot<TTurnCustom>;\n /** Threads absent on the previous turn (turn 1: the root thread; else empty). */\n new_threads: NewThreadInit[];\n /**\n * All new messages, for new and carried-forward threads alike — collected by\n * draining orchestrator.send() BEFORE this call. Draining without persisting is\n * safe: send() mutates only in-memory threads, and if createTurn fails the whole\n * in-memory state (orchestrator, threads, resolver) is discarded — so either this\n * turn commits atomically with its appends, or nothing was persisted at all.\n */\n new_context_appends: TurnContextAppend[];\n /**\n * Complete post-send capability maps: exactly one entry per turn thread.\n * Authoritative for this turn; the store does not carry capability rows forward.\n */\n capability_states: ThreadCapabilityStateInit[];\n /** Set only if session.title is NULL (first write wins). */\n update_session_title_if_not_exist: string | null;\n}\n\nexport interface FreezeAndGetTurnInput {\n session_id: string;\n turn_id: string;\n /** Written onto the turn row when the freeze actually cancels a running turn. */\n reason: CancellationReason;\n /** Caller-built cancelled turn.done event; store persists atomically with state flip when it cancels. */\n turn_done_event: PersistedTurnEvent;\n}\n\nexport interface GetTurnInput {\n session_id: string;\n turn_id: string;\n}\n\nexport interface ListTurnsInput {\n session_id: string;\n limit: number;\n page_token: string | undefined;\n}\n\nexport interface UpdateTurnStateInput {\n session_id: string;\n turn_id: string;\n state: TerminalTurnState;\n /** Caller-built turn.done; written atomically with the state flip in the same tx. */\n turn_done_event: PersistedTurnEvent;\n}\n\nexport interface AppendToEventsInput {\n session_id: string;\n turn_id: string;\n events: PersistedTurnEvent[];\n}\n\nexport interface AddThreadsInput {\n session_id: string;\n turn_id: string;\n threads: AgentThreadSnapshot[];\n}\n\nexport interface RemoveThreadsInput {\n session_id: string;\n turn_id: string;\n thread_ids: string[];\n}\n\nexport interface AppendToThreadContextInput {\n session_id: string;\n turn_id: string;\n thread_id: string;\n context: ContextMessage[];\n current_context_usage: CurrentContextUsage | null;\n completion: SubAgentCompletionMarker | null;\n}\n\nexport interface OverwriteThreadContextInput {\n session_id: string;\n turn_id: string;\n event: ThreadOverwriteContextEvent;\n}\n\nexport interface PatchMCPServersInput {\n session_id: string;\n turn_id: string;\n mcp_servers: MCPServerInitInfo[];\n}\n\nexport interface PatchSandboxInfoInput {\n session_id: string;\n turn_id: string;\n sandbox_info: SandboxInfo;\n}\n\nexport interface PatchThreadCapabilityStateInput {\n session_id: string;\n turn_id: string;\n thread_id: string;\n key: string;\n state: JsonValue;\n}\n\nexport interface ListTurnEventsInput {\n session_id: string;\n turn_id: string;\n limit: number;\n page_token: string | undefined;\n order: 'asc' | 'desc' | undefined;\n}\n\nexport interface ListSessionEventsInput {\n session_id: string;\n limit: number;\n page_token: string | undefined;\n last_turn_id: string | undefined;\n}\n\n/**\n * Session/turn persistence contract. Pure durability: no streaming, SSE, or\n * subscription members. Callers authorize the parent session before using\n * turn-scoped operations, which rely on globally unique session_id values.\n * Capability maps are initialized atomically by createTurn and subsequently\n * updated through patchThreadCapabilityState. Agent binding is session-scoped\n * as a discriminated `agent` (ref | value); named agents are not hydrated on read.\n */\nexport interface ISessionStore<\n TSessionCustom extends object = Record<string, never>,\n TTurnCustom extends object = Record<string, never>,\n> {\n /**\n * Persists a discriminated `agent` (ref | value). SQL backends may flatten to columns.\n * `session_id` is globally unique across tenants.\n * Persists caller-supplied `created_by` (immutable after create).\n * Sets `last_activity_timestamp_ms` (= now) on create.\n */\n createSession(input: CreateSessionInput<TSessionCustom>): Promise<void>;\n\n /** Permanently removes a session and all related data; missing sessions are a no-op. */\n deleteSession(input: DeleteSessionInput): Promise<void>;\n\n /**\n * Returns the session as stored (ref agents are not hydrated to a value).\n * Does **not** bump `last_activity_timestamp_ms` (read path).\n */\n getSession(input: GetSessionInput): Promise<SessionRecord<TSessionCustom> | undefined>;\n\n /**\n * PATCH semantics — update only the provided fields:\n * - agent: replace inline binding (inline sessions only; reference → invariant error).\n * - title: set/replace the session title.\n * Bumps `last_activity_timestamp_ms` (= now) in the same update.\n */\n updateSession(input: UpdateSessionInput<TSessionCustom>): Promise<void>;\n\n /**\n * Paginated list of the tenant's sessions ordered by `updated_at`\n * (`order` defaults to `desc`, `session_id` tie-break). `page_token` is a\n * keyset cursor on `(updated_at, session_id)`. `start_timestamp` /\n * `end_timestamp` are inclusive instant bounds on `created_at`. Optional\n * `agent_id` filters ref-bound sessions; optional `created_by` filters by\n * creator identity. Does **not** bump `last_activity_timestamp_ms` (read path).\n */\n listSessions(\n input: ListSessionsInput,\n ): Promise<{ data: SessionRecord<TSessionCustom>[]; pagination: TokenPagination }>;\n\n /**\n * Creates the turn AND advances `session.last_turn_id`. Context merging is the\n * store's responsibility: `new_context_appends` and `new_threads` are applied\n * on top of the previous turn's snapshot when `turn.previous_turn_id` is set.\n * `capability_states` is the complete authoritative map for every resulting\n * thread and is persisted directly without store-side carry-forward.\n *\n * Atomicity (store contract): insert turn + set `last_turn_id` (+ session\n * turn-list append if the backend has one) MUST be one atomic unit per\n * session. Concurrent createTurn on the same session must not drop a turn\n * row or leave `last_turn_id` pointing at a turn that was never created.\n * The implementation supplies the mechanism (session lock, row lock/tx, …).\n *\n * Also bumps `session.last_activity_timestamp_ms` in that same atomic unit.\n *\n * Fork semantics for `turn.previous_turn_id`:\n * - `null` — new root turn (no parent); always allowed.\n * - string — fork/chain from that turn when it exists. Tip-equality is NOT\n * required; concurrent forks from the same tip both succeed. Unknown id is\n * allowed (relaxed) and treated as no inheritance. If that turn exists and\n * is still `running`, reject with {@link PreviousTurnRunningError} —\n * callers must {@link freezeAndGetTurn} first.\n * `last_turn_id` always advances to the new turn in the same atomic unit.\n *\n * `update_session_title_if_not_exist`: when set AND `session.title` is\n * unset/null, set it in the same atomic unit; an existing title is NEVER\n * overwritten (first write wins). The caller derives the value; the store\n * only conditionally sets it.\n */\n createTurn(input: CreateTurnInput<TTurnCustom>): Promise<void>;\n\n /**\n * One tx: (a) conditionally cancel a running turn with `reason`; (b) if it\n * did cancel, insert the caller-built `turn_done_event` — already-terminal\n * turns skip the event insert; (c) return the now-immutable turn record.\n * Missing turn → {@link TurnNotFoundError}.\n */\n freezeAndGetTurn(input: FreezeAndGetTurnInput): Promise<TurnRecord<TTurnCustom>>;\n\n /** Returns the turn record, or undefined if not found in this session. */\n getTurn(input: GetTurnInput): Promise<TurnRecord<TTurnCustom> | undefined>;\n\n /** Paginated list of turn rows (no snapshot); use getTurn for assembled snapshot. */\n listTurns(\n input: ListTurnsInput,\n ): Promise<{ data: TurnRecordWithoutSnapshot<TTurnCustom>[]; pagination: TokenPagination }>;\n\n /**\n * Writes the terminal state and `turn_done_event` atomically. Store contract —\n * **first terminal write wins**:\n * - Allowed: `running` → `done` | `cancelled` | `error`.\n * - Rejected with **409** (or equivalent conflict): any write when status is already\n * terminal — including done→cancelled, cancelled→done, error→*, terminal→running.\n * - Missing turn → 404 / not-found.\n *\n * Check under the same concurrency control as other turn mutations (lock/CAS) —\n * not a racy read-then-write outside the critical section.\n */\n updateTurnState(input: UpdateTurnStateInput): Promise<void>;\n\n /**\n * Durable event log for the turn. MUST include lifecycle rows: a\n * `TurnCreatedEvent` at the start of the stream and a terminal `TurnDoneEvent`\n * (or its cancelled/error shape) at the end. Every turn written through this\n * API persists lifecycle in the stream — implementations never synthesize\n * missing created/done rows on read. Every event MUST carry `id` and\n * `created_at`; `id` is a monotonic ULID and is the primary within-turn sort\n * key. `created_at` records event creation time but is not the order key.\n */\n appendToEvents(input: AppendToEventsInput): Promise<void>;\n\n /** Adds thread snapshots to the turn (sub-agent spawns). */\n addThreads(input: AddThreadsInput): Promise<void>;\n\n /** Removes threads from the turn by id. */\n removeThreads(input: RemoveThreadsInput): Promise<void>;\n\n /** Appends messages to a thread's context; optionally updates usage / completion marker. */\n appendToThreadContext(input: AppendToThreadContextInput): Promise<void>;\n\n /** Replaces a thread's context wholesale (context-overwrite event). */\n overwriteThreadContext(input: OverwriteThreadContextInput): Promise<void>;\n\n /** Patches the turn snapshot's MCP server init info (by source id). */\n patchMCPServers(input: PatchMCPServersInput): Promise<void>;\n\n /** Patches the turn snapshot's sandbox info (id for cross-turn reattach). */\n patchSandboxInfo(input: PatchSandboxInfoInput): Promise<void>;\n\n /** Generic capability KV — store has zero Plan/feature knowledge. */\n patchThreadCapabilityState(input: PatchThreadCapabilityStateInput): Promise<void>;\n\n /** Paginated read ordered lexically by monotonic `event.id` (asc default). */\n listTurnEvents(input: ListTurnEventsInput): Promise<{\n data: PersistedTurnEvent[];\n pagination: TokenPagination;\n }>;\n\n /**\n * Paginated session-wide feed of persisted events across turns, including\n * turn.created / turn.done lifecycle rows. Reads only — never synthesizes.\n *\n * Includes events from **running** turns (the HTTP layer may 409 separately;\n * that is not store semantics). Ordering: newest turn first, then monotonic\n * `event.id` descending within each turn. `last_turn_id` anchors the window\n * to that turn plus its ancestors; when omitted, the session's current\n * `last_turn_id` selects the active branch. Continuation page tokens encode\n * that anchor and take precedence over `last_turn_id`, so later session\n * activity cannot move an in-progress pagination walk to another branch.\n * `ancestor_ids` may include only the previous N ancestors and need not reach\n * the root — implementations must spill through older turns' own\n * `ancestor_ids` when needed. Sibling branches from forks are excluded.\n */\n listSessionEvents(input: ListSessionEventsInput): Promise<{\n data: SessionEventItem[];\n pagination: TokenPagination;\n }>;\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAAA;AAAA;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../src/agent-session/store/ISessionStore.ts"],"sourcesContent":["import type { JsonValue } from '../../core/capabilities/AgentCapability';\nimport type { MCPServerInitInfo, ThreadOverwriteContextEvent } from '../../core/events/schema';\nimport type {\n AgentThreadSnapshot,\n ContextMessage,\n SubAgentCompletionMarker,\n} from '../../core/runtime/AgentThread.types';\nimport type { CurrentContextUsage } from '../../core/runtime/contextUsage';\nimport type { SandboxInfo } from '../../core/sandbox/Sandbox';\nimport type { SessionRecord } from '../models/SessionRecord';\nimport type { TurnRecord } from '../models/TurnRecord';\nimport type { PersistedTurnEvent, SessionEventItem } from '../schemas/events';\nimport type { TokenPagination } from '../schemas/pagination';\nimport type { SessionMetadata } from '../schemas/session';\nimport type { CancellationReason, TerminalTurnState } from '../schemas/turn';\n\n/**\n * Caller-supplied fields for creating a session; the store owns timestamps and tip state.\n * `agent` is a discriminated reference | inline binding.\n */\nexport type CreateSessionInput<TSessionCustom extends object = Record<string, never>> = Pick<\n SessionRecord<TSessionCustom>,\n 'tenant_id' | 'session_id' | 'agent' | 'created_by_subject' | 'external_id' | 'metadata' | 'source'\n> & {\n custom: TSessionCustom | null;\n};\n\n/**\n * PATCH fields for an existing session; `undefined` fields are left unchanged.\n * `agent` may be set only on inline sessions, and only as an inline arm (`{ type: 'inline', spec }`).\n * `metadata` when set fully replaces the stored map (`{}` clears).\n */\nexport type UpdateSessionInput<TSessionCustom extends object = Record<string, never>> = Pick<\n SessionRecord<TSessionCustom>,\n 'tenant_id' | 'session_id'\n> & {\n agent: Extract<SessionRecord<TSessionCustom>['agent'], { type: 'inline' }> | undefined;\n title: SessionRecord<TSessionCustom>['title'] | undefined;\n metadata: SessionRecord<TSessionCustom>['metadata'] | undefined;\n};\n\nexport interface GetSessionInput {\n tenant_id: string;\n session_id: string;\n}\n\nexport interface GetSessionByExternalIdInput {\n tenant_id: string;\n external_id: string;\n}\n\nexport interface DeleteSessionInput {\n tenant_id: string;\n session_id: string;\n}\n\nexport interface ListSessionsInput {\n tenant_id: string;\n limit: number;\n page_token: string | undefined;\n order: 'asc' | 'desc' | undefined;\n /** Inclusive lower bound on `created_at` (instant). */\n start_timestamp: Date | undefined;\n /** Inclusive upper bound on `created_at` (instant). */\n end_timestamp: Date | undefined;\n /** When set, only sessions bound to this named agent id. */\n agent_id: string | undefined;\n /** When set, match creator or named-agent binding. Empty `agent_ids` means creator-only. */\n created_by_or_agent_ids:\n | {\n created_by_subject_id: string;\n agent_ids: readonly string[];\n }\n | undefined;\n /**\n * When set, only sessions whose metadata contains all key/value pairs\n * (exact string equality; extra session keys are allowed).\n * `undefined` means no metadata filter; `{}` matches only sessions with empty metadata.\n */\n metadata: SessionMetadata | undefined;\n /** When set, only sessions whose `source.type` matches. */\n source_type: string | undefined;\n /**\n * When set, only sessions whose `source.id` matches.\n * Requires `source_type`.\n */\n source_id: string | undefined;\n}\n\n/** Turn row fields without assembled snapshot (create input / listTurns). */\nexport type TurnRecordWithoutSnapshot<TTurnCustom extends object = Record<string, never>> = Omit<\n TurnRecord<TTurnCustom>,\n 'snapshot'\n>;\n\n/** Thread registration; mutable per-turn data arrives through dedicated createTurn fields. */\nexport type NewThreadInit = Omit<\n AgentThreadSnapshot,\n 'context' | 'current_context_usage' | 'completion' | 'capability_state'\n>;\n\n/** Full post-send capability map for one thread. */\nexport type ThreadCapabilityStateInit = Pick<AgentThreadSnapshot, 'thread_id' | 'capability_state'>;\n\n/** One drained send() append batch for one thread; writer = the new turn. */\nexport interface TurnContextAppend {\n thread_id: string;\n context: ContextMessage[];\n current_context_usage: CurrentContextUsage | null;\n}\n\nexport interface CreateTurnInput<TTurnCustom extends object = Record<string, never>> {\n turn: TurnRecordWithoutSnapshot<TTurnCustom>;\n /** Threads absent on the previous turn (turn 1: the root thread; else empty). */\n new_threads: NewThreadInit[];\n /**\n * All new messages, for new and carried-forward threads alike — collected by\n * draining orchestrator.send() BEFORE this call. Draining without persisting is\n * safe: send() mutates only in-memory threads, and if createTurn fails the whole\n * in-memory state (orchestrator, threads, resolver) is discarded — so either this\n * turn commits atomically with its appends, or nothing was persisted at all.\n */\n new_context_appends: TurnContextAppend[];\n /**\n * Complete post-send capability maps: exactly one entry per turn thread.\n * Authoritative for this turn; the store does not carry capability rows forward.\n */\n capability_states: ThreadCapabilityStateInit[];\n /** Set only if session.title is NULL (first write wins). */\n update_session_title_if_not_exist: string | null;\n}\n\nexport interface FreezeAndGetTurnInput {\n session_id: string;\n turn_id: string;\n /** Written onto the turn row when the freeze actually cancels a running turn. */\n reason: CancellationReason;\n /** Caller-built cancelled turn.done event; store persists atomically with state flip when it cancels. */\n turn_done_event: PersistedTurnEvent;\n}\n\nexport interface GetTurnInput {\n session_id: string;\n turn_id: string;\n}\n\nexport interface ListTurnsInput {\n session_id: string;\n limit: number;\n page_token: string | undefined;\n}\n\nexport interface UpdateTurnStateInput {\n session_id: string;\n turn_id: string;\n state: TerminalTurnState;\n /** Caller-built turn.done; written atomically with the state flip in the same tx. */\n turn_done_event: PersistedTurnEvent;\n}\n\nexport interface AppendToEventsInput {\n session_id: string;\n turn_id: string;\n events: PersistedTurnEvent[];\n}\n\nexport interface AddThreadsInput {\n session_id: string;\n turn_id: string;\n threads: AgentThreadSnapshot[];\n}\n\nexport interface RemoveThreadsInput {\n session_id: string;\n turn_id: string;\n thread_ids: string[];\n}\n\nexport interface AppendToThreadContextInput {\n session_id: string;\n turn_id: string;\n thread_id: string;\n context: ContextMessage[];\n current_context_usage: CurrentContextUsage | null;\n completion: SubAgentCompletionMarker | null;\n}\n\nexport interface OverwriteThreadContextInput {\n session_id: string;\n turn_id: string;\n event: ThreadOverwriteContextEvent;\n}\n\nexport interface PatchMCPServersInput {\n session_id: string;\n turn_id: string;\n mcp_servers: MCPServerInitInfo[];\n}\n\nexport interface PatchSandboxInfoInput {\n session_id: string;\n turn_id: string;\n sandbox_info: SandboxInfo;\n}\n\nexport interface PatchThreadCapabilityStateInput {\n session_id: string;\n turn_id: string;\n thread_id: string;\n key: string;\n state: JsonValue;\n}\n\nexport interface ListTurnEventsInput {\n session_id: string;\n turn_id: string;\n limit: number;\n page_token: string | undefined;\n order: 'asc' | 'desc' | undefined;\n}\n\nexport interface ListSessionEventsInput {\n session_id: string;\n limit: number;\n page_token: string | undefined;\n last_turn_id: string | undefined;\n}\n\n/**\n * Session/turn persistence contract. Pure durability: no streaming, SSE, or\n * subscription members. Callers authorize the parent session before using\n * turn-scoped operations, which rely on globally unique session_id values.\n * Capability maps are initialized atomically by createTurn and subsequently\n * updated through patchThreadCapabilityState. Agent binding is session-scoped\n * as a discriminated `agent` (ref | value); named agents are not hydrated on read.\n */\nexport interface ISessionStore<\n TSessionCustom extends object = Record<string, never>,\n TTurnCustom extends object = Record<string, never>,\n> {\n /**\n * Persists a discriminated `agent` (ref | value). SQL backends may flatten to columns.\n * `session_id` is globally unique across tenants.\n * Persists caller-supplied `created_by_subject` (immutable after create).\n * Sets `last_activity_timestamp_ms` (= now) on create.\n */\n createSession(input: CreateSessionInput<TSessionCustom>): Promise<void>;\n\n /** Permanently removes a session and all related data; missing sessions are a no-op. */\n deleteSession(input: DeleteSessionInput): Promise<void>;\n\n /**\n * Returns the session as stored (ref agents are not hydrated to a value).\n * Does **not** bump `last_activity_timestamp_ms` (read path).\n */\n getSession(input: GetSessionInput): Promise<SessionRecord<TSessionCustom> | undefined>;\n\n /**\n * Lookup by tenant-scoped `external_id`. Missing or null external ids are not found.\n * Does **not** bump `last_activity_timestamp_ms` (read path).\n */\n getSessionByExternalId(input: GetSessionByExternalIdInput): Promise<SessionRecord<TSessionCustom> | undefined>;\n\n /**\n * PATCH semantics — update only the provided fields:\n * - agent: replace inline binding (inline sessions only; reference → invariant error).\n * - title: set/replace the session title.\n * - metadata: full replace of the caller-owned string map when set.\n * Bumps `last_activity_timestamp_ms` (= now) in the same update.\n */\n updateSession(input: UpdateSessionInput<TSessionCustom>): Promise<void>;\n\n /**\n * Paginated list of the tenant's sessions ordered by `updated_at`\n * (`order` defaults to `desc`, `session_id` tie-break). `page_token` is a\n * keyset cursor on `(updated_at, session_id)`. `start_timestamp` /\n * `end_timestamp` are inclusive instant bounds on `created_at`. Optional\n * `agent_id` filters ref-bound sessions. `created_by_or_agent_ids` matches\n * rows created by its subject OR bound to one of its agent ids; optional\n * `source_type` / `source_id` filter by JSON `source` (expression-indexed,\n * no scalar columns). Does **not** bump `last_activity_timestamp_ms` (read path).\n */\n listSessions(\n input: ListSessionsInput,\n ): Promise<{ data: SessionRecord<TSessionCustom>[]; pagination: TokenPagination }>;\n\n /**\n * Creates the turn AND advances `session.last_turn_id`. Context merging is the\n * store's responsibility: `new_context_appends` and `new_threads` are applied\n * on top of the previous turn's snapshot when `turn.previous_turn_id` is set.\n * `capability_states` is the complete authoritative map for every resulting\n * thread and is persisted directly without store-side carry-forward.\n *\n * Atomicity (store contract): insert turn + set `last_turn_id` (+ session\n * turn-list append if the backend has one) MUST be one atomic unit per\n * session. Concurrent createTurn on the same session must not drop a turn\n * row or leave `last_turn_id` pointing at a turn that was never created.\n * The implementation supplies the mechanism (session lock, row lock/tx, …).\n *\n * Also bumps `session.last_activity_timestamp_ms` and increments\n * `session.metrics.total_turns` in that same atomic unit.\n *\n * Fork semantics for `turn.previous_turn_id`:\n * - `null` — new root turn (no parent); always allowed.\n * - string — fork/chain from that turn when it exists. Tip-equality is NOT\n * required; concurrent forks from the same tip both succeed. Unknown id is\n * allowed (relaxed) and treated as no inheritance. If that turn exists and\n * is still `running`, reject with {@link PreviousTurnRunningError} —\n * callers must {@link freezeAndGetTurn} first.\n * `last_turn_id` always advances to the new turn in the same atomic unit.\n *\n * `update_session_title_if_not_exist`: when set AND `session.title` is\n * unset/null, set it in the same atomic unit; an existing title is NEVER\n * overwritten (first write wins). The caller derives the value; the store\n * only conditionally sets it.\n */\n createTurn(input: CreateTurnInput<TTurnCustom>): Promise<void>;\n\n /**\n * Cancel if still running (persist `turn_done` and fold cost/duration into\n * `session.metrics`); already-terminal turns are a read. Missing → {@link TurnNotFoundError}.\n */\n freezeAndGetTurn(input: FreezeAndGetTurnInput): Promise<TurnRecord<TTurnCustom>>;\n\n /** Returns the turn record, or undefined if not found in this session. */\n getTurn(input: GetTurnInput): Promise<TurnRecord<TTurnCustom> | undefined>;\n\n /** Paginated list of turn rows (no snapshot); use getTurn for assembled snapshot. */\n listTurns(\n input: ListTurnsInput,\n ): Promise<{ data: TurnRecordWithoutSnapshot<TTurnCustom>[]; pagination: TokenPagination }>;\n\n /**\n * First terminal write wins (`running` → done/cancelled/error); otherwise 409.\n * Winning write also folds cost/duration into `session.metrics`. Missing → 404.\n * Must use the same lock/CAS as other turn mutations.\n */\n updateTurnState(input: UpdateTurnStateInput): Promise<void>;\n\n /**\n * Durable event log for the turn. MUST include lifecycle rows: a\n * `TurnCreatedEvent` at the start of the stream and a terminal `TurnDoneEvent`\n * (or its cancelled/error shape) at the end. Every turn written through this\n * API persists lifecycle in the stream — implementations never synthesize\n * missing created/done rows on read. Every event MUST carry `id` and\n * `created_at`; `id` is a monotonic ULID and is the primary within-turn sort\n * key. `created_at` records event creation time but is not the order key.\n */\n appendToEvents(input: AppendToEventsInput): Promise<void>;\n\n /** Adds thread snapshots to the turn (sub-agent spawns). */\n addThreads(input: AddThreadsInput): Promise<void>;\n\n /** Removes threads from the turn by id. */\n removeThreads(input: RemoveThreadsInput): Promise<void>;\n\n /** Appends messages to a thread's context; optionally updates usage / completion marker. */\n appendToThreadContext(input: AppendToThreadContextInput): Promise<void>;\n\n /** Replaces a thread's context wholesale (context-overwrite event). */\n overwriteThreadContext(input: OverwriteThreadContextInput): Promise<void>;\n\n /** Patches the turn snapshot's MCP server init info (by source id). */\n patchMCPServers(input: PatchMCPServersInput): Promise<void>;\n\n /** Patches the turn snapshot's sandbox info (id for cross-turn reattach). */\n patchSandboxInfo(input: PatchSandboxInfoInput): Promise<void>;\n\n /** Generic capability KV — store has zero Plan/feature knowledge. */\n patchThreadCapabilityState(input: PatchThreadCapabilityStateInput): Promise<void>;\n\n /** Paginated read ordered lexically by monotonic `event.id` (asc default). */\n listTurnEvents(input: ListTurnEventsInput): Promise<{\n data: PersistedTurnEvent[];\n pagination: TokenPagination;\n }>;\n\n /**\n * Paginated session-wide feed of persisted events across turns, including\n * turn.created / turn.done lifecycle rows. Reads only — never synthesizes.\n *\n * Includes events from **running** turns (the HTTP layer may 409 separately;\n * that is not store semantics). Ordering: newest turn first, then monotonic\n * `event.id` descending within each turn. `last_turn_id` anchors the window\n * to that turn plus its ancestors; when omitted, the session's current\n * `last_turn_id` selects the active branch. Continuation page tokens encode\n * that anchor and take precedence over `last_turn_id`, so later session\n * activity cannot move an in-progress pagination walk to another branch.\n * `ancestor_ids` may include only the previous N ancestors and need not reach\n * the root — implementations must spill through older turns' own\n * `ancestor_ids` when needed. Sibling branches from forks are excluded.\n */\n listSessionEvents(input: ListSessionEventsInput): Promise<{\n data: SessionEventItem[];\n pagination: TokenPagination;\n }>;\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAAA;AAAA;","names":[]}
|
|
@@ -2,7 +2,7 @@ import type { SessionRecord } from '../models/SessionRecord';
|
|
|
2
2
|
import type { TurnRecord } from '../models/TurnRecord';
|
|
3
3
|
import type { PersistedTurnEvent, SessionEventItem } from '../schemas/events';
|
|
4
4
|
import type { TokenPagination } from '../schemas/pagination';
|
|
5
|
-
import type { AddThreadsInput, AppendToEventsInput, AppendToThreadContextInput, CreateSessionInput, CreateTurnInput, DeleteSessionInput, FreezeAndGetTurnInput, GetSessionInput, GetTurnInput, ISessionStore, ListSessionEventsInput, ListSessionsInput, ListTurnEventsInput, ListTurnsInput, OverwriteThreadContextInput, PatchMCPServersInput, PatchSandboxInfoInput, PatchThreadCapabilityStateInput, RemoveThreadsInput, TurnRecordWithoutSnapshot, UpdateSessionInput, UpdateTurnStateInput } from './ISessionStore';
|
|
5
|
+
import type { AddThreadsInput, AppendToEventsInput, AppendToThreadContextInput, CreateSessionInput, CreateTurnInput, DeleteSessionInput, FreezeAndGetTurnInput, GetSessionByExternalIdInput, GetSessionInput, GetTurnInput, ISessionStore, ListSessionEventsInput, ListSessionsInput, ListTurnEventsInput, ListTurnsInput, OverwriteThreadContextInput, PatchMCPServersInput, PatchSandboxInfoInput, PatchThreadCapabilityStateInput, RemoveThreadsInput, TurnRecordWithoutSnapshot, UpdateSessionInput, UpdateTurnStateInput } from './ISessionStore';
|
|
6
6
|
/**
|
|
7
7
|
* Reference ISessionStore implementation. Proves the contract without SSE/subscription
|
|
8
8
|
* hooks. Deep-copies on read/write boundaries so callers cannot mutate stored state.
|
|
@@ -14,6 +14,7 @@ export declare class InMemorySessionStore<TSessionCustom extends object = Record
|
|
|
14
14
|
createSession(input: CreateSessionInput<TSessionCustom>): Promise<void>;
|
|
15
15
|
deleteSession(input: DeleteSessionInput): Promise<void>;
|
|
16
16
|
getSession(input: GetSessionInput): Promise<SessionRecord<TSessionCustom> | undefined>;
|
|
17
|
+
getSessionByExternalId(input: GetSessionByExternalIdInput): Promise<SessionRecord<TSessionCustom> | undefined>;
|
|
17
18
|
updateSession(input: UpdateSessionInput<TSessionCustom>): Promise<void>;
|
|
18
19
|
listSessions(input: ListSessionsInput): Promise<{
|
|
19
20
|
data: SessionRecord<TSessionCustom>[];
|
|
@@ -28,6 +29,8 @@ export declare class InMemorySessionStore<TSessionCustom extends object = Record
|
|
|
28
29
|
}>;
|
|
29
30
|
updateTurnState(input: UpdateTurnStateInput): Promise<void>;
|
|
30
31
|
appendToEvents(input: AppendToEventsInput): Promise<void>;
|
|
32
|
+
/** Cost from turn metrics when present; duration is completed_at − created_at, floored at 0. */
|
|
33
|
+
private addTerminalSessionMetrics;
|
|
31
34
|
private requireTurn;
|
|
32
35
|
private requireRunningTurn;
|
|
33
36
|
addThreads(input: AddThreadsInput): Promise<void>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"InMemorySessionStore.d.ts","sourceRoot":"","sources":["../../../src/agent-session/store/InMemorySessionStore.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAC7D,OAAO,KAAK,EAAE,UAAU,EAAgB,MAAM,sBAAsB,CAAC;AACrE,OAAO,KAAK,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAC9E,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAG7D,OAAO,KAAK,EACV,eAAe,EACf,mBAAmB,EACnB,0BAA0B,EAC1B,kBAAkB,EAClB,eAAe,EACf,kBAAkB,EAClB,qBAAqB,EACrB,eAAe,EACf,YAAY,EACZ,aAAa,EACb,sBAAsB,EACtB,iBAAiB,EACjB,mBAAmB,EACnB,cAAc,EAEd,2BAA2B,EAC3B,oBAAoB,EACpB,qBAAqB,EACrB,+BAA+B,EAC/B,kBAAkB,EAElB,yBAAyB,EACzB,kBAAkB,EAClB,oBAAoB,EACrB,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"InMemorySessionStore.d.ts","sourceRoot":"","sources":["../../../src/agent-session/store/InMemorySessionStore.ts"],"names":[],"mappings":"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"}
|
|
@@ -116,17 +116,32 @@ var InMemorySessionStore = class {
|
|
|
116
116
|
if (this.sessions.has(key)) {
|
|
117
117
|
throw new import_SessionStoreErrors.SessionAlreadyExistsError(input.session_id);
|
|
118
118
|
}
|
|
119
|
+
const externalId = input.external_id;
|
|
120
|
+
if (externalId !== null) {
|
|
121
|
+
for (const stored of this.sessions.values()) {
|
|
122
|
+
if (stored.record.tenant_id === input.tenant_id && stored.record.external_id === externalId) {
|
|
123
|
+
throw new import_SessionStoreErrors.SessionExternalIdConflictError(externalId);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
119
127
|
const now = /* @__PURE__ */ new Date();
|
|
120
128
|
const record = {
|
|
121
129
|
tenant_id: input.tenant_id,
|
|
122
130
|
session_id: input.session_id,
|
|
123
|
-
|
|
131
|
+
created_by_subject: input.created_by_subject,
|
|
124
132
|
agent: deepCopy(input.agent),
|
|
125
133
|
title: null,
|
|
126
134
|
last_turn_id: null,
|
|
135
|
+
external_id: externalId,
|
|
136
|
+
source: input.source !== null ? deepCopy(input.source) : null,
|
|
127
137
|
created_at: now,
|
|
128
138
|
updated_at: now,
|
|
129
139
|
last_activity_timestamp_ms: Date.now(),
|
|
140
|
+
metrics: {
|
|
141
|
+
total_duration_ms: 0,
|
|
142
|
+
total_turns: 0
|
|
143
|
+
},
|
|
144
|
+
metadata: deepCopy(input.metadata),
|
|
130
145
|
custom: input.custom !== null ? deepCopy(input.custom) : null
|
|
131
146
|
};
|
|
132
147
|
this.sessions.set(key, { record, turnIds: [] });
|
|
@@ -149,6 +164,14 @@ var InMemorySessionStore = class {
|
|
|
149
164
|
const stored = this.sessions.get(sessionKey(input.session_id));
|
|
150
165
|
return stored?.record.tenant_id === input.tenant_id ? deepCopy(stored.record) : void 0;
|
|
151
166
|
}
|
|
167
|
+
async getSessionByExternalId(input) {
|
|
168
|
+
for (const stored of this.sessions.values()) {
|
|
169
|
+
if (stored.record.tenant_id === input.tenant_id && stored.record.external_id === input.external_id) {
|
|
170
|
+
return deepCopy(stored.record);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
return void 0;
|
|
174
|
+
}
|
|
152
175
|
async updateSession(input) {
|
|
153
176
|
const key = sessionKey(input.session_id);
|
|
154
177
|
const stored = this.sessions.get(key);
|
|
@@ -164,6 +187,9 @@ var InMemorySessionStore = class {
|
|
|
164
187
|
if (input.title !== void 0) {
|
|
165
188
|
stored.record.title = input.title;
|
|
166
189
|
}
|
|
190
|
+
if (input.metadata !== void 0) {
|
|
191
|
+
stored.record.metadata = deepCopy(input.metadata);
|
|
192
|
+
}
|
|
167
193
|
const now = Date.now();
|
|
168
194
|
stored.record.updated_at = new Date(now);
|
|
169
195
|
stored.record.last_activity_timestamp_ms = now;
|
|
@@ -171,6 +197,7 @@ var InMemorySessionStore = class {
|
|
|
171
197
|
}
|
|
172
198
|
async listSessions(input) {
|
|
173
199
|
const records = [];
|
|
200
|
+
const createdByOrAgentIds = input.created_by_or_agent_ids;
|
|
174
201
|
for (const stored of this.sessions.values()) {
|
|
175
202
|
if (stored.record.tenant_id !== input.tenant_id) {
|
|
176
203
|
continue;
|
|
@@ -178,7 +205,28 @@ var InMemorySessionStore = class {
|
|
|
178
205
|
if (input.agent_id !== void 0 && (stored.record.agent.type !== "reference" || stored.record.agent.id !== input.agent_id)) {
|
|
179
206
|
continue;
|
|
180
207
|
}
|
|
181
|
-
if (
|
|
208
|
+
if (createdByOrAgentIds !== void 0) {
|
|
209
|
+
const creatorMatches = stored.record.created_by_subject.subject_id === createdByOrAgentIds.created_by_subject_id;
|
|
210
|
+
const agentMatches = stored.record.agent.type === "reference" && createdByOrAgentIds.agent_ids.includes(stored.record.agent.id);
|
|
211
|
+
if (!creatorMatches && !agentMatches) {
|
|
212
|
+
continue;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
const metadataFilter = input.metadata;
|
|
216
|
+
if (metadataFilter !== void 0) {
|
|
217
|
+
const entries = Object.entries(metadataFilter);
|
|
218
|
+
if (entries.length === 0) {
|
|
219
|
+
if (Object.keys(stored.record.metadata).length > 0) {
|
|
220
|
+
continue;
|
|
221
|
+
}
|
|
222
|
+
} else if (!entries.every(([key, value]) => stored.record.metadata[key] === value)) {
|
|
223
|
+
continue;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
if (input.source_type !== void 0 && stored.record.source?.type !== input.source_type) {
|
|
227
|
+
continue;
|
|
228
|
+
}
|
|
229
|
+
if (input.source_id !== void 0 && stored.record.source?.id !== input.source_id) {
|
|
182
230
|
continue;
|
|
183
231
|
}
|
|
184
232
|
const createdAt = stored.record.created_at.getTime();
|
|
@@ -250,6 +298,7 @@ var InMemorySessionStore = class {
|
|
|
250
298
|
this.events.set(tKey, []);
|
|
251
299
|
stored.turnIds.push(input.turn.turn_id);
|
|
252
300
|
stored.record.last_turn_id = input.turn.turn_id;
|
|
301
|
+
stored.record.metrics.total_turns += 1;
|
|
253
302
|
stored.record.last_activity_timestamp_ms = Date.now();
|
|
254
303
|
stored.record.updated_at = /* @__PURE__ */ new Date();
|
|
255
304
|
if (input.update_session_title_if_not_exist !== null && stored.record.title === null) {
|
|
@@ -271,6 +320,7 @@ var InMemorySessionStore = class {
|
|
|
271
320
|
if (list) {
|
|
272
321
|
list.push(deepCopy(input.turn_done_event));
|
|
273
322
|
}
|
|
323
|
+
this.addTerminalSessionMetrics(input.session_id, turn.created_at, cancelledState);
|
|
274
324
|
}
|
|
275
325
|
return deepCopy(turn);
|
|
276
326
|
}
|
|
@@ -306,6 +356,7 @@ var InMemorySessionStore = class {
|
|
|
306
356
|
if (list) {
|
|
307
357
|
list.push(deepCopy(input.turn_done_event));
|
|
308
358
|
}
|
|
359
|
+
this.addTerminalSessionMetrics(input.session_id, turn.created_at, input.state);
|
|
309
360
|
}
|
|
310
361
|
async appendToEvents(input) {
|
|
311
362
|
this.requireRunningTurn(input.session_id, input.turn_id);
|
|
@@ -317,6 +368,19 @@ var InMemorySessionStore = class {
|
|
|
317
368
|
list.push(...deepCopy(input.events));
|
|
318
369
|
return;
|
|
319
370
|
}
|
|
371
|
+
/** Cost from turn metrics when present; duration is completed_at − created_at, floored at 0. */
|
|
372
|
+
addTerminalSessionMetrics(sessionId, created_at, state) {
|
|
373
|
+
const stored = this.sessions.get(sessionKey(sessionId));
|
|
374
|
+
if (!stored) {
|
|
375
|
+
throw new import_SessionStoreErrors.SessionNotFoundError(sessionId);
|
|
376
|
+
}
|
|
377
|
+
const elapsed_ms = Date.parse(state.completed_at) - created_at.getTime();
|
|
378
|
+
const turnCost = state.metrics?.total_cost_in_usd;
|
|
379
|
+
if (turnCost !== void 0) {
|
|
380
|
+
stored.record.metrics.total_cost_in_usd = (stored.record.metrics.total_cost_in_usd ?? 0) + turnCost;
|
|
381
|
+
}
|
|
382
|
+
stored.record.metrics.total_duration_ms += elapsed_ms > 0 ? Math.trunc(elapsed_ms) : 0;
|
|
383
|
+
}
|
|
320
384
|
requireTurn(sessionId, turnId) {
|
|
321
385
|
const turn = this.turns.get(turnKey({ session_id: sessionId, turn_id: turnId }));
|
|
322
386
|
if (!turn) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/agent-session/store/InMemorySessionStore.ts"],"sourcesContent":["import type { AgentThreadSnapshot } from '../../core/runtime/AgentThread.types';\nimport { getEmptyCurrentContextUsage } from '../../core/runtime/contextUsage';\nimport type { SessionRecord } from '../models/SessionRecord';\nimport type { TurnRecord, TurnSnapshot } from '../models/TurnRecord';\nimport type { PersistedTurnEvent, SessionEventItem } from '../schemas/events';\nimport type { TokenPagination } from '../schemas/pagination';\nimport type { TerminalTurnState } from '../schemas/turn';\nimport { assertCreateTurnThreadDelta } from './assertCreateTurnThreadDelta';\nimport type {\n AddThreadsInput,\n AppendToEventsInput,\n AppendToThreadContextInput,\n CreateSessionInput,\n CreateTurnInput,\n DeleteSessionInput,\n FreezeAndGetTurnInput,\n GetSessionInput,\n GetTurnInput,\n ISessionStore,\n ListSessionEventsInput,\n ListSessionsInput,\n ListTurnEventsInput,\n ListTurnsInput,\n NewThreadInit,\n OverwriteThreadContextInput,\n PatchMCPServersInput,\n PatchSandboxInfoInput,\n PatchThreadCapabilityStateInput,\n RemoveThreadsInput,\n TurnContextAppend,\n TurnRecordWithoutSnapshot,\n UpdateSessionInput,\n UpdateTurnStateInput,\n} from './ISessionStore';\nimport { decodeOffsetPageToken, encodeOffsetPageToken } from './OffsetPageToken';\nimport {\n decodeSessionEventPageToken,\n paginateSessionEventRows,\n type SessionEventPageCursor,\n} from './SessionEventPageToken';\nimport { decodeSessionListPageToken, paginateSessionListRows } from './SessionListPageToken';\nimport {\n PreviousTurnRunningError,\n SessionAlreadyExistsError,\n SessionNotFoundError,\n SessionStoreInvariantError,\n TurnAlreadyExistsError,\n TurnNotFoundError,\n TurnNotRunningError,\n} from './SessionStoreErrors';\n\n/* eslint-disable @typescript-eslint/require-await -- in-memory store is synchronous; methods stay async so thrown SessionStore*Error reject as Promises for ISessionStore callers */\n\ntype StoredEvent = PersistedTurnEvent;\n\ninterface StoredSession<TSessionCustom extends object> {\n record: SessionRecord<TSessionCustom>;\n turnIds: string[];\n}\n\nfunction deepCopy<T>(value: T): T {\n return structuredClone(value);\n}\n\nfunction sessionKey(sessionId: string): string {\n return sessionId;\n}\n\nfunction turnKey({ session_id, turn_id }: { session_id: string; turn_id: string }): string {\n return `${session_id}:${turn_id}`;\n}\n\n/** Lexicographic session_id order — shared by listSessions sort and keyset filter. */\nfunction compareSessionId(a: string, b: string): number {\n if (a < b) {\n return -1;\n }\n if (a > b) {\n return 1;\n }\n return 0;\n}\n\nfunction newThreadSnapshot(thread: NewThreadInit): AgentThreadSnapshot {\n return {\n thread_id: thread.thread_id,\n parent: thread.parent ?? null,\n agent_info: thread.agent_info ?? null,\n capability_state: null,\n context: [],\n current_context_usage: getEmptyCurrentContextUsage(),\n completion: null,\n };\n}\n\nfunction applyContextAppends(threads: Record<string, AgentThreadSnapshot>, appends: TurnContextAppend[]): void {\n for (const append of appends) {\n const thread = threads[append.thread_id];\n if (!thread) {\n throw new SessionStoreInvariantError(`new_context_appends references unknown thread ${append.thread_id}`);\n }\n thread.context.push(...deepCopy(append.context));\n if (append.current_context_usage !== null) {\n thread.current_context_usage = deepCopy(append.current_context_usage);\n }\n }\n}\n\nfunction buildSnapshotFromDelta(input: {\n previousSnapshot: TurnSnapshot | undefined;\n new_threads: NewThreadInit[];\n new_context_appends: TurnContextAppend[];\n capability_states: CreateTurnInput['capability_states'];\n}): TurnSnapshot {\n const threads: Record<string, AgentThreadSnapshot> = input.previousSnapshot\n ? deepCopy(input.previousSnapshot.threads)\n : {};\n\n assertCreateTurnThreadDelta({\n previousThreadIds: new Set(Object.keys(threads)),\n new_threads: input.new_threads,\n new_context_appends: input.new_context_appends,\n capability_states: input.capability_states,\n });\n\n for (const nt of input.new_threads) {\n threads[nt.thread_id] = newThreadSnapshot(nt);\n }\n\n applyContextAppends(threads, input.new_context_appends);\n for (const capability of input.capability_states) {\n const thread = threads[capability.thread_id];\n if (thread === undefined) {\n throw new SessionStoreInvariantError(`capability_states references unknown thread ${capability.thread_id}`);\n }\n thread.capability_state = deepCopy(capability.capability_state);\n }\n\n return {\n threads,\n mcp_servers: input.previousSnapshot ? deepCopy(input.previousSnapshot.mcp_servers) : null,\n sandbox_info: input.previousSnapshot ? deepCopy(input.previousSnapshot.sandbox_info) : null,\n };\n}\n\nfunction paginate<T>(items: T[], limit: number, pageToken?: string): { data: T[]; pagination: TokenPagination } {\n const offset = decodeOffsetPageToken(pageToken);\n const slice = items.slice(offset, offset + limit);\n return {\n data: slice,\n pagination: {\n limit,\n ...(offset + limit < items.length ? { next_page_token: encodeOffsetPageToken(offset + limit) } : {}),\n ...(offset > 0 ? { previous_page_token: encodeOffsetPageToken(Math.max(0, offset - limit)) } : {}),\n },\n };\n}\n\n/**\n * Reference ISessionStore implementation. Proves the contract without SSE/subscription\n * hooks. Deep-copies on read/write boundaries so callers cannot mutate stored state.\n */\nexport class InMemorySessionStore<\n TSessionCustom extends object = Record<string, never>,\n TTurnCustom extends object = Record<string, never>,\n> implements ISessionStore<TSessionCustom, TTurnCustom> {\n private readonly sessions = new Map<string, StoredSession<TSessionCustom>>();\n private readonly turns = new Map<string, TurnRecord<TTurnCustom>>();\n private readonly events = new Map<string, StoredEvent[]>();\n\n async createSession(input: CreateSessionInput<TSessionCustom>): Promise<void> {\n const key = sessionKey(input.session_id);\n if (this.sessions.has(key)) {\n throw new SessionAlreadyExistsError(input.session_id);\n }\n const now = new Date();\n const record: SessionRecord<TSessionCustom> = {\n tenant_id: input.tenant_id,\n session_id: input.session_id,\n created_by: input.created_by,\n agent: deepCopy(input.agent),\n title: null,\n last_turn_id: null,\n created_at: now,\n updated_at: now,\n last_activity_timestamp_ms: Date.now(),\n custom: input.custom !== null ? deepCopy(input.custom) : null,\n };\n this.sessions.set(key, { record, turnIds: [] });\n return;\n }\n\n async deleteSession(input: DeleteSessionInput): Promise<void> {\n const sKey = sessionKey(input.session_id);\n const stored = this.sessions.get(sKey);\n if (stored?.record.tenant_id !== input.tenant_id) {\n return;\n }\n for (const turnId of stored.turnIds) {\n const tKey = turnKey({ session_id: input.session_id, turn_id: turnId });\n this.turns.delete(tKey);\n this.events.delete(tKey);\n }\n this.sessions.delete(sKey);\n }\n\n async getSession(input: GetSessionInput): Promise<SessionRecord<TSessionCustom> | undefined> {\n const stored = this.sessions.get(sessionKey(input.session_id));\n return stored?.record.tenant_id === input.tenant_id ? deepCopy(stored.record) : undefined;\n }\n\n async updateSession(input: UpdateSessionInput<TSessionCustom>): Promise<void> {\n const key = sessionKey(input.session_id);\n const stored = this.sessions.get(key);\n if (stored?.record.tenant_id !== input.tenant_id) {\n throw new SessionNotFoundError(input.session_id);\n }\n if (input.agent !== undefined) {\n if (stored.record.agent.type === 'reference') {\n throw new SessionStoreInvariantError(`Session ${input.session_id} is named; agent cannot be updated`);\n }\n stored.record.agent = deepCopy(input.agent);\n }\n if (input.title !== undefined) {\n stored.record.title = input.title;\n }\n const now = Date.now();\n stored.record.updated_at = new Date(now);\n stored.record.last_activity_timestamp_ms = now;\n return;\n }\n\n async listSessions(\n input: ListSessionsInput,\n ): Promise<{ data: SessionRecord<TSessionCustom>[]; pagination: TokenPagination }> {\n const records: SessionRecord<TSessionCustom>[] = [];\n for (const stored of this.sessions.values()) {\n if (stored.record.tenant_id !== input.tenant_id) {\n continue;\n }\n if (\n input.agent_id !== undefined &&\n (stored.record.agent.type !== 'reference' || stored.record.agent.id !== input.agent_id)\n ) {\n continue;\n }\n if (input.created_by !== undefined && stored.record.created_by !== input.created_by) {\n continue;\n }\n const createdAt = stored.record.created_at.getTime();\n if (input.start_timestamp !== undefined && createdAt < input.start_timestamp.getTime()) {\n continue;\n }\n if (input.end_timestamp !== undefined && createdAt > input.end_timestamp.getTime()) {\n continue;\n }\n records.push(stored.record);\n }\n records.sort((a, b) => {\n const aTime = a.updated_at.getTime();\n const bTime = b.updated_at.getTime();\n if (aTime !== bTime) {\n return input.order === 'asc' ? aTime - bTime : bTime - aTime;\n }\n // Same lexicographic order as the keyset predicate below (and Postgres/SQLite).\n return input.order === 'asc'\n ? compareSessionId(a.session_id, b.session_id)\n : compareSessionId(b.session_id, a.session_id);\n });\n\n let filtered = records;\n const cursor = decodeSessionListPageToken(input.page_token);\n if (cursor) {\n const cursorTime = new Date(cursor.updated_at).getTime();\n filtered = records.filter(record => {\n const t = record.updated_at.getTime();\n const idCmp = compareSessionId(record.session_id, cursor.session_id);\n if (input.order === 'asc') {\n return t > cursorTime || (t === cursorTime && idCmp > 0);\n }\n return t < cursorTime || (t === cursorTime && idCmp < 0);\n });\n }\n\n const page = paginateSessionListRows(filtered, input.limit, row => row.updated_at.toISOString());\n return { data: deepCopy(page.data), pagination: page.pagination };\n }\n\n async createTurn(input: CreateTurnInput<TTurnCustom>): Promise<void> {\n // Atomicity is free here: this body is fully synchronous, so Node's\n // run-to-completion guarantees it. Real backends must still use their own\n // locking/transactions to satisfy the ISessionStore createTurn contract.\n const sKey = sessionKey(input.turn.session_id);\n const stored = this.sessions.get(sKey);\n if (!stored) {\n throw new SessionNotFoundError(input.turn.session_id);\n }\n\n const previousTurnId = input.turn.previous_turn_id;\n let previousSnapshot: TurnSnapshot | undefined;\n if (previousTurnId !== null) {\n const prevKey = turnKey({ session_id: input.turn.session_id, turn_id: previousTurnId });\n const prev = this.turns.get(prevKey);\n // Unknown previous_turn_id is allowed (relaxed): treat as no inheritance.\n // A still-running previous must be frozen first.\n if (prev !== undefined) {\n if (prev.state.status === 'running') {\n throw new PreviousTurnRunningError(previousTurnId);\n }\n previousSnapshot = prev.snapshot;\n }\n }\n\n const tKey = turnKey(input.turn);\n if (this.turns.has(tKey)) {\n throw new TurnAlreadyExistsError(input.turn.turn_id);\n }\n\n const snapshot = buildSnapshotFromDelta({\n previousSnapshot,\n new_threads: input.new_threads,\n new_context_appends: input.new_context_appends,\n capability_states: input.capability_states,\n });\n\n const turnRecord: TurnRecord<TTurnCustom> = {\n ...deepCopy(input.turn),\n snapshot,\n };\n\n this.turns.set(tKey, turnRecord);\n this.events.set(tKey, []);\n stored.turnIds.push(input.turn.turn_id);\n stored.record.last_turn_id = input.turn.turn_id;\n stored.record.last_activity_timestamp_ms = Date.now();\n stored.record.updated_at = new Date();\n if (input.update_session_title_if_not_exist !== null && stored.record.title === null) {\n stored.record.title = input.update_session_title_if_not_exist;\n }\n }\n\n async freezeAndGetTurn(input: FreezeAndGetTurnInput): Promise<TurnRecord<TTurnCustom>> {\n const tKey = turnKey(input);\n const turn = this.requireTurn(input.session_id, input.turn_id);\n\n if (turn.state.status === 'running') {\n const cancelledState: TerminalTurnState = {\n status: 'cancelled',\n reason: input.reason,\n completed_at: new Date().toISOString(),\n };\n turn.state = cancelledState;\n turn.updated_at = new Date();\n const list = this.events.get(tKey);\n if (list) {\n list.push(deepCopy(input.turn_done_event));\n }\n }\n\n return deepCopy(turn);\n }\n\n async getTurn(input: GetTurnInput): Promise<TurnRecord<TTurnCustom> | undefined> {\n const turn = this.turns.get(turnKey(input));\n return turn ? deepCopy(turn) : undefined;\n }\n\n async listTurns(\n input: ListTurnsInput,\n ): Promise<{ data: TurnRecordWithoutSnapshot<TTurnCustom>[]; pagination: TokenPagination }> {\n const stored = this.sessions.get(sessionKey(input.session_id));\n if (!stored) {\n throw new SessionNotFoundError(input.session_id);\n }\n const records = stored.turnIds.map(id => {\n const turn = this.turns.get(turnKey({ session_id: input.session_id, turn_id: id }));\n if (!turn) {\n throw new TurnNotFoundError(id);\n }\n const { snapshot, ...row } = deepCopy(turn);\n void snapshot;\n return row;\n });\n return paginate(records, input.limit, input.page_token);\n }\n\n async updateTurnState(input: UpdateTurnStateInput): Promise<void> {\n // Same as createTurn: synchronous body ⇒ atomic under run-to-completion.\n const tKey = turnKey(input);\n const turn = this.requireTurn(input.session_id, input.turn_id);\n if (turn.state.status !== 'running') {\n throw new TurnNotRunningError(input.turn_id, turn.state);\n }\n turn.state = deepCopy(input.state);\n turn.updated_at = new Date();\n const list = this.events.get(tKey);\n if (list) {\n list.push(deepCopy(input.turn_done_event));\n }\n }\n\n async appendToEvents(input: AppendToEventsInput): Promise<void> {\n this.requireRunningTurn(input.session_id, input.turn_id);\n const tKey = turnKey(input);\n const list = this.events.get(tKey);\n if (!list) {\n throw new TurnNotFoundError(input.turn_id);\n }\n list.push(...deepCopy(input.events));\n return;\n }\n\n private requireTurn(sessionId: string, turnId: string): TurnRecord<TTurnCustom> {\n const turn = this.turns.get(turnKey({ session_id: sessionId, turn_id: turnId }));\n if (!turn) {\n throw new TurnNotFoundError(turnId);\n }\n return turn;\n }\n\n private requireRunningTurn(sessionId: string, turnId: string): TurnRecord<TTurnCustom> {\n const turn = this.requireTurn(sessionId, turnId);\n if (turn.state.status !== 'running') {\n throw new TurnNotRunningError(turnId, turn.state);\n }\n return turn;\n }\n\n async addThreads(input: AddThreadsInput): Promise<void> {\n const turn = this.requireRunningTurn(input.session_id, input.turn_id);\n for (const thread of input.threads) {\n turn.snapshot.threads[thread.thread_id] = deepCopy(thread);\n }\n turn.updated_at = new Date();\n return;\n }\n\n async removeThreads(input: RemoveThreadsInput): Promise<void> {\n if (input.thread_ids.length === 0) {\n return;\n }\n const turn = this.requireRunningTurn(input.session_id, input.turn_id);\n for (const id of input.thread_ids) {\n Reflect.deleteProperty(turn.snapshot.threads, id);\n }\n turn.updated_at = new Date();\n return;\n }\n\n async appendToThreadContext(input: AppendToThreadContextInput): Promise<void> {\n const turn = this.requireRunningTurn(input.session_id, input.turn_id);\n const thread = turn.snapshot.threads[input.thread_id];\n if (!thread) {\n throw new SessionStoreInvariantError(`Thread not found: ${input.thread_id}`);\n }\n thread.context.push(...deepCopy(input.context));\n if (input.current_context_usage !== null) {\n thread.current_context_usage = deepCopy(input.current_context_usage);\n }\n if (input.completion !== null) {\n thread.completion = deepCopy(input.completion);\n }\n turn.updated_at = new Date();\n return;\n }\n\n async overwriteThreadContext(input: OverwriteThreadContextInput): Promise<void> {\n const turn = this.requireRunningTurn(input.session_id, input.turn_id);\n const threadId = input.event.thread_id;\n const thread = turn.snapshot.threads[threadId];\n if (!thread) {\n throw new SessionStoreInvariantError(`Thread not found: ${threadId}`);\n }\n thread.context = deepCopy(input.event.context);\n thread.current_context_usage = deepCopy(input.event.current_context_usage);\n turn.updated_at = new Date();\n return;\n }\n\n async patchMCPServers(input: PatchMCPServersInput): Promise<void> {\n const turn = this.requireRunningTurn(input.session_id, input.turn_id);\n turn.snapshot.mcp_servers ??= {};\n for (const server of input.mcp_servers) {\n turn.snapshot.mcp_servers[server.id] = deepCopy(server);\n }\n turn.updated_at = new Date();\n return;\n }\n\n async patchSandboxInfo(input: PatchSandboxInfoInput): Promise<void> {\n const turn = this.requireRunningTurn(input.session_id, input.turn_id);\n turn.snapshot.sandbox_info = deepCopy(input.sandbox_info);\n turn.updated_at = new Date();\n return;\n }\n\n async patchThreadCapabilityState(input: PatchThreadCapabilityStateInput): Promise<void> {\n const turn = this.requireRunningTurn(input.session_id, input.turn_id);\n const thread = turn.snapshot.threads[input.thread_id];\n if (!thread) {\n throw new SessionStoreInvariantError(`Thread not found: ${input.thread_id}`);\n }\n thread.capability_state ??= {};\n if (input.state === null) {\n Reflect.deleteProperty(thread.capability_state, input.key);\n if (Object.keys(thread.capability_state).length === 0) {\n thread.capability_state = null;\n }\n } else {\n thread.capability_state[input.key] = deepCopy(input.state);\n }\n turn.updated_at = new Date();\n return;\n }\n\n async listTurnEvents(input: ListTurnEventsInput): Promise<{\n data: PersistedTurnEvent[];\n pagination: TokenPagination;\n }> {\n this.requireTurn(input.session_id, input.turn_id);\n const list = this.events.get(turnKey(input));\n if (!list) {\n throw new TurnNotFoundError(input.turn_id);\n }\n const ordered = [...list].sort((a, b) =>\n input.order === 'desc' ? b.id.localeCompare(a.id) : a.id.localeCompare(b.id),\n );\n const page = paginate(ordered, input.limit, input.page_token);\n return { data: deepCopy(page.data), pagination: page.pagination };\n }\n\n async listSessionEvents(input: ListSessionEventsInput): Promise<{\n data: SessionEventItem[];\n pagination: TokenPagination;\n }> {\n const stored = this.sessions.get(sessionKey(input.session_id));\n if (!stored) {\n throw new SessionNotFoundError(input.session_id);\n }\n\n const decodedCursor = input.page_token === undefined ? undefined : decodeSessionEventPageToken(input.page_token);\n const lastTurnId = decodedCursor?.last_turn_id ?? input.last_turn_id ?? stored.record.last_turn_id;\n if (lastTurnId === null) {\n return { data: [], pagination: { limit: input.limit } };\n }\n const cursor: SessionEventPageCursor = {\n last_turn_id: lastTurnId,\n offset: decodedCursor?.offset ?? 0,\n };\n\n const anchor = this.turns.get(turnKey({ session_id: input.session_id, turn_id: cursor.last_turn_id }));\n if (!anchor) {\n throw new TurnNotFoundError(cursor.last_turn_id);\n }\n const turnIds = this.resolveAncestorChain(input.session_id, anchor);\n const flattened: SessionEventItem[] = [];\n for (const turnId of [...turnIds].reverse()) {\n const evts = this.events.get(turnKey({ session_id: input.session_id, turn_id: turnId })) ?? [];\n for (const event of [...evts].sort((a, b) => b.id.localeCompare(a.id))) {\n flattened.push({ turn_id: turnId, event });\n }\n }\n const page = paginateSessionEventRows(\n flattened.slice(cursor.offset, cursor.offset + input.limit + 1),\n input.limit,\n cursor,\n );\n return { data: deepCopy(page.data), pagination: page.pagination };\n }\n\n /**\n * Full chain (oldest first, anchor last). `ancestor_ids` may be only the\n * previous N ancestors, so spill through the oldest ancestor's own window\n * until a root or gap. A missing turn or repeated id ends the walk.\n */\n private resolveAncestorChain(sessionId: string, anchor: TurnRecord<TTurnCustom>): string[] {\n const chain = [...anchor.ancestor_ids, anchor.turn_id];\n const seen = new Set(chain);\n let oldestId = chain[0];\n while (oldestId && oldestId !== anchor.turn_id) {\n const oldest = this.turns.get(turnKey({ session_id: sessionId, turn_id: oldestId }));\n if (!oldest) {\n break;\n }\n const older = oldest.ancestor_ids.filter(id => !seen.has(id));\n if (older.length === 0) {\n break;\n }\n chain.unshift(...older);\n for (const id of older) {\n seen.add(id);\n }\n oldestId = older[0];\n }\n return chain;\n }\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../src/agent-session/store/InMemorySessionStore.ts"],"sourcesContent":["import type { AgentThreadSnapshot } from '../../core/runtime/AgentThread.types';\nimport { getEmptyCurrentContextUsage } from '../../core/runtime/contextUsage';\nimport type { SessionRecord } from '../models/SessionRecord';\nimport type { TurnRecord, TurnSnapshot } from '../models/TurnRecord';\nimport type { PersistedTurnEvent, SessionEventItem } from '../schemas/events';\nimport type { TokenPagination } from '../schemas/pagination';\nimport type { TerminalTurnState } from '../schemas/turn';\nimport { assertCreateTurnThreadDelta } from './assertCreateTurnThreadDelta';\nimport type {\n AddThreadsInput,\n AppendToEventsInput,\n AppendToThreadContextInput,\n CreateSessionInput,\n CreateTurnInput,\n DeleteSessionInput,\n FreezeAndGetTurnInput,\n GetSessionByExternalIdInput,\n GetSessionInput,\n GetTurnInput,\n ISessionStore,\n ListSessionEventsInput,\n ListSessionsInput,\n ListTurnEventsInput,\n ListTurnsInput,\n NewThreadInit,\n OverwriteThreadContextInput,\n PatchMCPServersInput,\n PatchSandboxInfoInput,\n PatchThreadCapabilityStateInput,\n RemoveThreadsInput,\n TurnContextAppend,\n TurnRecordWithoutSnapshot,\n UpdateSessionInput,\n UpdateTurnStateInput,\n} from './ISessionStore';\nimport { decodeOffsetPageToken, encodeOffsetPageToken } from './OffsetPageToken';\nimport {\n decodeSessionEventPageToken,\n paginateSessionEventRows,\n type SessionEventPageCursor,\n} from './SessionEventPageToken';\nimport { decodeSessionListPageToken, paginateSessionListRows } from './SessionListPageToken';\nimport {\n PreviousTurnRunningError,\n SessionAlreadyExistsError,\n SessionExternalIdConflictError,\n SessionNotFoundError,\n SessionStoreInvariantError,\n TurnAlreadyExistsError,\n TurnNotFoundError,\n TurnNotRunningError,\n} from './SessionStoreErrors';\n\n/* eslint-disable @typescript-eslint/require-await -- in-memory store is synchronous; methods stay async so thrown SessionStore*Error reject as Promises for ISessionStore callers */\n\ntype StoredEvent = PersistedTurnEvent;\n\ninterface StoredSession<TSessionCustom extends object> {\n record: SessionRecord<TSessionCustom>;\n turnIds: string[];\n}\n\nfunction deepCopy<T>(value: T): T {\n return structuredClone(value);\n}\n\nfunction sessionKey(sessionId: string): string {\n return sessionId;\n}\n\nfunction turnKey({ session_id, turn_id }: { session_id: string; turn_id: string }): string {\n return `${session_id}:${turn_id}`;\n}\n\n/** Lexicographic session_id order — shared by listSessions sort and keyset filter. */\nfunction compareSessionId(a: string, b: string): number {\n if (a < b) {\n return -1;\n }\n if (a > b) {\n return 1;\n }\n return 0;\n}\n\nfunction newThreadSnapshot(thread: NewThreadInit): AgentThreadSnapshot {\n return {\n thread_id: thread.thread_id,\n parent: thread.parent ?? null,\n agent_info: thread.agent_info ?? null,\n capability_state: null,\n context: [],\n current_context_usage: getEmptyCurrentContextUsage(),\n completion: null,\n };\n}\n\nfunction applyContextAppends(threads: Record<string, AgentThreadSnapshot>, appends: TurnContextAppend[]): void {\n for (const append of appends) {\n const thread = threads[append.thread_id];\n if (!thread) {\n throw new SessionStoreInvariantError(`new_context_appends references unknown thread ${append.thread_id}`);\n }\n thread.context.push(...deepCopy(append.context));\n if (append.current_context_usage !== null) {\n thread.current_context_usage = deepCopy(append.current_context_usage);\n }\n }\n}\n\nfunction buildSnapshotFromDelta(input: {\n previousSnapshot: TurnSnapshot | undefined;\n new_threads: NewThreadInit[];\n new_context_appends: TurnContextAppend[];\n capability_states: CreateTurnInput['capability_states'];\n}): TurnSnapshot {\n const threads: Record<string, AgentThreadSnapshot> = input.previousSnapshot\n ? deepCopy(input.previousSnapshot.threads)\n : {};\n\n assertCreateTurnThreadDelta({\n previousThreadIds: new Set(Object.keys(threads)),\n new_threads: input.new_threads,\n new_context_appends: input.new_context_appends,\n capability_states: input.capability_states,\n });\n\n for (const nt of input.new_threads) {\n threads[nt.thread_id] = newThreadSnapshot(nt);\n }\n\n applyContextAppends(threads, input.new_context_appends);\n for (const capability of input.capability_states) {\n const thread = threads[capability.thread_id];\n if (thread === undefined) {\n throw new SessionStoreInvariantError(`capability_states references unknown thread ${capability.thread_id}`);\n }\n thread.capability_state = deepCopy(capability.capability_state);\n }\n\n return {\n threads,\n mcp_servers: input.previousSnapshot ? deepCopy(input.previousSnapshot.mcp_servers) : null,\n sandbox_info: input.previousSnapshot ? deepCopy(input.previousSnapshot.sandbox_info) : null,\n };\n}\n\nfunction paginate<T>(items: T[], limit: number, pageToken?: string): { data: T[]; pagination: TokenPagination } {\n const offset = decodeOffsetPageToken(pageToken);\n const slice = items.slice(offset, offset + limit);\n return {\n data: slice,\n pagination: {\n limit,\n ...(offset + limit < items.length ? { next_page_token: encodeOffsetPageToken(offset + limit) } : {}),\n ...(offset > 0 ? { previous_page_token: encodeOffsetPageToken(Math.max(0, offset - limit)) } : {}),\n },\n };\n}\n\n/**\n * Reference ISessionStore implementation. Proves the contract without SSE/subscription\n * hooks. Deep-copies on read/write boundaries so callers cannot mutate stored state.\n */\nexport class InMemorySessionStore<\n TSessionCustom extends object = Record<string, never>,\n TTurnCustom extends object = Record<string, never>,\n> implements ISessionStore<TSessionCustom, TTurnCustom> {\n private readonly sessions = new Map<string, StoredSession<TSessionCustom>>();\n private readonly turns = new Map<string, TurnRecord<TTurnCustom>>();\n private readonly events = new Map<string, StoredEvent[]>();\n\n async createSession(input: CreateSessionInput<TSessionCustom>): Promise<void> {\n const key = sessionKey(input.session_id);\n if (this.sessions.has(key)) {\n throw new SessionAlreadyExistsError(input.session_id);\n }\n const externalId = input.external_id;\n if (externalId !== null) {\n for (const stored of this.sessions.values()) {\n if (stored.record.tenant_id === input.tenant_id && stored.record.external_id === externalId) {\n throw new SessionExternalIdConflictError(externalId);\n }\n }\n }\n const now = new Date();\n const record: SessionRecord<TSessionCustom> = {\n tenant_id: input.tenant_id,\n session_id: input.session_id,\n created_by_subject: input.created_by_subject,\n agent: deepCopy(input.agent),\n title: null,\n last_turn_id: null,\n external_id: externalId,\n source: input.source !== null ? deepCopy(input.source) : null,\n created_at: now,\n updated_at: now,\n last_activity_timestamp_ms: Date.now(),\n metrics: {\n total_duration_ms: 0,\n total_turns: 0,\n },\n metadata: deepCopy(input.metadata),\n custom: input.custom !== null ? deepCopy(input.custom) : null,\n };\n this.sessions.set(key, { record, turnIds: [] });\n return;\n }\n\n async deleteSession(input: DeleteSessionInput): Promise<void> {\n const sKey = sessionKey(input.session_id);\n const stored = this.sessions.get(sKey);\n if (stored?.record.tenant_id !== input.tenant_id) {\n return;\n }\n for (const turnId of stored.turnIds) {\n const tKey = turnKey({ session_id: input.session_id, turn_id: turnId });\n this.turns.delete(tKey);\n this.events.delete(tKey);\n }\n this.sessions.delete(sKey);\n }\n\n async getSession(input: GetSessionInput): Promise<SessionRecord<TSessionCustom> | undefined> {\n const stored = this.sessions.get(sessionKey(input.session_id));\n return stored?.record.tenant_id === input.tenant_id ? deepCopy(stored.record) : undefined;\n }\n\n async getSessionByExternalId(input: GetSessionByExternalIdInput): Promise<SessionRecord<TSessionCustom> | undefined> {\n for (const stored of this.sessions.values()) {\n if (stored.record.tenant_id === input.tenant_id && stored.record.external_id === input.external_id) {\n return deepCopy(stored.record);\n }\n }\n return undefined;\n }\n\n async updateSession(input: UpdateSessionInput<TSessionCustom>): Promise<void> {\n const key = sessionKey(input.session_id);\n const stored = this.sessions.get(key);\n if (stored?.record.tenant_id !== input.tenant_id) {\n throw new SessionNotFoundError(input.session_id);\n }\n if (input.agent !== undefined) {\n if (stored.record.agent.type === 'reference') {\n throw new SessionStoreInvariantError(`Session ${input.session_id} is named; agent cannot be updated`);\n }\n stored.record.agent = deepCopy(input.agent);\n }\n if (input.title !== undefined) {\n stored.record.title = input.title;\n }\n if (input.metadata !== undefined) {\n stored.record.metadata = deepCopy(input.metadata);\n }\n const now = Date.now();\n stored.record.updated_at = new Date(now);\n stored.record.last_activity_timestamp_ms = now;\n return;\n }\n\n async listSessions(\n input: ListSessionsInput,\n ): Promise<{ data: SessionRecord<TSessionCustom>[]; pagination: TokenPagination }> {\n const records: SessionRecord<TSessionCustom>[] = [];\n const createdByOrAgentIds = input.created_by_or_agent_ids;\n for (const stored of this.sessions.values()) {\n if (stored.record.tenant_id !== input.tenant_id) {\n continue;\n }\n if (\n input.agent_id !== undefined &&\n (stored.record.agent.type !== 'reference' || stored.record.agent.id !== input.agent_id)\n ) {\n continue;\n }\n if (createdByOrAgentIds !== undefined) {\n const creatorMatches =\n stored.record.created_by_subject.subject_id === createdByOrAgentIds.created_by_subject_id;\n const agentMatches =\n stored.record.agent.type === 'reference' && createdByOrAgentIds.agent_ids.includes(stored.record.agent.id);\n if (!creatorMatches && !agentMatches) {\n continue;\n }\n }\n const metadataFilter = input.metadata;\n if (metadataFilter !== undefined) {\n const entries = Object.entries(metadataFilter);\n if (entries.length === 0) {\n if (Object.keys(stored.record.metadata).length > 0) {\n continue;\n }\n } else if (!entries.every(([key, value]) => stored.record.metadata[key] === value)) {\n continue;\n }\n }\n if (input.source_type !== undefined && stored.record.source?.type !== input.source_type) {\n continue;\n }\n if (input.source_id !== undefined && stored.record.source?.id !== input.source_id) {\n continue;\n }\n const createdAt = stored.record.created_at.getTime();\n if (input.start_timestamp !== undefined && createdAt < input.start_timestamp.getTime()) {\n continue;\n }\n if (input.end_timestamp !== undefined && createdAt > input.end_timestamp.getTime()) {\n continue;\n }\n records.push(stored.record);\n }\n records.sort((a, b) => {\n const aTime = a.updated_at.getTime();\n const bTime = b.updated_at.getTime();\n if (aTime !== bTime) {\n return input.order === 'asc' ? aTime - bTime : bTime - aTime;\n }\n // Same lexicographic order as the keyset predicate below (and Postgres/SQLite).\n return input.order === 'asc'\n ? compareSessionId(a.session_id, b.session_id)\n : compareSessionId(b.session_id, a.session_id);\n });\n\n let filtered = records;\n const cursor = decodeSessionListPageToken(input.page_token);\n if (cursor) {\n const cursorTime = new Date(cursor.updated_at).getTime();\n filtered = records.filter(record => {\n const t = record.updated_at.getTime();\n const idCmp = compareSessionId(record.session_id, cursor.session_id);\n if (input.order === 'asc') {\n return t > cursorTime || (t === cursorTime && idCmp > 0);\n }\n return t < cursorTime || (t === cursorTime && idCmp < 0);\n });\n }\n\n const page = paginateSessionListRows(filtered, input.limit, row => row.updated_at.toISOString());\n return { data: deepCopy(page.data), pagination: page.pagination };\n }\n\n async createTurn(input: CreateTurnInput<TTurnCustom>): Promise<void> {\n // Atomicity is free here: this body is fully synchronous, so Node's\n // run-to-completion guarantees it. Real backends must still use their own\n // locking/transactions to satisfy the ISessionStore createTurn contract.\n const sKey = sessionKey(input.turn.session_id);\n const stored = this.sessions.get(sKey);\n if (!stored) {\n throw new SessionNotFoundError(input.turn.session_id);\n }\n\n const previousTurnId = input.turn.previous_turn_id;\n let previousSnapshot: TurnSnapshot | undefined;\n if (previousTurnId !== null) {\n const prevKey = turnKey({ session_id: input.turn.session_id, turn_id: previousTurnId });\n const prev = this.turns.get(prevKey);\n // Unknown previous_turn_id is allowed (relaxed): treat as no inheritance.\n // A still-running previous must be frozen first.\n if (prev !== undefined) {\n if (prev.state.status === 'running') {\n throw new PreviousTurnRunningError(previousTurnId);\n }\n previousSnapshot = prev.snapshot;\n }\n }\n\n const tKey = turnKey(input.turn);\n if (this.turns.has(tKey)) {\n throw new TurnAlreadyExistsError(input.turn.turn_id);\n }\n\n const snapshot = buildSnapshotFromDelta({\n previousSnapshot,\n new_threads: input.new_threads,\n new_context_appends: input.new_context_appends,\n capability_states: input.capability_states,\n });\n\n const turnRecord: TurnRecord<TTurnCustom> = {\n ...deepCopy(input.turn),\n snapshot,\n };\n\n this.turns.set(tKey, turnRecord);\n this.events.set(tKey, []);\n stored.turnIds.push(input.turn.turn_id);\n stored.record.last_turn_id = input.turn.turn_id;\n stored.record.metrics.total_turns += 1;\n stored.record.last_activity_timestamp_ms = Date.now();\n stored.record.updated_at = new Date();\n if (input.update_session_title_if_not_exist !== null && stored.record.title === null) {\n stored.record.title = input.update_session_title_if_not_exist;\n }\n }\n\n async freezeAndGetTurn(input: FreezeAndGetTurnInput): Promise<TurnRecord<TTurnCustom>> {\n const tKey = turnKey(input);\n const turn = this.requireTurn(input.session_id, input.turn_id);\n\n if (turn.state.status === 'running') {\n const cancelledState: TerminalTurnState = {\n status: 'cancelled',\n reason: input.reason,\n completed_at: new Date().toISOString(),\n };\n turn.state = cancelledState;\n turn.updated_at = new Date();\n const list = this.events.get(tKey);\n if (list) {\n list.push(deepCopy(input.turn_done_event));\n }\n this.addTerminalSessionMetrics(input.session_id, turn.created_at, cancelledState);\n }\n\n return deepCopy(turn);\n }\n\n async getTurn(input: GetTurnInput): Promise<TurnRecord<TTurnCustom> | undefined> {\n const turn = this.turns.get(turnKey(input));\n return turn ? deepCopy(turn) : undefined;\n }\n\n async listTurns(\n input: ListTurnsInput,\n ): Promise<{ data: TurnRecordWithoutSnapshot<TTurnCustom>[]; pagination: TokenPagination }> {\n const stored = this.sessions.get(sessionKey(input.session_id));\n if (!stored) {\n throw new SessionNotFoundError(input.session_id);\n }\n const records = stored.turnIds.map(id => {\n const turn = this.turns.get(turnKey({ session_id: input.session_id, turn_id: id }));\n if (!turn) {\n throw new TurnNotFoundError(id);\n }\n const { snapshot, ...row } = deepCopy(turn);\n void snapshot;\n return row;\n });\n return paginate(records, input.limit, input.page_token);\n }\n\n async updateTurnState(input: UpdateTurnStateInput): Promise<void> {\n // Same as createTurn: synchronous body ⇒ atomic under run-to-completion.\n const tKey = turnKey(input);\n const turn = this.requireTurn(input.session_id, input.turn_id);\n if (turn.state.status !== 'running') {\n throw new TurnNotRunningError(input.turn_id, turn.state);\n }\n turn.state = deepCopy(input.state);\n turn.updated_at = new Date();\n const list = this.events.get(tKey);\n if (list) {\n list.push(deepCopy(input.turn_done_event));\n }\n this.addTerminalSessionMetrics(input.session_id, turn.created_at, input.state);\n }\n\n async appendToEvents(input: AppendToEventsInput): Promise<void> {\n this.requireRunningTurn(input.session_id, input.turn_id);\n const tKey = turnKey(input);\n const list = this.events.get(tKey);\n if (!list) {\n throw new TurnNotFoundError(input.turn_id);\n }\n list.push(...deepCopy(input.events));\n return;\n }\n\n /** Cost from turn metrics when present; duration is completed_at − created_at, floored at 0. */\n private addTerminalSessionMetrics(sessionId: string, created_at: Date, state: TerminalTurnState): void {\n const stored = this.sessions.get(sessionKey(sessionId));\n if (!stored) {\n throw new SessionNotFoundError(sessionId);\n }\n const elapsed_ms = Date.parse(state.completed_at) - created_at.getTime();\n const turnCost = state.metrics?.total_cost_in_usd;\n if (turnCost !== undefined) {\n stored.record.metrics.total_cost_in_usd = (stored.record.metrics.total_cost_in_usd ?? 0) + turnCost;\n }\n stored.record.metrics.total_duration_ms += elapsed_ms > 0 ? Math.trunc(elapsed_ms) : 0;\n }\n\n private requireTurn(sessionId: string, turnId: string): TurnRecord<TTurnCustom> {\n const turn = this.turns.get(turnKey({ session_id: sessionId, turn_id: turnId }));\n if (!turn) {\n throw new TurnNotFoundError(turnId);\n }\n return turn;\n }\n\n private requireRunningTurn(sessionId: string, turnId: string): TurnRecord<TTurnCustom> {\n const turn = this.requireTurn(sessionId, turnId);\n if (turn.state.status !== 'running') {\n throw new TurnNotRunningError(turnId, turn.state);\n }\n return turn;\n }\n\n async addThreads(input: AddThreadsInput): Promise<void> {\n const turn = this.requireRunningTurn(input.session_id, input.turn_id);\n for (const thread of input.threads) {\n turn.snapshot.threads[thread.thread_id] = deepCopy(thread);\n }\n turn.updated_at = new Date();\n return;\n }\n\n async removeThreads(input: RemoveThreadsInput): Promise<void> {\n if (input.thread_ids.length === 0) {\n return;\n }\n const turn = this.requireRunningTurn(input.session_id, input.turn_id);\n for (const id of input.thread_ids) {\n Reflect.deleteProperty(turn.snapshot.threads, id);\n }\n turn.updated_at = new Date();\n return;\n }\n\n async appendToThreadContext(input: AppendToThreadContextInput): Promise<void> {\n const turn = this.requireRunningTurn(input.session_id, input.turn_id);\n const thread = turn.snapshot.threads[input.thread_id];\n if (!thread) {\n throw new SessionStoreInvariantError(`Thread not found: ${input.thread_id}`);\n }\n thread.context.push(...deepCopy(input.context));\n if (input.current_context_usage !== null) {\n thread.current_context_usage = deepCopy(input.current_context_usage);\n }\n if (input.completion !== null) {\n thread.completion = deepCopy(input.completion);\n }\n turn.updated_at = new Date();\n return;\n }\n\n async overwriteThreadContext(input: OverwriteThreadContextInput): Promise<void> {\n const turn = this.requireRunningTurn(input.session_id, input.turn_id);\n const threadId = input.event.thread_id;\n const thread = turn.snapshot.threads[threadId];\n if (!thread) {\n throw new SessionStoreInvariantError(`Thread not found: ${threadId}`);\n }\n thread.context = deepCopy(input.event.context);\n thread.current_context_usage = deepCopy(input.event.current_context_usage);\n turn.updated_at = new Date();\n return;\n }\n\n async patchMCPServers(input: PatchMCPServersInput): Promise<void> {\n const turn = this.requireRunningTurn(input.session_id, input.turn_id);\n turn.snapshot.mcp_servers ??= {};\n for (const server of input.mcp_servers) {\n turn.snapshot.mcp_servers[server.id] = deepCopy(server);\n }\n turn.updated_at = new Date();\n return;\n }\n\n async patchSandboxInfo(input: PatchSandboxInfoInput): Promise<void> {\n const turn = this.requireRunningTurn(input.session_id, input.turn_id);\n turn.snapshot.sandbox_info = deepCopy(input.sandbox_info);\n turn.updated_at = new Date();\n return;\n }\n\n async patchThreadCapabilityState(input: PatchThreadCapabilityStateInput): Promise<void> {\n const turn = this.requireRunningTurn(input.session_id, input.turn_id);\n const thread = turn.snapshot.threads[input.thread_id];\n if (!thread) {\n throw new SessionStoreInvariantError(`Thread not found: ${input.thread_id}`);\n }\n thread.capability_state ??= {};\n if (input.state === null) {\n Reflect.deleteProperty(thread.capability_state, input.key);\n if (Object.keys(thread.capability_state).length === 0) {\n thread.capability_state = null;\n }\n } else {\n thread.capability_state[input.key] = deepCopy(input.state);\n }\n turn.updated_at = new Date();\n return;\n }\n\n async listTurnEvents(input: ListTurnEventsInput): Promise<{\n data: PersistedTurnEvent[];\n pagination: TokenPagination;\n }> {\n this.requireTurn(input.session_id, input.turn_id);\n const list = this.events.get(turnKey(input));\n if (!list) {\n throw new TurnNotFoundError(input.turn_id);\n }\n const ordered = [...list].sort((a, b) =>\n input.order === 'desc' ? b.id.localeCompare(a.id) : a.id.localeCompare(b.id),\n );\n const page = paginate(ordered, input.limit, input.page_token);\n return { data: deepCopy(page.data), pagination: page.pagination };\n }\n\n async listSessionEvents(input: ListSessionEventsInput): Promise<{\n data: SessionEventItem[];\n pagination: TokenPagination;\n }> {\n const stored = this.sessions.get(sessionKey(input.session_id));\n if (!stored) {\n throw new SessionNotFoundError(input.session_id);\n }\n\n const decodedCursor = input.page_token === undefined ? undefined : decodeSessionEventPageToken(input.page_token);\n const lastTurnId = decodedCursor?.last_turn_id ?? input.last_turn_id ?? stored.record.last_turn_id;\n if (lastTurnId === null) {\n return { data: [], pagination: { limit: input.limit } };\n }\n const cursor: SessionEventPageCursor = {\n last_turn_id: lastTurnId,\n offset: decodedCursor?.offset ?? 0,\n };\n\n const anchor = this.turns.get(turnKey({ session_id: input.session_id, turn_id: cursor.last_turn_id }));\n if (!anchor) {\n throw new TurnNotFoundError(cursor.last_turn_id);\n }\n const turnIds = this.resolveAncestorChain(input.session_id, anchor);\n const flattened: SessionEventItem[] = [];\n for (const turnId of [...turnIds].reverse()) {\n const evts = this.events.get(turnKey({ session_id: input.session_id, turn_id: turnId })) ?? [];\n for (const event of [...evts].sort((a, b) => b.id.localeCompare(a.id))) {\n flattened.push({ turn_id: turnId, event });\n }\n }\n const page = paginateSessionEventRows(\n flattened.slice(cursor.offset, cursor.offset + input.limit + 1),\n input.limit,\n cursor,\n );\n return { data: deepCopy(page.data), pagination: page.pagination };\n }\n\n /**\n * Full chain (oldest first, anchor last). `ancestor_ids` may be only the\n * previous N ancestors, so spill through the oldest ancestor's own window\n * until a root or gap. A missing turn or repeated id ends the walk.\n */\n private resolveAncestorChain(sessionId: string, anchor: TurnRecord<TTurnCustom>): string[] {\n const chain = [...anchor.ancestor_ids, anchor.turn_id];\n const seen = new Set(chain);\n let oldestId = chain[0];\n while (oldestId && oldestId !== anchor.turn_id) {\n const oldest = this.turns.get(turnKey({ session_id: sessionId, turn_id: oldestId }));\n if (!oldest) {\n break;\n }\n const older = oldest.ancestor_ids.filter(id => !seen.has(id));\n if (older.length === 0) {\n break;\n }\n chain.unshift(...older);\n for (const id of older) {\n seen.add(id);\n }\n oldestId = older[0];\n }\n return chain;\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AACA,0BAA4C;AAM5C,yCAA4C;AA4B5C,6BAA6D;AAC7D,mCAIO;AACP,kCAAoE;AACpE,gCASO;AAWP,SAAS,SAAY,OAAa;AAChC,SAAO,gBAAgB,KAAK;AAC9B;AAEA,SAAS,WAAW,WAA2B;AAC7C,SAAO;AACT;AAEA,SAAS,QAAQ,EAAE,YAAY,QAAQ,GAAoD;AACzF,SAAO,GAAG,UAAU,IAAI,OAAO;AACjC;AAGA,SAAS,iBAAiB,GAAW,GAAmB;AACtD,MAAI,IAAI,GAAG;AACT,WAAO;AAAA,EACT;AACA,MAAI,IAAI,GAAG;AACT,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAEA,SAAS,kBAAkB,QAA4C;AACrE,SAAO;AAAA,IACL,WAAW,OAAO;AAAA,IAClB,QAAQ,OAAO,UAAU;AAAA,IACzB,YAAY,OAAO,cAAc;AAAA,IACjC,kBAAkB;AAAA,IAClB,SAAS,CAAC;AAAA,IACV,2BAAuB,iDAA4B;AAAA,IACnD,YAAY;AAAA,EACd;AACF;AAEA,SAAS,oBAAoB,SAA8C,SAAoC;AAC7G,aAAW,UAAU,SAAS;AAC5B,UAAM,SAAS,QAAQ,OAAO,SAAS;AACvC,QAAI,CAAC,QAAQ;AACX,YAAM,IAAI,qDAA2B,iDAAiD,OAAO,SAAS,EAAE;AAAA,IAC1G;AACA,WAAO,QAAQ,KAAK,GAAG,SAAS,OAAO,OAAO,CAAC;AAC/C,QAAI,OAAO,0BAA0B,MAAM;AACzC,aAAO,wBAAwB,SAAS,OAAO,qBAAqB;AAAA,IACtE;AAAA,EACF;AACF;AAEA,SAAS,uBAAuB,OAKf;AACf,QAAM,UAA+C,MAAM,mBACvD,SAAS,MAAM,iBAAiB,OAAO,IACvC,CAAC;AAEL,sEAA4B;AAAA,IAC1B,mBAAmB,IAAI,IAAI,OAAO,KAAK,OAAO,CAAC;AAAA,IAC/C,aAAa,MAAM;AAAA,IACnB,qBAAqB,MAAM;AAAA,IAC3B,mBAAmB,MAAM;AAAA,EAC3B,CAAC;AAED,aAAW,MAAM,MAAM,aAAa;AAClC,YAAQ,GAAG,SAAS,IAAI,kBAAkB,EAAE;AAAA,EAC9C;AAEA,sBAAoB,SAAS,MAAM,mBAAmB;AACtD,aAAW,cAAc,MAAM,mBAAmB;AAChD,UAAM,SAAS,QAAQ,WAAW,SAAS;AAC3C,QAAI,WAAW,QAAW;AACxB,YAAM,IAAI,qDAA2B,+CAA+C,WAAW,SAAS,EAAE;AAAA,IAC5G;AACA,WAAO,mBAAmB,SAAS,WAAW,gBAAgB;AAAA,EAChE;AAEA,SAAO;AAAA,IACL;AAAA,IACA,aAAa,MAAM,mBAAmB,SAAS,MAAM,iBAAiB,WAAW,IAAI;AAAA,IACrF,cAAc,MAAM,mBAAmB,SAAS,MAAM,iBAAiB,YAAY,IAAI;AAAA,EACzF;AACF;AAEA,SAAS,SAAY,OAAY,OAAe,WAAgE;AAC9G,QAAM,aAAS,8CAAsB,SAAS;AAC9C,QAAM,QAAQ,MAAM,MAAM,QAAQ,SAAS,KAAK;AAChD,SAAO;AAAA,IACL,MAAM;AAAA,IACN,YAAY;AAAA,MACV;AAAA,MACA,GAAI,SAAS,QAAQ,MAAM,SAAS,EAAE,qBAAiB,8CAAsB,SAAS,KAAK,EAAE,IAAI,CAAC;AAAA,MAClG,GAAI,SAAS,IAAI,EAAE,yBAAqB,8CAAsB,KAAK,IAAI,GAAG,SAAS,KAAK,CAAC,EAAE,IAAI,CAAC;AAAA,IAClG;AAAA,EACF;AACF;AAMO,IAAM,uBAAN,MAGiD;AAAA,EACrC,WAAW,oBAAI,IAA2C;AAAA,EAC1D,QAAQ,oBAAI,IAAqC;AAAA,EACjD,SAAS,oBAAI,IAA2B;AAAA,EAEzD,MAAM,cAAc,OAA0D;AAC5E,UAAM,MAAM,WAAW,MAAM,UAAU;AACvC,QAAI,KAAK,SAAS,IAAI,GAAG,GAAG;AAC1B,YAAM,IAAI,oDAA0B,MAAM,UAAU;AAAA,IACtD;AACA,UAAM,aAAa,MAAM;AACzB,QAAI,eAAe,MAAM;AACvB,iBAAW,UAAU,KAAK,SAAS,OAAO,GAAG;AAC3C,YAAI,OAAO,OAAO,cAAc,MAAM,aAAa,OAAO,OAAO,gBAAgB,YAAY;AAC3F,gBAAM,IAAI,yDAA+B,UAAU;AAAA,QACrD;AAAA,MACF;AAAA,IACF;AACA,UAAM,MAAM,oBAAI,KAAK;AACrB,UAAM,SAAwC;AAAA,MAC5C,WAAW,MAAM;AAAA,MACjB,YAAY,MAAM;AAAA,MAClB,oBAAoB,MAAM;AAAA,MAC1B,OAAO,SAAS,MAAM,KAAK;AAAA,MAC3B,OAAO;AAAA,MACP,cAAc;AAAA,MACd,aAAa;AAAA,MACb,QAAQ,MAAM,WAAW,OAAO,SAAS,MAAM,MAAM,IAAI;AAAA,MACzD,YAAY;AAAA,MACZ,YAAY;AAAA,MACZ,4BAA4B,KAAK,IAAI;AAAA,MACrC,SAAS;AAAA,QACP,mBAAmB;AAAA,QACnB,aAAa;AAAA,MACf;AAAA,MACA,UAAU,SAAS,MAAM,QAAQ;AAAA,MACjC,QAAQ,MAAM,WAAW,OAAO,SAAS,MAAM,MAAM,IAAI;AAAA,IAC3D;AACA,SAAK,SAAS,IAAI,KAAK,EAAE,QAAQ,SAAS,CAAC,EAAE,CAAC;AAC9C;AAAA,EACF;AAAA,EAEA,MAAM,cAAc,OAA0C;AAC5D,UAAM,OAAO,WAAW,MAAM,UAAU;AACxC,UAAM,SAAS,KAAK,SAAS,IAAI,IAAI;AACrC,QAAI,QAAQ,OAAO,cAAc,MAAM,WAAW;AAChD;AAAA,IACF;AACA,eAAW,UAAU,OAAO,SAAS;AACnC,YAAM,OAAO,QAAQ,EAAE,YAAY,MAAM,YAAY,SAAS,OAAO,CAAC;AACtE,WAAK,MAAM,OAAO,IAAI;AACtB,WAAK,OAAO,OAAO,IAAI;AAAA,IACzB;AACA,SAAK,SAAS,OAAO,IAAI;AAAA,EAC3B;AAAA,EAEA,MAAM,WAAW,OAA4E;AAC3F,UAAM,SAAS,KAAK,SAAS,IAAI,WAAW,MAAM,UAAU,CAAC;AAC7D,WAAO,QAAQ,OAAO,cAAc,MAAM,YAAY,SAAS,OAAO,MAAM,IAAI;AAAA,EAClF;AAAA,EAEA,MAAM,uBAAuB,OAAwF;AACnH,eAAW,UAAU,KAAK,SAAS,OAAO,GAAG;AAC3C,UAAI,OAAO,OAAO,cAAc,MAAM,aAAa,OAAO,OAAO,gBAAgB,MAAM,aAAa;AAClG,eAAO,SAAS,OAAO,MAAM;AAAA,MAC/B;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,cAAc,OAA0D;AAC5E,UAAM,MAAM,WAAW,MAAM,UAAU;AACvC,UAAM,SAAS,KAAK,SAAS,IAAI,GAAG;AACpC,QAAI,QAAQ,OAAO,cAAc,MAAM,WAAW;AAChD,YAAM,IAAI,+CAAqB,MAAM,UAAU;AAAA,IACjD;AACA,QAAI,MAAM,UAAU,QAAW;AAC7B,UAAI,OAAO,OAAO,MAAM,SAAS,aAAa;AAC5C,cAAM,IAAI,qDAA2B,WAAW,MAAM,UAAU,oCAAoC;AAAA,MACtG;AACA,aAAO,OAAO,QAAQ,SAAS,MAAM,KAAK;AAAA,IAC5C;AACA,QAAI,MAAM,UAAU,QAAW;AAC7B,aAAO,OAAO,QAAQ,MAAM;AAAA,IAC9B;AACA,QAAI,MAAM,aAAa,QAAW;AAChC,aAAO,OAAO,WAAW,SAAS,MAAM,QAAQ;AAAA,IAClD;AACA,UAAM,MAAM,KAAK,IAAI;AACrB,WAAO,OAAO,aAAa,IAAI,KAAK,GAAG;AACvC,WAAO,OAAO,6BAA6B;AAC3C;AAAA,EACF;AAAA,EAEA,MAAM,aACJ,OACiF;AACjF,UAAM,UAA2C,CAAC;AAClD,UAAM,sBAAsB,MAAM;AAClC,eAAW,UAAU,KAAK,SAAS,OAAO,GAAG;AAC3C,UAAI,OAAO,OAAO,cAAc,MAAM,WAAW;AAC/C;AAAA,MACF;AACA,UACE,MAAM,aAAa,WAClB,OAAO,OAAO,MAAM,SAAS,eAAe,OAAO,OAAO,MAAM,OAAO,MAAM,WAC9E;AACA;AAAA,MACF;AACA,UAAI,wBAAwB,QAAW;AACrC,cAAM,iBACJ,OAAO,OAAO,mBAAmB,eAAe,oBAAoB;AACtE,cAAM,eACJ,OAAO,OAAO,MAAM,SAAS,eAAe,oBAAoB,UAAU,SAAS,OAAO,OAAO,MAAM,EAAE;AAC3G,YAAI,CAAC,kBAAkB,CAAC,cAAc;AACpC;AAAA,QACF;AAAA,MACF;AACA,YAAM,iBAAiB,MAAM;AAC7B,UAAI,mBAAmB,QAAW;AAChC,cAAM,UAAU,OAAO,QAAQ,cAAc;AAC7C,YAAI,QAAQ,WAAW,GAAG;AACxB,cAAI,OAAO,KAAK,OAAO,OAAO,QAAQ,EAAE,SAAS,GAAG;AAClD;AAAA,UACF;AAAA,QACF,WAAW,CAAC,QAAQ,MAAM,CAAC,CAAC,KAAK,KAAK,MAAM,OAAO,OAAO,SAAS,GAAG,MAAM,KAAK,GAAG;AAClF;AAAA,QACF;AAAA,MACF;AACA,UAAI,MAAM,gBAAgB,UAAa,OAAO,OAAO,QAAQ,SAAS,MAAM,aAAa;AACvF;AAAA,MACF;AACA,UAAI,MAAM,cAAc,UAAa,OAAO,OAAO,QAAQ,OAAO,MAAM,WAAW;AACjF;AAAA,MACF;AACA,YAAM,YAAY,OAAO,OAAO,WAAW,QAAQ;AACnD,UAAI,MAAM,oBAAoB,UAAa,YAAY,MAAM,gBAAgB,QAAQ,GAAG;AACtF;AAAA,MACF;AACA,UAAI,MAAM,kBAAkB,UAAa,YAAY,MAAM,cAAc,QAAQ,GAAG;AAClF;AAAA,MACF;AACA,cAAQ,KAAK,OAAO,MAAM;AAAA,IAC5B;AACA,YAAQ,KAAK,CAAC,GAAG,MAAM;AACrB,YAAM,QAAQ,EAAE,WAAW,QAAQ;AACnC,YAAM,QAAQ,EAAE,WAAW,QAAQ;AACnC,UAAI,UAAU,OAAO;AACnB,eAAO,MAAM,UAAU,QAAQ,QAAQ,QAAQ,QAAQ;AAAA,MACzD;AAEA,aAAO,MAAM,UAAU,QACnB,iBAAiB,EAAE,YAAY,EAAE,UAAU,IAC3C,iBAAiB,EAAE,YAAY,EAAE,UAAU;AAAA,IACjD,CAAC;AAED,QAAI,WAAW;AACf,UAAM,aAAS,wDAA2B,MAAM,UAAU;AAC1D,QAAI,QAAQ;AACV,YAAM,aAAa,IAAI,KAAK,OAAO,UAAU,EAAE,QAAQ;AACvD,iBAAW,QAAQ,OAAO,YAAU;AAClC,cAAM,IAAI,OAAO,WAAW,QAAQ;AACpC,cAAM,QAAQ,iBAAiB,OAAO,YAAY,OAAO,UAAU;AACnE,YAAI,MAAM,UAAU,OAAO;AACzB,iBAAO,IAAI,cAAe,MAAM,cAAc,QAAQ;AAAA,QACxD;AACA,eAAO,IAAI,cAAe,MAAM,cAAc,QAAQ;AAAA,MACxD,CAAC;AAAA,IACH;AAEA,UAAM,WAAO,qDAAwB,UAAU,MAAM,OAAO,SAAO,IAAI,WAAW,YAAY,CAAC;AAC/F,WAAO,EAAE,MAAM,SAAS,KAAK,IAAI,GAAG,YAAY,KAAK,WAAW;AAAA,EAClE;AAAA,EAEA,MAAM,WAAW,OAAoD;AAInE,UAAM,OAAO,WAAW,MAAM,KAAK,UAAU;AAC7C,UAAM,SAAS,KAAK,SAAS,IAAI,IAAI;AACrC,QAAI,CAAC,QAAQ;AACX,YAAM,IAAI,+CAAqB,MAAM,KAAK,UAAU;AAAA,IACtD;AAEA,UAAM,iBAAiB,MAAM,KAAK;AAClC,QAAI;AACJ,QAAI,mBAAmB,MAAM;AAC3B,YAAM,UAAU,QAAQ,EAAE,YAAY,MAAM,KAAK,YAAY,SAAS,eAAe,CAAC;AACtF,YAAM,OAAO,KAAK,MAAM,IAAI,OAAO;AAGnC,UAAI,SAAS,QAAW;AACtB,YAAI,KAAK,MAAM,WAAW,WAAW;AACnC,gBAAM,IAAI,mDAAyB,cAAc;AAAA,QACnD;AACA,2BAAmB,KAAK;AAAA,MAC1B;AAAA,IACF;AAEA,UAAM,OAAO,QAAQ,MAAM,IAAI;AAC/B,QAAI,KAAK,MAAM,IAAI,IAAI,GAAG;AACxB,YAAM,IAAI,iDAAuB,MAAM,KAAK,OAAO;AAAA,IACrD;AAEA,UAAM,WAAW,uBAAuB;AAAA,MACtC;AAAA,MACA,aAAa,MAAM;AAAA,MACnB,qBAAqB,MAAM;AAAA,MAC3B,mBAAmB,MAAM;AAAA,IAC3B,CAAC;AAED,UAAM,aAAsC;AAAA,MAC1C,GAAG,SAAS,MAAM,IAAI;AAAA,MACtB;AAAA,IACF;AAEA,SAAK,MAAM,IAAI,MAAM,UAAU;AAC/B,SAAK,OAAO,IAAI,MAAM,CAAC,CAAC;AACxB,WAAO,QAAQ,KAAK,MAAM,KAAK,OAAO;AACtC,WAAO,OAAO,eAAe,MAAM,KAAK;AACxC,WAAO,OAAO,QAAQ,eAAe;AACrC,WAAO,OAAO,6BAA6B,KAAK,IAAI;AACpD,WAAO,OAAO,aAAa,oBAAI,KAAK;AACpC,QAAI,MAAM,sCAAsC,QAAQ,OAAO,OAAO,UAAU,MAAM;AACpF,aAAO,OAAO,QAAQ,MAAM;AAAA,IAC9B;AAAA,EACF;AAAA,EAEA,MAAM,iBAAiB,OAAgE;AACrF,UAAM,OAAO,QAAQ,KAAK;AAC1B,UAAM,OAAO,KAAK,YAAY,MAAM,YAAY,MAAM,OAAO;AAE7D,QAAI,KAAK,MAAM,WAAW,WAAW;AACnC,YAAM,iBAAoC;AAAA,QACxC,QAAQ;AAAA,QACR,QAAQ,MAAM;AAAA,QACd,eAAc,oBAAI,KAAK,GAAE,YAAY;AAAA,MACvC;AACA,WAAK,QAAQ;AACb,WAAK,aAAa,oBAAI,KAAK;AAC3B,YAAM,OAAO,KAAK,OAAO,IAAI,IAAI;AACjC,UAAI,MAAM;AACR,aAAK,KAAK,SAAS,MAAM,eAAe,CAAC;AAAA,MAC3C;AACA,WAAK,0BAA0B,MAAM,YAAY,KAAK,YAAY,cAAc;AAAA,IAClF;AAEA,WAAO,SAAS,IAAI;AAAA,EACtB;AAAA,EAEA,MAAM,QAAQ,OAAmE;AAC/E,UAAM,OAAO,KAAK,MAAM,IAAI,QAAQ,KAAK,CAAC;AAC1C,WAAO,OAAO,SAAS,IAAI,IAAI;AAAA,EACjC;AAAA,EAEA,MAAM,UACJ,OAC0F;AAC1F,UAAM,SAAS,KAAK,SAAS,IAAI,WAAW,MAAM,UAAU,CAAC;AAC7D,QAAI,CAAC,QAAQ;AACX,YAAM,IAAI,+CAAqB,MAAM,UAAU;AAAA,IACjD;AACA,UAAM,UAAU,OAAO,QAAQ,IAAI,QAAM;AACvC,YAAM,OAAO,KAAK,MAAM,IAAI,QAAQ,EAAE,YAAY,MAAM,YAAY,SAAS,GAAG,CAAC,CAAC;AAClF,UAAI,CAAC,MAAM;AACT,cAAM,IAAI,4CAAkB,EAAE;AAAA,MAChC;AACA,YAAM,EAAE,UAAU,GAAG,IAAI,IAAI,SAAS,IAAI;AAC1C,WAAK;AACL,aAAO;AAAA,IACT,CAAC;AACD,WAAO,SAAS,SAAS,MAAM,OAAO,MAAM,UAAU;AAAA,EACxD;AAAA,EAEA,MAAM,gBAAgB,OAA4C;AAEhE,UAAM,OAAO,QAAQ,KAAK;AAC1B,UAAM,OAAO,KAAK,YAAY,MAAM,YAAY,MAAM,OAAO;AAC7D,QAAI,KAAK,MAAM,WAAW,WAAW;AACnC,YAAM,IAAI,8CAAoB,MAAM,SAAS,KAAK,KAAK;AAAA,IACzD;AACA,SAAK,QAAQ,SAAS,MAAM,KAAK;AACjC,SAAK,aAAa,oBAAI,KAAK;AAC3B,UAAM,OAAO,KAAK,OAAO,IAAI,IAAI;AACjC,QAAI,MAAM;AACR,WAAK,KAAK,SAAS,MAAM,eAAe,CAAC;AAAA,IAC3C;AACA,SAAK,0BAA0B,MAAM,YAAY,KAAK,YAAY,MAAM,KAAK;AAAA,EAC/E;AAAA,EAEA,MAAM,eAAe,OAA2C;AAC9D,SAAK,mBAAmB,MAAM,YAAY,MAAM,OAAO;AACvD,UAAM,OAAO,QAAQ,KAAK;AAC1B,UAAM,OAAO,KAAK,OAAO,IAAI,IAAI;AACjC,QAAI,CAAC,MAAM;AACT,YAAM,IAAI,4CAAkB,MAAM,OAAO;AAAA,IAC3C;AACA,SAAK,KAAK,GAAG,SAAS,MAAM,MAAM,CAAC;AACnC;AAAA,EACF;AAAA;AAAA,EAGQ,0BAA0B,WAAmB,YAAkB,OAAgC;AACrG,UAAM,SAAS,KAAK,SAAS,IAAI,WAAW,SAAS,CAAC;AACtD,QAAI,CAAC,QAAQ;AACX,YAAM,IAAI,+CAAqB,SAAS;AAAA,IAC1C;AACA,UAAM,aAAa,KAAK,MAAM,MAAM,YAAY,IAAI,WAAW,QAAQ;AACvE,UAAM,WAAW,MAAM,SAAS;AAChC,QAAI,aAAa,QAAW;AAC1B,aAAO,OAAO,QAAQ,qBAAqB,OAAO,OAAO,QAAQ,qBAAqB,KAAK;AAAA,IAC7F;AACA,WAAO,OAAO,QAAQ,qBAAqB,aAAa,IAAI,KAAK,MAAM,UAAU,IAAI;AAAA,EACvF;AAAA,EAEQ,YAAY,WAAmB,QAAyC;AAC9E,UAAM,OAAO,KAAK,MAAM,IAAI,QAAQ,EAAE,YAAY,WAAW,SAAS,OAAO,CAAC,CAAC;AAC/E,QAAI,CAAC,MAAM;AACT,YAAM,IAAI,4CAAkB,MAAM;AAAA,IACpC;AACA,WAAO;AAAA,EACT;AAAA,EAEQ,mBAAmB,WAAmB,QAAyC;AACrF,UAAM,OAAO,KAAK,YAAY,WAAW,MAAM;AAC/C,QAAI,KAAK,MAAM,WAAW,WAAW;AACnC,YAAM,IAAI,8CAAoB,QAAQ,KAAK,KAAK;AAAA,IAClD;AACA,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,WAAW,OAAuC;AACtD,UAAM,OAAO,KAAK,mBAAmB,MAAM,YAAY,MAAM,OAAO;AACpE,eAAW,UAAU,MAAM,SAAS;AAClC,WAAK,SAAS,QAAQ,OAAO,SAAS,IAAI,SAAS,MAAM;AAAA,IAC3D;AACA,SAAK,aAAa,oBAAI,KAAK;AAC3B;AAAA,EACF;AAAA,EAEA,MAAM,cAAc,OAA0C;AAC5D,QAAI,MAAM,WAAW,WAAW,GAAG;AACjC;AAAA,IACF;AACA,UAAM,OAAO,KAAK,mBAAmB,MAAM,YAAY,MAAM,OAAO;AACpE,eAAW,MAAM,MAAM,YAAY;AACjC,cAAQ,eAAe,KAAK,SAAS,SAAS,EAAE;AAAA,IAClD;AACA,SAAK,aAAa,oBAAI,KAAK;AAC3B;AAAA,EACF;AAAA,EAEA,MAAM,sBAAsB,OAAkD;AAC5E,UAAM,OAAO,KAAK,mBAAmB,MAAM,YAAY,MAAM,OAAO;AACpE,UAAM,SAAS,KAAK,SAAS,QAAQ,MAAM,SAAS;AACpD,QAAI,CAAC,QAAQ;AACX,YAAM,IAAI,qDAA2B,qBAAqB,MAAM,SAAS,EAAE;AAAA,IAC7E;AACA,WAAO,QAAQ,KAAK,GAAG,SAAS,MAAM,OAAO,CAAC;AAC9C,QAAI,MAAM,0BAA0B,MAAM;AACxC,aAAO,wBAAwB,SAAS,MAAM,qBAAqB;AAAA,IACrE;AACA,QAAI,MAAM,eAAe,MAAM;AAC7B,aAAO,aAAa,SAAS,MAAM,UAAU;AAAA,IAC/C;AACA,SAAK,aAAa,oBAAI,KAAK;AAC3B;AAAA,EACF;AAAA,EAEA,MAAM,uBAAuB,OAAmD;AAC9E,UAAM,OAAO,KAAK,mBAAmB,MAAM,YAAY,MAAM,OAAO;AACpE,UAAM,WAAW,MAAM,MAAM;AAC7B,UAAM,SAAS,KAAK,SAAS,QAAQ,QAAQ;AAC7C,QAAI,CAAC,QAAQ;AACX,YAAM,IAAI,qDAA2B,qBAAqB,QAAQ,EAAE;AAAA,IACtE;AACA,WAAO,UAAU,SAAS,MAAM,MAAM,OAAO;AAC7C,WAAO,wBAAwB,SAAS,MAAM,MAAM,qBAAqB;AACzE,SAAK,aAAa,oBAAI,KAAK;AAC3B;AAAA,EACF;AAAA,EAEA,MAAM,gBAAgB,OAA4C;AAChE,UAAM,OAAO,KAAK,mBAAmB,MAAM,YAAY,MAAM,OAAO;AACpE,SAAK,SAAS,gBAAgB,CAAC;AAC/B,eAAW,UAAU,MAAM,aAAa;AACtC,WAAK,SAAS,YAAY,OAAO,EAAE,IAAI,SAAS,MAAM;AAAA,IACxD;AACA,SAAK,aAAa,oBAAI,KAAK;AAC3B;AAAA,EACF;AAAA,EAEA,MAAM,iBAAiB,OAA6C;AAClE,UAAM,OAAO,KAAK,mBAAmB,MAAM,YAAY,MAAM,OAAO;AACpE,SAAK,SAAS,eAAe,SAAS,MAAM,YAAY;AACxD,SAAK,aAAa,oBAAI,KAAK;AAC3B;AAAA,EACF;AAAA,EAEA,MAAM,2BAA2B,OAAuD;AACtF,UAAM,OAAO,KAAK,mBAAmB,MAAM,YAAY,MAAM,OAAO;AACpE,UAAM,SAAS,KAAK,SAAS,QAAQ,MAAM,SAAS;AACpD,QAAI,CAAC,QAAQ;AACX,YAAM,IAAI,qDAA2B,qBAAqB,MAAM,SAAS,EAAE;AAAA,IAC7E;AACA,WAAO,qBAAqB,CAAC;AAC7B,QAAI,MAAM,UAAU,MAAM;AACxB,cAAQ,eAAe,OAAO,kBAAkB,MAAM,GAAG;AACzD,UAAI,OAAO,KAAK,OAAO,gBAAgB,EAAE,WAAW,GAAG;AACrD,eAAO,mBAAmB;AAAA,MAC5B;AAAA,IACF,OAAO;AACL,aAAO,iBAAiB,MAAM,GAAG,IAAI,SAAS,MAAM,KAAK;AAAA,IAC3D;AACA,SAAK,aAAa,oBAAI,KAAK;AAC3B;AAAA,EACF;AAAA,EAEA,MAAM,eAAe,OAGlB;AACD,SAAK,YAAY,MAAM,YAAY,MAAM,OAAO;AAChD,UAAM,OAAO,KAAK,OAAO,IAAI,QAAQ,KAAK,CAAC;AAC3C,QAAI,CAAC,MAAM;AACT,YAAM,IAAI,4CAAkB,MAAM,OAAO;AAAA,IAC3C;AACA,UAAM,UAAU,CAAC,GAAG,IAAI,EAAE;AAAA,MAAK,CAAC,GAAG,MACjC,MAAM,UAAU,SAAS,EAAE,GAAG,cAAc,EAAE,EAAE,IAAI,EAAE,GAAG,cAAc,EAAE,EAAE;AAAA,IAC7E;AACA,UAAM,OAAO,SAAS,SAAS,MAAM,OAAO,MAAM,UAAU;AAC5D,WAAO,EAAE,MAAM,SAAS,KAAK,IAAI,GAAG,YAAY,KAAK,WAAW;AAAA,EAClE;AAAA,EAEA,MAAM,kBAAkB,OAGrB;AACD,UAAM,SAAS,KAAK,SAAS,IAAI,WAAW,MAAM,UAAU,CAAC;AAC7D,QAAI,CAAC,QAAQ;AACX,YAAM,IAAI,+CAAqB,MAAM,UAAU;AAAA,IACjD;AAEA,UAAM,gBAAgB,MAAM,eAAe,SAAY,aAAY,0DAA4B,MAAM,UAAU;AAC/G,UAAM,aAAa,eAAe,gBAAgB,MAAM,gBAAgB,OAAO,OAAO;AACtF,QAAI,eAAe,MAAM;AACvB,aAAO,EAAE,MAAM,CAAC,GAAG,YAAY,EAAE,OAAO,MAAM,MAAM,EAAE;AAAA,IACxD;AACA,UAAM,SAAiC;AAAA,MACrC,cAAc;AAAA,MACd,QAAQ,eAAe,UAAU;AAAA,IACnC;AAEA,UAAM,SAAS,KAAK,MAAM,IAAI,QAAQ,EAAE,YAAY,MAAM,YAAY,SAAS,OAAO,aAAa,CAAC,CAAC;AACrG,QAAI,CAAC,QAAQ;AACX,YAAM,IAAI,4CAAkB,OAAO,YAAY;AAAA,IACjD;AACA,UAAM,UAAU,KAAK,qBAAqB,MAAM,YAAY,MAAM;AAClE,UAAM,YAAgC,CAAC;AACvC,eAAW,UAAU,CAAC,GAAG,OAAO,EAAE,QAAQ,GAAG;AAC3C,YAAM,OAAO,KAAK,OAAO,IAAI,QAAQ,EAAE,YAAY,MAAM,YAAY,SAAS,OAAO,CAAC,CAAC,KAAK,CAAC;AAC7F,iBAAW,SAAS,CAAC,GAAG,IAAI,EAAE,KAAK,CAAC,GAAG,MAAM,EAAE,GAAG,cAAc,EAAE,EAAE,CAAC,GAAG;AACtE,kBAAU,KAAK,EAAE,SAAS,QAAQ,MAAM,CAAC;AAAA,MAC3C;AAAA,IACF;AACA,UAAM,WAAO;AAAA,MACX,UAAU,MAAM,OAAO,QAAQ,OAAO,SAAS,MAAM,QAAQ,CAAC;AAAA,MAC9D,MAAM;AAAA,MACN;AAAA,IACF;AACA,WAAO,EAAE,MAAM,SAAS,KAAK,IAAI,GAAG,YAAY,KAAK,WAAW;AAAA,EAClE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOQ,qBAAqB,WAAmB,QAA2C;AACzF,UAAM,QAAQ,CAAC,GAAG,OAAO,cAAc,OAAO,OAAO;AACrD,UAAM,OAAO,IAAI,IAAI,KAAK;AAC1B,QAAI,WAAW,MAAM,CAAC;AACtB,WAAO,YAAY,aAAa,OAAO,SAAS;AAC9C,YAAM,SAAS,KAAK,MAAM,IAAI,QAAQ,EAAE,YAAY,WAAW,SAAS,SAAS,CAAC,CAAC;AACnF,UAAI,CAAC,QAAQ;AACX;AAAA,MACF;AACA,YAAM,QAAQ,OAAO,aAAa,OAAO,QAAM,CAAC,KAAK,IAAI,EAAE,CAAC;AAC5D,UAAI,MAAM,WAAW,GAAG;AACtB;AAAA,MACF;AACA,YAAM,QAAQ,GAAG,KAAK;AACtB,iBAAW,MAAM,OAAO;AACtB,aAAK,IAAI,EAAE;AAAA,MACb;AACA,iBAAW,MAAM,CAAC;AAAA,IACpB;AACA,WAAO;AAAA,EACT;AACF;","names":[]}
|