@grackle-ai/core 0.131.0 → 0.132.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -2
- package/dist/ahp-session-state.d.ts +168 -0
- package/dist/ahp-session-state.d.ts.map +1 -0
- package/dist/ahp-session-state.js +469 -0
- package/dist/ahp-session-state.js.map +1 -0
- package/dist/auto-reconnect.js +5 -1
- package/dist/auto-reconnect.js.map +1 -1
- package/dist/budget-checker.d.ts.map +1 -1
- package/dist/budget-checker.js +2 -1
- package/dist/budget-checker.js.map +1 -1
- package/dist/compute-task-status.d.ts.map +1 -1
- package/dist/compute-task-status.js +1 -3
- package/dist/compute-task-status.js.map +1 -1
- package/dist/concurrency.d.ts.map +1 -1
- package/dist/concurrency.js +1 -1
- package/dist/concurrency.js.map +1 -1
- package/dist/credential-bundle.d.ts +23 -2
- package/dist/credential-bundle.d.ts.map +1 -1
- package/dist/credential-bundle.js +30 -26
- package/dist/credential-bundle.js.map +1 -1
- package/dist/event-bus.d.ts.map +1 -1
- package/dist/event-bus.js.map +1 -1
- package/dist/event-processor.d.ts +2 -2
- package/dist/event-processor.d.ts.map +1 -1
- package/dist/event-processor.js +136 -38
- package/dist/event-processor.js.map +1 -1
- package/dist/github-account-import.d.ts.map +1 -1
- package/dist/github-account-import.js +3 -1
- package/dist/github-account-import.js.map +1 -1
- package/dist/grpc-shared-utils.d.ts.map +1 -1
- package/dist/grpc-shared-utils.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/log-writer.d.ts.map +1 -1
- package/dist/log-writer.js +1 -5
- package/dist/log-writer.js.map +1 -1
- package/dist/logger.d.ts.map +1 -1
- package/dist/logger.js.map +1 -1
- package/dist/notification-router.d.ts.map +1 -1
- package/dist/notification-router.js +3 -1
- package/dist/notification-router.js.map +1 -1
- package/dist/persona-mapper.d.ts.map +1 -1
- package/dist/persona-mapper.js.map +1 -1
- package/dist/pipe-delivery.d.ts.map +1 -1
- package/dist/pipe-delivery.js +11 -10
- package/dist/pipe-delivery.js.map +1 -1
- package/dist/processor-registry.d.ts.map +1 -1
- package/dist/processor-registry.js.map +1 -1
- package/dist/reanimate-agent.d.ts.map +1 -1
- package/dist/reanimate-agent.js +7 -9
- package/dist/reanimate-agent.js.map +1 -1
- package/dist/session-action-recorder.d.ts +2 -1
- package/dist/session-action-recorder.d.ts.map +1 -1
- package/dist/session-action-recorder.js +8 -1
- package/dist/session-action-recorder.js.map +1 -1
- package/dist/session-recovery.d.ts +1 -1
- package/dist/session-recovery.d.ts.map +1 -1
- package/dist/session-recovery.js +15 -13
- package/dist/session-recovery.js.map +1 -1
- package/dist/signals/signal-delivery.d.ts.map +1 -1
- package/dist/signals/signal-delivery.js +2 -2
- package/dist/signals/signal-delivery.js.map +1 -1
- package/dist/spawn-context-registry.d.ts.map +1 -1
- package/dist/spawn-context-registry.js.map +1 -1
- package/dist/stream-hub.d.ts.map +1 -1
- package/dist/stream-hub.js +6 -2
- package/dist/stream-hub.js.map +1 -1
- package/dist/stream-registry.d.ts.map +1 -1
- package/dist/stream-registry.js +18 -8
- package/dist/stream-registry.js.map +1 -1
- package/dist/task-session.d.ts.map +1 -1
- package/dist/task-session.js +37 -18
- package/dist/task-session.js.map +1 -1
- package/dist/telemetry.d.ts.map +1 -1
- package/dist/telemetry.js.map +1 -1
- package/dist/test-utils/mock-database.d.ts +2 -0
- package/dist/test-utils/mock-database.d.ts.map +1 -1
- package/dist/test-utils/mock-database.js +20 -3
- package/dist/test-utils/mock-database.js.map +1 -1
- package/dist/token-push.d.ts +3 -2
- package/dist/token-push.d.ts.map +1 -1
- package/dist/token-push.js +14 -21
- package/dist/token-push.js.map +1 -1
- package/dist/trace-context.d.ts.map +1 -1
- package/dist/trace-context.js +4 -4
- package/dist/trace-context.js.map +1 -1
- package/dist/transcript.d.ts.map +1 -1
- package/dist/transcript.js +3 -1
- package/dist/transcript.js.map +1 -1
- package/dist/version-check.d.ts.map +1 -1
- package/dist/version-check.js +19 -4
- package/dist/version-check.js.map +1 -1
- package/package.json +12 -10
package/README.md
CHANGED
|
@@ -32,8 +32,10 @@ This package is consumed by `@grackle-ai/server` (the orchestrator) which wires
|
|
|
32
32
|
```typescript
|
|
33
33
|
import {
|
|
34
34
|
registerGrackleRoutes,
|
|
35
|
-
registerAdapter,
|
|
36
|
-
|
|
35
|
+
registerAdapter,
|
|
36
|
+
startHeartbeat,
|
|
37
|
+
emit,
|
|
38
|
+
subscribe,
|
|
37
39
|
createWsBridge,
|
|
38
40
|
logger,
|
|
39
41
|
} from "@grackle-ai/core";
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Session state manager (AHP HR1b / RFC #1292).
|
|
3
|
+
*
|
|
4
|
+
* Wraps the agent-event mapper, AHP sessionReducer, and snapshot store into
|
|
5
|
+
* a single per-session class. Each instance maintains the live `SessionState`
|
|
6
|
+
* by folding mapped actions through the reducer, and persists checkpoints to
|
|
7
|
+
* the `session_snapshots` table.
|
|
8
|
+
*
|
|
9
|
+
* @module ahp-session-state
|
|
10
|
+
*/
|
|
11
|
+
import { type AgentEventFields, type MapperContext } from "@grackle-ai/common";
|
|
12
|
+
import { type SessionState } from "@grackle-ai/ahp";
|
|
13
|
+
import { type SessionActionQuery, type SessionActionRow, type SnapshotRecord, type SessionSnapshotRow } from "@grackle-ai/database";
|
|
14
|
+
/**
|
|
15
|
+
* Persistence interface for `SessionStateManager`.
|
|
16
|
+
*
|
|
17
|
+
* Injecting a custom implementation lets unit and integration tests exercise
|
|
18
|
+
* the full processEvent → snapshot → reconstruct pipeline against an in-memory
|
|
19
|
+
* store instead of a real SQLite database.
|
|
20
|
+
*/
|
|
21
|
+
export interface SessionStore {
|
|
22
|
+
/** Persist a snapshot of the current `SessionState` and `MapperContext`. */
|
|
23
|
+
persistSnapshot(record: SnapshotRecord): void;
|
|
24
|
+
/** Load the latest snapshot(s) for a session, newest first. */
|
|
25
|
+
querySnapshot(sessionId: string, limit?: number): SessionSnapshotRow[];
|
|
26
|
+
/** Load session actions for replay, oldest first. */
|
|
27
|
+
querySessionActions(query: SessionActionQuery): SessionActionRow[];
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Callback for snapshot results.
|
|
31
|
+
*/
|
|
32
|
+
export interface SnapshotResult {
|
|
33
|
+
/** Whether a snapshot was persisted. */
|
|
34
|
+
persisted: boolean;
|
|
35
|
+
/** The ULID of the last action included, or `undefined` if nothing was saved. */
|
|
36
|
+
lastSeq?: string;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Options for creating a `SessionStateManager`.
|
|
40
|
+
*/
|
|
41
|
+
export interface SessionStateManagerOptions {
|
|
42
|
+
/** Initial `SessionState` from a prior reconstruction (skips `createInitialState`). */
|
|
43
|
+
initialSnapshot?: SessionState;
|
|
44
|
+
/**
|
|
45
|
+
* Custom persistence store. Defaults to the real SQLite-backed store.
|
|
46
|
+
* Pass an in-memory implementation for testing.
|
|
47
|
+
*/
|
|
48
|
+
store?: SessionStore;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Per-session state manager that processes AgentEvents through the AHP mapper
|
|
52
|
+
* and reducer, maintains live SessionState, and persists periodic snapshots.
|
|
53
|
+
*/
|
|
54
|
+
export declare class SessionStateManager {
|
|
55
|
+
/**
|
|
56
|
+
* Event types that correspond to rows fed through `SessionStateManager.processEvent()`
|
|
57
|
+
* in the live pipeline. Rows with other types (e.g. `signal`, `widget`) are recorded in
|
|
58
|
+
* `session_actions` by other code paths but were never processed by the state manager,
|
|
59
|
+
* so replaying them would incorrectly advance `context.eventIndex`.
|
|
60
|
+
*
|
|
61
|
+
* "user_input" is intentionally absent — it is handled separately by remapping it to
|
|
62
|
+
* "turn_started" before calling `mapAgentEvent`.
|
|
63
|
+
*/
|
|
64
|
+
private static readonly AGENT_EVENT_TYPES;
|
|
65
|
+
/** The current SessionState (built by folding mapped actions). */
|
|
66
|
+
private state;
|
|
67
|
+
/** Mapper context maintained across events in the stream. */
|
|
68
|
+
private context;
|
|
69
|
+
/** Current session ID. */
|
|
70
|
+
private sessionId;
|
|
71
|
+
/** Number of actions since last snapshot flush. */
|
|
72
|
+
private actionCountSinceLastFlush;
|
|
73
|
+
/** Persistence store (real DB by default; injectable for tests). */
|
|
74
|
+
private store;
|
|
75
|
+
/**
|
|
76
|
+
* Number of actions between automatic snapshot flushes.
|
|
77
|
+
* Set to `0` to disable count-based flushing only; event-triggered
|
|
78
|
+
* flushes (turn_complete, terminal status, shutdown) still occur.
|
|
79
|
+
*/
|
|
80
|
+
snapshotThreshold: number;
|
|
81
|
+
/**
|
|
82
|
+
* Set to true when the initial prompt is injected as turn_started.
|
|
83
|
+
* The first runtime turn_started for the same turn is then skipped
|
|
84
|
+
* to avoid a duplicate SessionTurnStarted action.
|
|
85
|
+
*/
|
|
86
|
+
private injectedInitialTurn;
|
|
87
|
+
/**
|
|
88
|
+
* Create a new SessionStateManager.
|
|
89
|
+
*
|
|
90
|
+
* @param sessionId - The session ID to manage.
|
|
91
|
+
* @param options - Optional initial snapshot and persistence store.
|
|
92
|
+
*/
|
|
93
|
+
constructor(sessionId: string, options?: SessionStateManagerOptions);
|
|
94
|
+
/**
|
|
95
|
+
* Process a single AgentEvent through the mapper and reducer,
|
|
96
|
+
* and flush a snapshot if the threshold or turn_complete is reached.
|
|
97
|
+
*
|
|
98
|
+
* @param event - The AgentEvent to process.
|
|
99
|
+
* @param serverSeq - Monotonic ULID of the session_action record for this event.
|
|
100
|
+
* Used to anchor snapshots to the real action sequence for reconstruction.
|
|
101
|
+
* @returns The last action's ULID included in the snapshot, or `undefined`
|
|
102
|
+
* if no actions were produced or the threshold was not reached.
|
|
103
|
+
*/
|
|
104
|
+
processEvent(event: AgentEventFields, serverSeq: string): string | undefined;
|
|
105
|
+
/**
|
|
106
|
+
* Mark that the initial prompt was injected as turn_started.
|
|
107
|
+
* The next runtime turn_started will be skipped to avoid a duplicate.
|
|
108
|
+
*/
|
|
109
|
+
markInjectedInitialTurn(): void;
|
|
110
|
+
/**
|
|
111
|
+
* Get the current SessionState.
|
|
112
|
+
*
|
|
113
|
+
* Returns a deep clone frozen to prevent callers from mutating the
|
|
114
|
+
* manager's internal state.
|
|
115
|
+
*
|
|
116
|
+
* @returns A frozen deep clone of the current state.
|
|
117
|
+
*/
|
|
118
|
+
getState(): SessionState;
|
|
119
|
+
/**
|
|
120
|
+
* Get the current mapper context (useful for debugging or external state sync).
|
|
121
|
+
*
|
|
122
|
+
* Returns a deep clone frozen to prevent callers from mutating the
|
|
123
|
+
* manager's internal state.
|
|
124
|
+
*
|
|
125
|
+
* @returns A frozen deep clone of the current context.
|
|
126
|
+
*/
|
|
127
|
+
getContext(): MapperContext;
|
|
128
|
+
/**
|
|
129
|
+
* Persist a snapshot of the current SessionState and MapperContext to the store.
|
|
130
|
+
*
|
|
131
|
+
* Serializes key fields from SessionState (summary, lifecycle, turns,
|
|
132
|
+
* activeTurn, steeringMessage, queuedMessages, inputRequests, config, _meta)
|
|
133
|
+
* and the full MapperContext into JSON. Excludes serverTools, activeClient,
|
|
134
|
+
* and customizations.
|
|
135
|
+
*
|
|
136
|
+
* @param lastSeq - ULID string of the last action included in this snapshot.
|
|
137
|
+
* @returns Result describing whether a snapshot was persisted.
|
|
138
|
+
*/
|
|
139
|
+
snapshot(lastSeq?: string): SnapshotResult;
|
|
140
|
+
/**
|
|
141
|
+
* Clear internal state. Call on session shutdown.
|
|
142
|
+
*/
|
|
143
|
+
clear(): void;
|
|
144
|
+
/**
|
|
145
|
+
* Reconstruct SessionState from the latest snapshot plus delta actions.
|
|
146
|
+
*
|
|
147
|
+
* Strategy:
|
|
148
|
+
* - If the snapshot includes a `mapperContext`: delta replay — replay only the
|
|
149
|
+
* actions since the snapshot using the stored context (O(delta)).
|
|
150
|
+
* - If the snapshot is missing a `mapperContext` (older snapshot): full replay —
|
|
151
|
+
* replay all session_actions from the start with a fresh context (O(n) fallback).
|
|
152
|
+
* - If there is no snapshot at all: full replay from the beginning.
|
|
153
|
+
*
|
|
154
|
+
* @param sessionId - The session to reconstruct.
|
|
155
|
+
* @param store - Persistence store to read from. Defaults to the real DB store.
|
|
156
|
+
* Pass the same store used during `processEvent` when testing.
|
|
157
|
+
* @returns Reconstructed SessionState, or a minimal initial state if no
|
|
158
|
+
* snapshot or actions exist.
|
|
159
|
+
*/
|
|
160
|
+
static reconstruct(sessionId: string, store?: SessionStore): SessionState;
|
|
161
|
+
private createInitialState;
|
|
162
|
+
private static createInitialState;
|
|
163
|
+
private static replayAllActions;
|
|
164
|
+
private static replayRows;
|
|
165
|
+
private static reconstructAgentEvent;
|
|
166
|
+
private serializeSnapshot;
|
|
167
|
+
}
|
|
168
|
+
//# sourceMappingURL=ahp-session-state.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ahp-session-state.d.ts","sourceRoot":"","sources":["../src/ahp-session-state.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAGH,OAAO,EAAiB,KAAK,gBAAgB,EAAE,KAAK,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAC9F,OAAO,EAIL,KAAK,YAAY,EAClB,MAAM,iBAAiB,CAAC;AAMzB,OAAO,EAIL,KAAK,kBAAkB,EACvB,KAAK,gBAAgB,EACrB,KAAK,cAAc,EACnB,KAAK,kBAAkB,EACxB,MAAM,sBAAsB,CAAC;AAa9B;;;;;;GAMG;AACH,MAAM,WAAW,YAAY;IAC3B,4EAA4E;IAC5E,eAAe,CAAC,MAAM,EAAE,cAAc,GAAG,IAAI,CAAC;IAC9C,+DAA+D;IAC/D,aAAa,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,kBAAkB,EAAE,CAAC;IACvE,qDAAqD;IACrD,mBAAmB,CAAC,KAAK,EAAE,kBAAkB,GAAG,gBAAgB,EAAE,CAAC;CACpE;AASD;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,wCAAwC;IACxC,SAAS,EAAE,OAAO,CAAC;IACnB,iFAAiF;IACjF,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;GAEG;AACH,MAAM,WAAW,0BAA0B;IACzC,uFAAuF;IACvF,eAAe,CAAC,EAAE,YAAY,CAAC;IAC/B;;;OAGG;IACH,KAAK,CAAC,EAAE,YAAY,CAAC;CACtB;AAED;;;GAGG;AACH,qBAAa,mBAAmB;IAC9B;;;;;;;;OAQG;IACH,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,iBAAiB,CAYtC;IAEH,kEAAkE;IAClE,OAAO,CAAC,KAAK,CAAe;IAE5B,6DAA6D;IAC7D,OAAO,CAAC,OAAO,CAAgB;IAE/B,0BAA0B;IAC1B,OAAO,CAAC,SAAS,CAAS;IAE1B,mDAAmD;IACnD,OAAO,CAAC,yBAAyB,CAAS;IAE1C,oEAAoE;IACpE,OAAO,CAAC,KAAK,CAAe;IAE5B;;;;OAIG;IACI,iBAAiB,EAAE,MAAM,CAAC;IAEjC;;;;OAIG;IACH,OAAO,CAAC,mBAAmB,CAAU;IAErC;;;;;OAKG;gBACgB,SAAS,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,0BAA0B;IAqB1E;;;;;;;;;OASG;IACI,YAAY,CAAC,KAAK,EAAE,gBAAgB,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IA0DnF;;;OAGG;IACI,uBAAuB,IAAI,IAAI;IAItC;;;;;;;OAOG;IACI,QAAQ,IAAI,YAAY;IAwC/B;;;;;;;OAOG;IACI,UAAU,IAAI,aAAa;IAelC;;;;;;;;;;OAUG;IACI,QAAQ,CAAC,OAAO,GAAE,MAAY,GAAG,cAAc;IAuBtD;;OAEG;IACI,KAAK,IAAI,IAAI;IAYpB;;;;;;;;;;;;;;;OAeG;WACW,WAAW,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,YAAY,GAAG,YAAY;IA2DhF,OAAO,CAAC,kBAAkB;IAI1B,OAAO,CAAC,MAAM,CAAC,kBAAkB;IAejC,OAAO,CAAC,MAAM,CAAC,gBAAgB;IAyB/B,OAAO,CAAC,MAAM,CAAC,UAAU;IA+DzB,OAAO,CAAC,MAAM,CAAC,qBAAqB;IAUpC,OAAO,CAAC,iBAAiB;CAyB1B"}
|
|
@@ -0,0 +1,469 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Session state manager (AHP HR1b / RFC #1292).
|
|
3
|
+
*
|
|
4
|
+
* Wraps the agent-event mapper, AHP sessionReducer, and snapshot store into
|
|
5
|
+
* a single per-session class. Each instance maintains the live `SessionState`
|
|
6
|
+
* by folding mapped actions through the reducer, and persists checkpoints to
|
|
7
|
+
* the `session_snapshots` table.
|
|
8
|
+
*
|
|
9
|
+
* @module ahp-session-state
|
|
10
|
+
*/
|
|
11
|
+
import { logger } from "./logger.js";
|
|
12
|
+
import { mapAgentEvent } from "@grackle-ai/common";
|
|
13
|
+
import { sessionReducer, SessionLifecycle, SessionStatus, } from "@grackle-ai/ahp";
|
|
14
|
+
import { persistSnapshot as dbPersistSnapshot, querySnapshot as dbQuerySnapshot, querySessionActions as dbQuerySessionActions, } from "@grackle-ai/database";
|
|
15
|
+
/** Default flush interval (actions between snapshots). */
|
|
16
|
+
const DEFAULT_SNAPSHOT_THRESHOLD = 100;
|
|
17
|
+
/**
|
|
18
|
+
* Hard cap on events replayed during reconstruction.
|
|
19
|
+
* Must not exceed `MAX_SESSION_ACTION_LIMIT` (5 000) from `@grackle-ai/database`
|
|
20
|
+
* or `querySessionActions` will silently truncate and reconstruction will be
|
|
21
|
+
* incomplete. Paging support can raise this ceiling in a future iteration.
|
|
22
|
+
*/
|
|
23
|
+
const MAX_RECONSTRUCTION_EVENTS = 5_000;
|
|
24
|
+
/** Default store backed by the real SQLite database. */
|
|
25
|
+
const defaultStore = {
|
|
26
|
+
persistSnapshot: dbPersistSnapshot,
|
|
27
|
+
querySnapshot: dbQuerySnapshot,
|
|
28
|
+
querySessionActions: dbQuerySessionActions,
|
|
29
|
+
};
|
|
30
|
+
/**
|
|
31
|
+
* Per-session state manager that processes AgentEvents through the AHP mapper
|
|
32
|
+
* and reducer, maintains live SessionState, and persists periodic snapshots.
|
|
33
|
+
*/
|
|
34
|
+
export class SessionStateManager {
|
|
35
|
+
/**
|
|
36
|
+
* Event types that correspond to rows fed through `SessionStateManager.processEvent()`
|
|
37
|
+
* in the live pipeline. Rows with other types (e.g. `signal`, `widget`) are recorded in
|
|
38
|
+
* `session_actions` by other code paths but were never processed by the state manager,
|
|
39
|
+
* so replaying them would incorrectly advance `context.eventIndex`.
|
|
40
|
+
*
|
|
41
|
+
* "user_input" is intentionally absent — it is handled separately by remapping it to
|
|
42
|
+
* "turn_started" before calling `mapAgentEvent`.
|
|
43
|
+
*/
|
|
44
|
+
static AGENT_EVENT_TYPES = new Set([
|
|
45
|
+
"turn_started",
|
|
46
|
+
"turn_complete",
|
|
47
|
+
"input_needed",
|
|
48
|
+
"text",
|
|
49
|
+
"tool_use",
|
|
50
|
+
"tool_result",
|
|
51
|
+
"usage",
|
|
52
|
+
"error",
|
|
53
|
+
"status",
|
|
54
|
+
"system",
|
|
55
|
+
"runtime_session_id",
|
|
56
|
+
]);
|
|
57
|
+
/** The current SessionState (built by folding mapped actions). */
|
|
58
|
+
state;
|
|
59
|
+
/** Mapper context maintained across events in the stream. */
|
|
60
|
+
context;
|
|
61
|
+
/** Current session ID. */
|
|
62
|
+
sessionId;
|
|
63
|
+
/** Number of actions since last snapshot flush. */
|
|
64
|
+
actionCountSinceLastFlush;
|
|
65
|
+
/** Persistence store (real DB by default; injectable for tests). */
|
|
66
|
+
store;
|
|
67
|
+
/**
|
|
68
|
+
* Number of actions between automatic snapshot flushes.
|
|
69
|
+
* Set to `0` to disable count-based flushing only; event-triggered
|
|
70
|
+
* flushes (turn_complete, terminal status, shutdown) still occur.
|
|
71
|
+
*/
|
|
72
|
+
snapshotThreshold;
|
|
73
|
+
/**
|
|
74
|
+
* Set to true when the initial prompt is injected as turn_started.
|
|
75
|
+
* The first runtime turn_started for the same turn is then skipped
|
|
76
|
+
* to avoid a duplicate SessionTurnStarted action.
|
|
77
|
+
*/
|
|
78
|
+
injectedInitialTurn;
|
|
79
|
+
/**
|
|
80
|
+
* Create a new SessionStateManager.
|
|
81
|
+
*
|
|
82
|
+
* @param sessionId - The session ID to manage.
|
|
83
|
+
* @param options - Optional initial snapshot and persistence store.
|
|
84
|
+
*/
|
|
85
|
+
constructor(sessionId, options) {
|
|
86
|
+
this.sessionId = sessionId;
|
|
87
|
+
this.actionCountSinceLastFlush = 0;
|
|
88
|
+
this.snapshotThreshold = DEFAULT_SNAPSHOT_THRESHOLD;
|
|
89
|
+
this.injectedInitialTurn = false;
|
|
90
|
+
this.store = options?.store ?? defaultStore;
|
|
91
|
+
this.context = {
|
|
92
|
+
turnId: undefined,
|
|
93
|
+
openToolCalls: [],
|
|
94
|
+
partCounter: 0,
|
|
95
|
+
eventIndex: 0,
|
|
96
|
+
metaAccumulator: {},
|
|
97
|
+
};
|
|
98
|
+
if (options?.initialSnapshot) {
|
|
99
|
+
this.state = options.initialSnapshot;
|
|
100
|
+
}
|
|
101
|
+
else {
|
|
102
|
+
this.state = this.createInitialState();
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Process a single AgentEvent through the mapper and reducer,
|
|
107
|
+
* and flush a snapshot if the threshold or turn_complete is reached.
|
|
108
|
+
*
|
|
109
|
+
* @param event - The AgentEvent to process.
|
|
110
|
+
* @param serverSeq - Monotonic ULID of the session_action record for this event.
|
|
111
|
+
* Used to anchor snapshots to the real action sequence for reconstruction.
|
|
112
|
+
* @returns The last action's ULID included in the snapshot, or `undefined`
|
|
113
|
+
* if no actions were produced or the threshold was not reached.
|
|
114
|
+
*/
|
|
115
|
+
processEvent(event, serverSeq) {
|
|
116
|
+
// Dedup: skip the first runtime turn_started if we injected the initial prompt.
|
|
117
|
+
// The mapper would otherwise produce a duplicate SessionTurnStarted action.
|
|
118
|
+
if (this.injectedInitialTurn && event.type === "turn_started") {
|
|
119
|
+
this.injectedInitialTurn = false;
|
|
120
|
+
return undefined;
|
|
121
|
+
}
|
|
122
|
+
const idx = this.context.eventIndex++;
|
|
123
|
+
const { actions, note } = mapAgentEvent(event, idx, this.context);
|
|
124
|
+
// Fold each action through the reducer.
|
|
125
|
+
// All actions from the mapper are session-specific, so casting to SessionAction is safe.
|
|
126
|
+
for (const action of actions) {
|
|
127
|
+
this.state = sessionReducer(this.state, action);
|
|
128
|
+
this.actionCountSinceLastFlush += 1;
|
|
129
|
+
}
|
|
130
|
+
// Apply mapper carries (_meta fields the reducer doesn't handle).
|
|
131
|
+
// Only re-create _meta when values actually change (avoids unnecessary
|
|
132
|
+
// object identity updates that break equality checks downstream).
|
|
133
|
+
const metaChanges = {};
|
|
134
|
+
if (this.context.metaAccumulator.costMillicents !== undefined) {
|
|
135
|
+
const existing = this.state._meta?.costMillicents;
|
|
136
|
+
if (existing === undefined || existing !== this.context.metaAccumulator.costMillicents) {
|
|
137
|
+
metaChanges.costMillicents = this.context.metaAccumulator.costMillicents;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
if (this.context.metaAccumulator.runtimeSessionId !== undefined) {
|
|
141
|
+
const existing = this.state._meta?.runtimeSessionId;
|
|
142
|
+
if (existing === undefined || existing !== this.context.metaAccumulator.runtimeSessionId) {
|
|
143
|
+
metaChanges.runtimeSessionId = this.context.metaAccumulator.runtimeSessionId;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
if (Object.keys(metaChanges).length > 0) {
|
|
147
|
+
this.state._meta = { ...(this.state._meta ?? {}), ...metaChanges };
|
|
148
|
+
}
|
|
149
|
+
let lastSeq;
|
|
150
|
+
// Check snapshot threshold
|
|
151
|
+
if (this.snapshotThreshold > 0 && this.actionCountSinceLastFlush >= this.snapshotThreshold) {
|
|
152
|
+
this.snapshot(serverSeq);
|
|
153
|
+
lastSeq = serverSeq;
|
|
154
|
+
}
|
|
155
|
+
// Auto-snapshot on turn_complete (only if not already flushed above)
|
|
156
|
+
else if (
|
|
157
|
+
// eslint-disable-next-line @typescript-eslint/prefer-optional-chain -- note.type is always defined when note is non-null
|
|
158
|
+
note &&
|
|
159
|
+
note.disposition === "mapped" &&
|
|
160
|
+
note.type === "turn_complete") {
|
|
161
|
+
this.snapshot(serverSeq);
|
|
162
|
+
lastSeq = serverSeq;
|
|
163
|
+
}
|
|
164
|
+
return lastSeq;
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Mark that the initial prompt was injected as turn_started.
|
|
168
|
+
* The next runtime turn_started will be skipped to avoid a duplicate.
|
|
169
|
+
*/
|
|
170
|
+
markInjectedInitialTurn() {
|
|
171
|
+
this.injectedInitialTurn = true;
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Get the current SessionState.
|
|
175
|
+
*
|
|
176
|
+
* Returns a deep clone frozen to prevent callers from mutating the
|
|
177
|
+
* manager's internal state.
|
|
178
|
+
*
|
|
179
|
+
* @returns A frozen deep clone of the current state.
|
|
180
|
+
*/
|
|
181
|
+
getState() {
|
|
182
|
+
const copy = structuredClone(this.state);
|
|
183
|
+
try {
|
|
184
|
+
Object.freeze(copy.turns);
|
|
185
|
+
}
|
|
186
|
+
catch {
|
|
187
|
+
/* ignore */
|
|
188
|
+
}
|
|
189
|
+
try {
|
|
190
|
+
copy.turns.forEach(Object.freeze);
|
|
191
|
+
}
|
|
192
|
+
catch {
|
|
193
|
+
/* ignore */
|
|
194
|
+
}
|
|
195
|
+
try {
|
|
196
|
+
Object.freeze(copy.queuedMessages);
|
|
197
|
+
}
|
|
198
|
+
catch {
|
|
199
|
+
/* ignore */
|
|
200
|
+
}
|
|
201
|
+
try {
|
|
202
|
+
Object.freeze(copy.inputRequests);
|
|
203
|
+
}
|
|
204
|
+
catch {
|
|
205
|
+
/* ignore */
|
|
206
|
+
}
|
|
207
|
+
try {
|
|
208
|
+
Object.freeze(copy.config);
|
|
209
|
+
}
|
|
210
|
+
catch {
|
|
211
|
+
/* ignore */
|
|
212
|
+
}
|
|
213
|
+
try {
|
|
214
|
+
Object.freeze(copy._meta);
|
|
215
|
+
}
|
|
216
|
+
catch {
|
|
217
|
+
/* ignore */
|
|
218
|
+
}
|
|
219
|
+
try {
|
|
220
|
+
Object.freeze(copy);
|
|
221
|
+
}
|
|
222
|
+
catch {
|
|
223
|
+
/* ignore */
|
|
224
|
+
}
|
|
225
|
+
return copy;
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
228
|
+
* Get the current mapper context (useful for debugging or external state sync).
|
|
229
|
+
*
|
|
230
|
+
* Returns a deep clone frozen to prevent callers from mutating the
|
|
231
|
+
* manager's internal state.
|
|
232
|
+
*
|
|
233
|
+
* @returns A frozen deep clone of the current context.
|
|
234
|
+
*/
|
|
235
|
+
getContext() {
|
|
236
|
+
const copy = structuredClone(this.context);
|
|
237
|
+
try {
|
|
238
|
+
Object.freeze(copy.openToolCalls);
|
|
239
|
+
}
|
|
240
|
+
catch {
|
|
241
|
+
/* ignore */
|
|
242
|
+
}
|
|
243
|
+
try {
|
|
244
|
+
Object.freeze(copy);
|
|
245
|
+
}
|
|
246
|
+
catch {
|
|
247
|
+
/* ignore */
|
|
248
|
+
}
|
|
249
|
+
return copy;
|
|
250
|
+
}
|
|
251
|
+
/**
|
|
252
|
+
* Persist a snapshot of the current SessionState and MapperContext to the store.
|
|
253
|
+
*
|
|
254
|
+
* Serializes key fields from SessionState (summary, lifecycle, turns,
|
|
255
|
+
* activeTurn, steeringMessage, queuedMessages, inputRequests, config, _meta)
|
|
256
|
+
* and the full MapperContext into JSON. Excludes serverTools, activeClient,
|
|
257
|
+
* and customizations.
|
|
258
|
+
*
|
|
259
|
+
* @param lastSeq - ULID string of the last action included in this snapshot.
|
|
260
|
+
* @returns Result describing whether a snapshot was persisted.
|
|
261
|
+
*/
|
|
262
|
+
snapshot(lastSeq = "0") {
|
|
263
|
+
try {
|
|
264
|
+
const snapshotData = this.serializeSnapshot();
|
|
265
|
+
const record = {
|
|
266
|
+
seq: lastSeq,
|
|
267
|
+
sessionId: this.sessionId,
|
|
268
|
+
snapshotAt: new Date().toISOString(),
|
|
269
|
+
state: snapshotData,
|
|
270
|
+
mapperContext: JSON.stringify(this.context),
|
|
271
|
+
};
|
|
272
|
+
this.store.persistSnapshot(record);
|
|
273
|
+
this.actionCountSinceLastFlush = 0;
|
|
274
|
+
logger.info({ sessionId: this.sessionId, seq: lastSeq }, "Snapshot persisted");
|
|
275
|
+
return { persisted: true, lastSeq };
|
|
276
|
+
}
|
|
277
|
+
catch (err) {
|
|
278
|
+
logger.error({ err, sessionId: this.sessionId }, "Failed to persist snapshot");
|
|
279
|
+
return { persisted: false };
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
/**
|
|
283
|
+
* Clear internal state. Call on session shutdown.
|
|
284
|
+
*/
|
|
285
|
+
clear() {
|
|
286
|
+
this.state = this.createInitialState();
|
|
287
|
+
this.context = {
|
|
288
|
+
turnId: undefined,
|
|
289
|
+
openToolCalls: [],
|
|
290
|
+
partCounter: 0,
|
|
291
|
+
eventIndex: 0,
|
|
292
|
+
metaAccumulator: {},
|
|
293
|
+
};
|
|
294
|
+
this.actionCountSinceLastFlush = 0;
|
|
295
|
+
}
|
|
296
|
+
/**
|
|
297
|
+
* Reconstruct SessionState from the latest snapshot plus delta actions.
|
|
298
|
+
*
|
|
299
|
+
* Strategy:
|
|
300
|
+
* - If the snapshot includes a `mapperContext`: delta replay — replay only the
|
|
301
|
+
* actions since the snapshot using the stored context (O(delta)).
|
|
302
|
+
* - If the snapshot is missing a `mapperContext` (older snapshot): full replay —
|
|
303
|
+
* replay all session_actions from the start with a fresh context (O(n) fallback).
|
|
304
|
+
* - If there is no snapshot at all: full replay from the beginning.
|
|
305
|
+
*
|
|
306
|
+
* @param sessionId - The session to reconstruct.
|
|
307
|
+
* @param store - Persistence store to read from. Defaults to the real DB store.
|
|
308
|
+
* Pass the same store used during `processEvent` when testing.
|
|
309
|
+
* @returns Reconstructed SessionState, or a minimal initial state if no
|
|
310
|
+
* snapshot or actions exist.
|
|
311
|
+
*/
|
|
312
|
+
static reconstruct(sessionId, store) {
|
|
313
|
+
const s = store ?? defaultStore;
|
|
314
|
+
const snapshots = s.querySnapshot(sessionId, 1);
|
|
315
|
+
if (snapshots.length === 0) {
|
|
316
|
+
return SessionStateManager.replayAllActions(sessionId, s);
|
|
317
|
+
}
|
|
318
|
+
const latest = snapshots[0];
|
|
319
|
+
let baseState;
|
|
320
|
+
try {
|
|
321
|
+
baseState = JSON.parse(latest.state);
|
|
322
|
+
}
|
|
323
|
+
catch (err) {
|
|
324
|
+
logger.error({ err, sessionId, seq: latest.seq }, "Corrupted snapshot state — falling back to full replay");
|
|
325
|
+
return SessionStateManager.replayAllActions(sessionId, s);
|
|
326
|
+
}
|
|
327
|
+
// Delta replay: use stored MapperContext to seed the replay
|
|
328
|
+
if (latest.mapperContext) {
|
|
329
|
+
let replayContext;
|
|
330
|
+
try {
|
|
331
|
+
const parsed = JSON.parse(latest.mapperContext);
|
|
332
|
+
// Normalize fields that may be missing from snapshots written before they were added.
|
|
333
|
+
// eventIndex defaults to 0 so synthetic IDs (turn-N, tc-N) start fresh rather than NaN.
|
|
334
|
+
replayContext = {
|
|
335
|
+
...parsed,
|
|
336
|
+
eventIndex: Number.isFinite(parsed.eventIndex) ? parsed.eventIndex : 0,
|
|
337
|
+
openToolCalls: Array.isArray(parsed.openToolCalls) ? parsed.openToolCalls : [],
|
|
338
|
+
partCounter: Number.isFinite(parsed.partCounter) ? parsed.partCounter : 0,
|
|
339
|
+
};
|
|
340
|
+
}
|
|
341
|
+
catch (err) {
|
|
342
|
+
logger.warn({ err, sessionId, seq: latest.seq }, "Corrupted snapshot mapperContext — falling back to full replay");
|
|
343
|
+
return SessionStateManager.replayAllActions(sessionId, s);
|
|
344
|
+
}
|
|
345
|
+
const deltaRows = s.querySessionActions({
|
|
346
|
+
sessionId,
|
|
347
|
+
fromSeq: latest.seq,
|
|
348
|
+
limit: MAX_RECONSTRUCTION_EVENTS,
|
|
349
|
+
});
|
|
350
|
+
return SessionStateManager.replayRows(baseState, replayContext, deltaRows);
|
|
351
|
+
}
|
|
352
|
+
// Snapshot exists but has no mapperContext (old snapshot format) — full replay
|
|
353
|
+
logger.debug({ sessionId, seq: latest.seq }, "Snapshot missing mapperContext — falling back to full replay");
|
|
354
|
+
return SessionStateManager.replayAllActions(sessionId, s);
|
|
355
|
+
}
|
|
356
|
+
createInitialState() {
|
|
357
|
+
return SessionStateManager.createInitialState(this.sessionId);
|
|
358
|
+
}
|
|
359
|
+
static createInitialState(sessionId) {
|
|
360
|
+
return {
|
|
361
|
+
summary: {
|
|
362
|
+
resource: `ahp-session:${sessionId}`,
|
|
363
|
+
provider: "grackle",
|
|
364
|
+
title: "",
|
|
365
|
+
status: SessionStatus.Idle,
|
|
366
|
+
createdAt: Date.now(),
|
|
367
|
+
modifiedAt: Date.now(),
|
|
368
|
+
},
|
|
369
|
+
lifecycle: SessionLifecycle.Creating,
|
|
370
|
+
turns: [],
|
|
371
|
+
};
|
|
372
|
+
}
|
|
373
|
+
static replayAllActions(sessionId, store) {
|
|
374
|
+
const allRows = store.querySessionActions({
|
|
375
|
+
sessionId,
|
|
376
|
+
limit: MAX_RECONSTRUCTION_EVENTS,
|
|
377
|
+
});
|
|
378
|
+
if (allRows.length === 0) {
|
|
379
|
+
return SessionStateManager.createInitialState(sessionId);
|
|
380
|
+
}
|
|
381
|
+
const freshContext = {
|
|
382
|
+
turnId: undefined,
|
|
383
|
+
openToolCalls: [],
|
|
384
|
+
partCounter: 0,
|
|
385
|
+
eventIndex: 0,
|
|
386
|
+
metaAccumulator: {},
|
|
387
|
+
};
|
|
388
|
+
return SessionStateManager.replayRows(SessionStateManager.createInitialState(allRows[0].sessionId), freshContext, allRows);
|
|
389
|
+
}
|
|
390
|
+
static replayRows(baseState, context, rows) {
|
|
391
|
+
let state = baseState;
|
|
392
|
+
// Mirrors the live pipeline's markInjectedInitialTurn dedup: when a "user_input"
|
|
393
|
+
// row is remapped to "turn_started", the runtime's subsequent real turn_started is
|
|
394
|
+
// skipped (without advancing eventIndex) to avoid a duplicate SessionTurnStarted.
|
|
395
|
+
let skipNextTurnStarted = false;
|
|
396
|
+
for (const row of rows) {
|
|
397
|
+
// "user_input" rows are stored in session_actions for the injected prompt, but
|
|
398
|
+
// the live pipeline processed them as synthetic "turn_started" events via
|
|
399
|
+
// makeAgentEvent(..., "turn_started", JSON.stringify({user_message: content})).
|
|
400
|
+
// Replicate that here to keep eventIndex and state consistent with the live run.
|
|
401
|
+
let eventRow = row;
|
|
402
|
+
if (row.type === "user_input") {
|
|
403
|
+
eventRow = {
|
|
404
|
+
...row,
|
|
405
|
+
type: "turn_started",
|
|
406
|
+
content: JSON.stringify({ user_message: row.content }),
|
|
407
|
+
};
|
|
408
|
+
skipNextTurnStarted = true;
|
|
409
|
+
}
|
|
410
|
+
else if (skipNextTurnStarted && row.type === "turn_started") {
|
|
411
|
+
// Skip the runtime's real turn_started (mirrors markInjectedInitialTurn dedup).
|
|
412
|
+
// Do NOT advance eventIndex — the live pipeline skipped this event before the
|
|
413
|
+
// eventIndex increment.
|
|
414
|
+
skipNextTurnStarted = false;
|
|
415
|
+
continue;
|
|
416
|
+
}
|
|
417
|
+
else if (!SessionStateManager.AGENT_EVENT_TYPES.has(row.type)) {
|
|
418
|
+
// Skip rows recorded by other code paths (signal, widget, etc.) that were
|
|
419
|
+
// never fed through processEvent() in the live pipeline. Do NOT advance
|
|
420
|
+
// eventIndex so it stays aligned with the live run.
|
|
421
|
+
continue;
|
|
422
|
+
}
|
|
423
|
+
const event = SessionStateManager.reconstructAgentEvent(eventRow);
|
|
424
|
+
// Use context.eventIndex so delta replay starts from the correct offset,
|
|
425
|
+
// keeping synthetic turn/tool IDs consistent with the live processing run.
|
|
426
|
+
const { actions } = mapAgentEvent(event, context.eventIndex++, context);
|
|
427
|
+
for (const action of actions) {
|
|
428
|
+
state = sessionReducer(state, action);
|
|
429
|
+
}
|
|
430
|
+
if (context.metaAccumulator.costMillicents !== undefined) {
|
|
431
|
+
state._meta = {
|
|
432
|
+
...(state._meta ?? {}),
|
|
433
|
+
costMillicents: context.metaAccumulator.costMillicents,
|
|
434
|
+
};
|
|
435
|
+
}
|
|
436
|
+
if (context.metaAccumulator.runtimeSessionId !== undefined) {
|
|
437
|
+
state._meta = {
|
|
438
|
+
...(state._meta ?? {}),
|
|
439
|
+
runtimeSessionId: context.metaAccumulator.runtimeSessionId,
|
|
440
|
+
};
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
return state;
|
|
444
|
+
}
|
|
445
|
+
static reconstructAgentEvent(row) {
|
|
446
|
+
return {
|
|
447
|
+
type: row.type,
|
|
448
|
+
content: row.content,
|
|
449
|
+
toolCallId: row.toolCallId,
|
|
450
|
+
turnId: row.turnId,
|
|
451
|
+
diagnostic: row.diagnostic,
|
|
452
|
+
};
|
|
453
|
+
}
|
|
454
|
+
serializeSnapshot() {
|
|
455
|
+
const { summary, lifecycle, turns, activeTurn, steeringMessage, queuedMessages, inputRequests, config, _meta, } = this.state;
|
|
456
|
+
return JSON.stringify({
|
|
457
|
+
summary,
|
|
458
|
+
lifecycle,
|
|
459
|
+
turns,
|
|
460
|
+
activeTurn,
|
|
461
|
+
steeringMessage,
|
|
462
|
+
queuedMessages,
|
|
463
|
+
inputRequests,
|
|
464
|
+
config,
|
|
465
|
+
_meta,
|
|
466
|
+
});
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
//# sourceMappingURL=ahp-session-state.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ahp-session-state.js","sourceRoot":"","sources":["../src/ahp-session-state.ts"],"names":[],"mappings":"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"}
|