@minpeter/pss-runtime 0.1.0-next.0 → 0.1.0-next.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.
Files changed (96) hide show
  1. package/README.md +85 -194
  2. package/dist/agent-loop.js +8 -14
  3. package/dist/agent-loop.js.map +1 -1
  4. package/dist/agent-namespace.js +17 -0
  5. package/dist/agent-namespace.js.map +1 -0
  6. package/dist/agent-validation.js +35 -0
  7. package/dist/agent-validation.js.map +1 -0
  8. package/dist/agent.d.ts +21 -10
  9. package/dist/agent.js +81 -37
  10. package/dist/agent.js.map +1 -1
  11. package/dist/child-session-cleanups.js +61 -0
  12. package/dist/child-session-cleanups.js.map +1 -0
  13. package/dist/hooks.d.ts +32 -0
  14. package/dist/index.d.ts +4 -8
  15. package/dist/index.js +1 -6
  16. package/dist/llm.js +1 -7
  17. package/dist/llm.js.map +1 -1
  18. package/dist/session/events.d.ts +23 -20
  19. package/dist/session/input-normalization.js +66 -0
  20. package/dist/session/input-normalization.js.map +1 -0
  21. package/dist/session/input.d.ts +0 -4
  22. package/dist/session/mapping.js +1 -2
  23. package/dist/session/mapping.js.map +1 -1
  24. package/dist/session/run.js +1 -0
  25. package/dist/session/run.js.map +1 -1
  26. package/dist/session/runtime-input.js +38 -58
  27. package/dist/session/runtime-input.js.map +1 -1
  28. package/dist/session/session-errors.js +23 -0
  29. package/dist/session/session-errors.js.map +1 -0
  30. package/dist/session/session-kill.js +23 -0
  31. package/dist/session/session-kill.js.map +1 -0
  32. package/dist/session/session-runtime-drain.js +22 -0
  33. package/dist/session/session-runtime-drain.js.map +1 -0
  34. package/dist/session/session-state.js +102 -0
  35. package/dist/session/session-state.js.map +1 -0
  36. package/dist/session/session-turn-error.js +35 -0
  37. package/dist/session/session-turn-error.js.map +1 -0
  38. package/dist/session/session.js +103 -285
  39. package/dist/session/session.js.map +1 -1
  40. package/dist/session/snapshot.js +5 -31
  41. package/dist/session/snapshot.js.map +1 -1
  42. package/dist/session/store/file.d.ts +1 -0
  43. package/dist/session/store/file.js +14 -0
  44. package/dist/session/store/file.js.map +1 -1
  45. package/dist/session/store/memory.d.ts +1 -0
  46. package/dist/session/store/memory.js +5 -0
  47. package/dist/session/store/memory.js.map +1 -1
  48. package/dist/session/store/types.d.ts +1 -0
  49. package/dist/subagent-job-cancel.js +28 -0
  50. package/dist/subagent-job-cancel.js.map +1 -0
  51. package/dist/subagent-job-output.js +63 -0
  52. package/dist/subagent-job-output.js.map +1 -0
  53. package/dist/subagent-jobs.js +151 -0
  54. package/dist/subagent-jobs.js.map +1 -0
  55. package/dist/subagent-prompt-schema.js +114 -0
  56. package/dist/subagent-prompt-schema.js.map +1 -0
  57. package/dist/subagent-run.js +111 -0
  58. package/dist/subagent-run.js.map +1 -0
  59. package/dist/subagents.js +92 -0
  60. package/dist/subagents.js.map +1 -0
  61. package/package.json +1 -6
  62. package/dist/plugins/compaction.d.ts +0 -15
  63. package/dist/plugins/compaction.js +0 -98
  64. package/dist/plugins/compaction.js.map +0 -1
  65. package/dist/plugins/index.d.ts +0 -5
  66. package/dist/plugins/index.js +0 -5
  67. package/dist/plugins/memory.d.ts +0 -11
  68. package/dist/plugins/memory.js +0 -146
  69. package/dist/plugins/memory.js.map +0 -1
  70. package/dist/plugins/runner.d.ts +0 -1
  71. package/dist/plugins/runner.js +0 -83
  72. package/dist/plugins/runner.js.map +0 -1
  73. package/dist/plugins/scope.js +0 -13
  74. package/dist/plugins/scope.js.map +0 -1
  75. package/dist/plugins/sessions.d.ts +0 -12
  76. package/dist/plugins/sessions.js +0 -34
  77. package/dist/plugins/sessions.js.map +0 -1
  78. package/dist/plugins/tool-hook-handlers.js +0 -77
  79. package/dist/plugins/tool-hook-handlers.js.map +0 -1
  80. package/dist/plugins/tool-hook-results.js +0 -64
  81. package/dist/plugins/tool-hook-results.js.map +0 -1
  82. package/dist/plugins/tool-hooks.js +0 -111
  83. package/dist/plugins/tool-hooks.js.map +0 -1
  84. package/dist/plugins/types.d.ts +0 -105
  85. package/dist/plugins/types.js +0 -20
  86. package/dist/plugins/types.js.map +0 -1
  87. package/dist/session/lifecycle.d.ts +0 -12
  88. package/dist/session/lifecycle.js +0 -126
  89. package/dist/session/lifecycle.js.map +0 -1
  90. package/dist/session/overlay-anchor.js +0 -151
  91. package/dist/session/overlay-anchor.js.map +0 -1
  92. package/dist/session/overlay.js +0 -141
  93. package/dist/session/overlay.js.map +0 -1
  94. package/dist/session/snapshot.d.ts +0 -1
  95. /package/dist/{agent-loop.d.ts → session/history.d.ts} +0 -0
  96. /package/dist/{plugins/scope.d.ts → session/session-state.d.ts} +0 -0
@@ -1,43 +1,36 @@
1
- import { runWithAgentPluginScope } from "../plugins/scope.js";
2
1
  import { runAgentLoop } from "../agent-loop.js";
3
- import { ModelMessageHistory } from "./history.js";
4
- import { createRuntimeInputStepLifecycle, runPluginAfterTurnHandlers, runPluginBeforeTurnHandlers } from "./lifecycle.js";
5
- import { addRuntimeInput, closeRuntimeInput, createRuntimeInputState, normalizeAgentInput, shiftRuntimeInput } from "./runtime-input.js";
6
- import { SessionOverlayState } from "./overlay.js";
2
+ import { normalizeAgentInput } from "./input-normalization.js";
7
3
  import { BufferedAgentRun } from "./run.js";
8
- import { decodeStoredSessionSnapshot, encodeSessionSnapshot } from "./snapshot.js";
4
+ import { addSteeringInput, closeRuntimeInput, createRuntimeInputState, hooksForRuntimeInput, withRuntimeInputWindow, withSteeringPlacement } from "./runtime-input.js";
5
+ import { errorMessage, runAfterTurnHook, sessionKilledError, sessionTerminalError } from "./session-errors.js";
6
+ import { closeKilledRuntimeInputs } from "./session-kill.js";
7
+ import { drainRuntimeInput } from "./session-runtime-drain.js";
8
+ import { SessionState } from "./session-state.js";
9
+ import { emitTurnErrorAfterRecovery } from "./session-turn-error.js";
9
10
  //#region src/session/session.ts
10
11
  var AgentSession = class {
12
+ #hooks;
11
13
  #inputQueue = [];
12
- #internalLlm;
13
14
  #llm;
14
- #onPluginError;
15
- #persistence;
16
- #plugins;
15
+ #pendingRuntimeInputs = [];
16
+ #state;
17
17
  #activeAbort;
18
18
  #activeRun;
19
19
  #activeRuntimeInput;
20
- #history = new ModelMessageHistory();
20
+ #deletePromise;
21
21
  #killed = false;
22
- #loadPromise;
23
- #loaded = false;
24
- #pluginState = {};
25
- #compactions = [];
26
- #overlays = new SessionOverlayState();
27
22
  #running = false;
28
- #storeVersion;
29
- constructor(llm, persistence, plugins, internalLlm = llm, onPluginError) {
30
- this.#internalLlm = internalLlm;
31
- this.#onPluginError = onPluginError;
32
- this.#persistence = persistence;
33
- this.#plugins = plugins;
23
+ #runToCloseOnKill;
24
+ constructor(llm, persistence, hooks) {
25
+ this.#hooks = hooks;
34
26
  this.#llm = llm;
27
+ this.#state = new SessionState(persistence);
35
28
  }
36
29
  async send(input) {
37
- if (this.#killed) throw sessionKilledError();
38
- await this.#ensureLoaded();
39
- if (this.#killed) throw sessionKilledError();
40
- const runtimeInput = createRuntimeInputState();
30
+ if (this.#killed || this.#deletePromise) throw sessionTerminalError(this.#killed);
31
+ await this.#state.ensureLoaded();
32
+ if (this.#killed || this.#deletePromise) throw sessionTerminalError(this.#killed);
33
+ const runtimeInput = createRuntimeInputState(this.#pendingRuntimeInputs.splice(0));
41
34
  const acceptedInput = normalizeAgentInput(input);
42
35
  const run = new BufferedAgentRun();
43
36
  run.emit(acceptedInput);
@@ -56,80 +49,68 @@ var AgentSession = class {
56
49
  return run;
57
50
  }
58
51
  async steer(input) {
59
- if (this.#killed) throw sessionKilledError();
52
+ if (this.#killed || this.#deletePromise) throw sessionTerminalError(this.#killed);
60
53
  const runtimeInput = this.#activeRuntimeInput;
61
54
  const run = this.#activeRun;
62
55
  if (!(runtimeInput && run)) return this.send(input);
63
- await addRuntimeInput(runtimeInput, input);
64
- return run;
65
- }
66
- async overlay(input) {
67
- if (this.#killed) throw sessionKilledError();
68
- await this.#ensureLoaded();
69
- if (this.#killed) throw sessionKilledError();
70
- const activeRun = this.#activeRun;
71
- if (activeRun) {
72
- const placement = this.#activeRuntimeInput?.steerPlacement ?? this.#activeRuntimeInput?.placement ?? "step-end";
73
- const entry = this.#overlays.appendActiveOverlay(input, placement);
74
- if (!entry) throw new Error("Active overlay frame is unavailable.");
75
- activeRun.emit({
76
- input: entry.summary,
77
- placement: entry.placement,
78
- type: "overlay-accepted"
79
- });
80
- return activeRun;
81
- }
82
- const entry = this.#overlays.appendPendingOverlay(input);
83
- const run = new BufferedAgentRun();
84
- run.emit({
85
- input: entry.summary,
86
- placement: entry.placement,
87
- type: "overlay-accepted"
88
- });
89
- run.close();
56
+ await addSteeringInput(runtimeInput, input);
90
57
  return run;
91
58
  }
92
59
  interrupt() {
93
60
  this.#activeAbort?.abort();
94
61
  }
95
- kill() {
62
+ delete() {
63
+ this.#deletePromise ??= this.#state.delete().then(() => this.kill(), (error) => {
64
+ this.#deletePromise = void 0;
65
+ throw error;
66
+ });
67
+ return this.#deletePromise;
68
+ }
69
+ enqueueRuntimeInput(input, placement = "turn-start") {
96
70
  if (this.#killed) return;
97
- this.#killed = true;
98
- this.#expireActiveOverlays("kill");
99
- this.#activeAbort?.abort();
100
- closeRuntimeInput(this.#activeRuntimeInput, sessionKilledError().message);
101
- while (this.#inputQueue.length > 0) {
102
- const item = this.#inputQueue.shift();
103
- closeRuntimeInput(item?.runtimeInput, sessionKilledError().message);
104
- item?.run.emit({
105
- type: "turn-error",
106
- message: sessionKilledError().message
71
+ const runtimeInput = this.#activeRuntimeInput;
72
+ if (runtimeInput && !runtimeInput.closedReason) {
73
+ if (placement === "turn-start" && runtimeInput.placement !== placement) {
74
+ this.#enqueuePendingRuntimeInput({
75
+ input,
76
+ placement
77
+ });
78
+ return;
79
+ }
80
+ runtimeInput.queue.push({
81
+ input,
82
+ placement
107
83
  });
108
- item?.run.close(void 0, sessionKilledError().message);
84
+ return;
109
85
  }
86
+ this.#enqueuePendingRuntimeInput({
87
+ input,
88
+ placement
89
+ });
110
90
  }
111
- async #ensureLoaded() {
112
- if (this.#loaded) return;
113
- this.#loadPromise ??= this.#loadSessionState();
114
- try {
115
- await this.#loadPromise;
116
- } catch (error) {
117
- this.#loadPromise = void 0;
118
- throw error;
119
- }
91
+ emitObserverEvent(event) {
92
+ this.#activeRun?.emit(event);
120
93
  }
121
- async #loadSessionState() {
122
- if (this.#loaded) return;
123
- await this.#replaceWithStoredSession();
124
- this.#loaded = true;
94
+ #enqueuePendingRuntimeInput(input) {
95
+ const queuedTurn = this.#inputQueue[0];
96
+ if (input.placement === "turn-start" && queuedTurn) {
97
+ queuedTurn.runtimeInput.queue.push(input);
98
+ return;
99
+ }
100
+ this.#pendingRuntimeInputs.push(input);
125
101
  }
126
- async #replaceWithStoredSession() {
127
- const stored = await this.#persistence.store.load(this.#persistence.key);
128
- this.#storeVersion = stored?.version;
129
- const snapshot = decodeStoredSessionSnapshot(stored);
130
- this.#history = new ModelMessageHistory(snapshot.history);
131
- this.#pluginState = structuredClone(snapshot.pluginState);
132
- this.#compactions = structuredClone(snapshot.compactions);
102
+ kill() {
103
+ if (this.#killed) return;
104
+ this.#killed = true;
105
+ const killedError = sessionKilledError();
106
+ this.#pendingRuntimeInputs.length = 0;
107
+ this.#activeAbort?.abort();
108
+ closeKilledRuntimeInputs({
109
+ activeRuntimeInput: this.#activeRuntimeInput,
110
+ inputQueue: this.#inputQueue,
111
+ message: killedError.message,
112
+ runToClose: this.#runToCloseOnKill ?? this.#activeRun
113
+ });
133
114
  }
134
115
  async #drainInputQueue() {
135
116
  if (this.#running) return;
@@ -146,242 +127,79 @@ var AgentSession = class {
146
127
  async #processQueuedInput({ input, run, runtimeInput }) {
147
128
  const activeAbort = new AbortController();
148
129
  this.#activeAbort = activeAbort;
149
- const historySnapshot = this.#history.modelSnapshot();
150
- this.#overlays.startTurn(input, historySnapshot);
151
130
  this.#activeRun = run;
152
131
  this.#activeRuntimeInput = runtimeInput;
132
+ this.#runToCloseOnKill = run;
133
+ const historySnapshot = this.#state.modelSnapshot();
153
134
  try {
154
- await this.#withSteeringPlacement(runtimeInput, "turn-start", async () => {
155
- await runPluginBeforeTurnHandlers(this.#pluginLifecycle(), {
135
+ await withSteeringPlacement(runtimeInput, "turn-start", async () => {
136
+ await this.#hooks?.beforeTurn?.({
137
+ history: this.#state.modelSnapshot(),
156
138
  input,
157
- runtimeInput,
158
139
  signal: activeAbort.signal
159
140
  });
160
141
  });
161
- await this.#withRuntimeInputWindow(runtimeInput, "turn-start", async () => {
142
+ await withRuntimeInputWindow(runtimeInput, "turn-start", async () => {
162
143
  await run.emitBoundary({ type: "turn-start" });
163
144
  });
164
- this.#history.appendUserInput(input);
165
- await this.#commitHistory();
166
- await this.#drainRuntimeInput(run, runtimeInput, "turn-start");
145
+ this.#state.appendUserInput(input);
146
+ await this.#state.commit();
147
+ await drainRuntimeInput({
148
+ placement: "turn-start",
149
+ run,
150
+ runtimeInput,
151
+ state: this.#state
152
+ });
167
153
  const result = await runAgentLoop({
168
154
  emit: async (event) => {
169
155
  if (event.type === "step-start" || event.type === "step-end") {
170
- await this.#withRuntimeInputWindow(runtimeInput, event.type, async () => {
156
+ await withRuntimeInputWindow(runtimeInput, event.type, async () => {
171
157
  await run.emitBoundary(event);
172
158
  });
173
- const overlayInputAdded = event.type === "step-end" && this.#overlays.consumeStepEndOverlayInputAdded();
174
- const runtimeInputAdded = await this.#drainRuntimeInput(run, runtimeInput, event.type);
175
- if (event.type === "step-end") return {
176
- overlayInputAdded,
177
- runtimeInputAdded
178
- };
179
- return;
159
+ const runtimeInputAdded = await drainRuntimeInput({
160
+ placement: event.type,
161
+ run,
162
+ runtimeInput,
163
+ state: this.#state
164
+ });
165
+ return event.type === "step-end" ? { runtimeInputAdded } : void 0;
180
166
  }
181
167
  run.emit(event);
182
168
  },
183
- history: this.#history,
184
- stepLifecycle: createRuntimeInputStepLifecycle({
185
- lifecycle: this.#pluginLifecycle(),
186
- runtimeInput,
187
- withSteeringPlacement: (placement, callback) => this.#withSteeringPlacement(runtimeInput, placement, callback)
188
- }),
189
- llm: (context) => this.#invokeLlm(context),
169
+ history: this.#state.history,
170
+ hooks: hooksForRuntimeInput(this.#hooks, runtimeInput),
171
+ llm: this.#llm,
190
172
  signal: activeAbort.signal
191
173
  });
192
- await this.#commitHistory();
174
+ await this.#state.commit();
193
175
  const terminalEvent = result === "aborted" ? "turn-abort" : "turn-end";
194
176
  closeRuntimeInput(runtimeInput, terminalEvent);
195
- this.#expireActiveOverlays(terminalEvent);
196
177
  this.#activeRuntimeInput = void 0;
197
178
  this.#activeRun = void 0;
198
- if (await runPluginAfterTurnHandlers(this.#pluginLifecycle(), {
179
+ await runAfterTurnHook(this.#hooks, {
180
+ history: this.#state.modelSnapshot(),
199
181
  input,
200
182
  result,
201
183
  signal: activeAbort.signal
202
- })) await this.#commitHistory();
184
+ });
203
185
  run.emit({ type: terminalEvent });
204
186
  } catch (error) {
205
- if (error instanceof SessionCommitConflictError) {
206
- run.emit({
207
- type: "turn-error",
208
- message: error.message
209
- });
210
- closeRuntimeInput(runtimeInput, "a session commit conflict");
211
- this.#expireActiveOverlays("turn-error");
212
- this.#activeAbort = void 0;
213
- return;
214
- }
215
- this.#history.rollback(historySnapshot);
216
- try {
217
- await this.#commitHistory();
218
- } catch (rollbackError) {
219
- run.emit({
220
- type: "turn-error",
221
- message: `${errorMessage(error)}; history rollback persistence failed: ${errorMessage(rollbackError)}`
222
- });
223
- closeRuntimeInput(runtimeInput, "turn-error");
224
- this.#expireActiveOverlays("turn-error");
225
- this.#activeAbort = void 0;
226
- return;
227
- }
228
- run.emit({
229
- type: "turn-error",
230
- message: errorMessage(error)
187
+ await emitTurnErrorAfterRecovery({
188
+ error: error instanceof Error ? error : new Error(String(error)),
189
+ historySnapshot,
190
+ run,
191
+ runtimeInput,
192
+ state: this.#state
231
193
  });
232
- closeRuntimeInput(runtimeInput, "turn-error");
233
- this.#expireActiveOverlays("turn-error");
234
194
  } finally {
235
195
  closeRuntimeInput(runtimeInput);
236
196
  this.#activeAbort = void 0;
237
197
  this.#activeRun = void 0;
238
198
  this.#activeRuntimeInput = void 0;
239
- this.#overlays.resetActiveTurn();
199
+ this.#runToCloseOnKill = void 0;
240
200
  run.close(void 0, runtimeInput.closedReason);
241
201
  }
242
202
  }
243
- async #commitHistory() {
244
- const result = await this.#persistence.store.commit(this.#persistence.key, { state: encodeSessionSnapshot({
245
- compactions: this.#compactions,
246
- history: this.#history.modelSnapshot(),
247
- pluginState: this.#pluginState
248
- }) }, { expectedVersion: this.#storeVersion ?? null });
249
- if (!result.ok) {
250
- await this.#replaceWithStoredSession();
251
- throw new SessionCommitConflictError(this.#persistence.key);
252
- }
253
- this.#storeVersion = result.version;
254
- }
255
- #createPluginScope(signal) {
256
- return {
257
- eventHandlers: this.#plugins?.eventHandlers,
258
- getCompactions: () => structuredClone(this.#compactions),
259
- getPluginState: (pluginName) => this.#pluginState[pluginName],
260
- history: () => this.#history.modelSnapshot(),
261
- sessionKey: this.#persistence.key,
262
- overlay: (input) => this.overlay(input),
263
- setCompactions: (compactions) => {
264
- this.#compactions = structuredClone([...compactions]);
265
- },
266
- setPluginState: (pluginName, state) => {
267
- this.#pluginState = {
268
- ...this.#pluginState,
269
- [pluginName]: structuredClone(state)
270
- };
271
- },
272
- signal,
273
- steer: (input) => this.steer(input),
274
- summarize: (messages) => this.#summarizeForPlugins(messages, signal)
275
- };
276
- }
277
- #pluginLifecycle() {
278
- return {
279
- createScope: (signal) => this.#createPluginScope(signal),
280
- history: () => this.#history.modelSnapshot(),
281
- onPluginError: this.#onPluginError,
282
- plugins: this.#plugins,
283
- sessionKey: this.#persistence.key,
284
- overlaySession: (input) => this.overlay(input),
285
- steerCurrentRun: async (runtimeInput, input) => {
286
- await addRuntimeInput(runtimeInput, input);
287
- if (!this.#activeRun) throw new Error("Agent plugin steering requires an active run.");
288
- return this.#activeRun;
289
- },
290
- steerSession: (input) => this.steer(input)
291
- };
292
- }
293
- #invokeLlm({ history, signal }) {
294
- const activeSignal = signal ?? new AbortController().signal;
295
- const invoke = async () => {
296
- let transformedHistory = history;
297
- for (const transform of this.#plugins?.contextTransforms ?? []) transformedHistory = await transform({
298
- history: transformedHistory,
299
- sessionKey: this.#persistence.key,
300
- signal: activeSignal
301
- });
302
- const modelHistory = this.#overlays.compose(transformedHistory, history);
303
- this.#overlays.markInferenceStarted();
304
- return this.#llm({
305
- history: modelHistory,
306
- signal: activeSignal
307
- });
308
- };
309
- return runWithAgentPluginScope(this.#createPluginScope(activeSignal), invoke);
310
- }
311
- async #summarizeForPlugins(messages, signal) {
312
- return outputToText(await this.#internalLlm({
313
- history: [{
314
- content: "Summarize these earlier session messages for future model context.",
315
- role: "system"
316
- }, ...messages],
317
- signal
318
- })) || `Summarized ${messages.length} messages.`;
319
- }
320
- async #withRuntimeInputWindow(runtimeInput, placement, callback) {
321
- const previousSteerPlacement = runtimeInput.steerPlacement;
322
- runtimeInput.placement = placement;
323
- runtimeInput.steerPlacement = placement;
324
- try {
325
- return await callback();
326
- } finally {
327
- runtimeInput.placement = void 0;
328
- runtimeInput.steerPlacement = previousSteerPlacement;
329
- }
330
- }
331
- async #withSteeringPlacement(runtimeInput, placement, callback) {
332
- const previousSteerPlacement = runtimeInput.steerPlacement;
333
- runtimeInput.steerPlacement = placement;
334
- try {
335
- return await callback();
336
- } finally {
337
- runtimeInput.steerPlacement = previousSteerPlacement;
338
- }
339
- }
340
- async #drainRuntimeInput(run, runtimeInput, placement) {
341
- let added = false;
342
- let next = shiftRuntimeInput(runtimeInput, placement);
343
- while (next) {
344
- added = true;
345
- run.emit({
346
- type: "runtime-input",
347
- input: next.input,
348
- placement
349
- });
350
- this.#history.appendUserInput(next.input);
351
- await this.#commitHistory();
352
- next = shiftRuntimeInput(runtimeInput, placement);
353
- }
354
- return added;
355
- }
356
- #expireActiveOverlays(reason) {
357
- const event = this.#overlays.expireActiveFrame(reason);
358
- if (!event) return;
359
- this.#activeRun?.emit(event);
360
- }
361
- };
362
- function errorMessage(error) {
363
- if (error instanceof Error) return error.message;
364
- return String(error);
365
- }
366
- function outputToText(output) {
367
- const parts = [];
368
- for (const message of output) {
369
- if (message.role !== "assistant") continue;
370
- if (typeof message.content === "string") {
371
- parts.push(message.content);
372
- continue;
373
- }
374
- for (const part of message.content) if (part.type === "text") parts.push(part.text);
375
- }
376
- return parts.join("\n").trim();
377
- }
378
- function sessionKilledError() {
379
- return /* @__PURE__ */ new Error("Session killed");
380
- }
381
- var SessionCommitConflictError = class extends Error {
382
- constructor(key) {
383
- super(`Session ${JSON.stringify(key)} commit conflict`);
384
- }
385
203
  };
386
204
  //#endregion
387
205
  export { AgentSession };
@@ -1 +1 @@
1
- {"version":3,"file":"session.js","names":["#inputQueue","#internalLlm","#llm","#onPluginError","#persistence","#plugins","#overlays","#killed","#ensureLoaded","#drainInputQueue","#activeRuntimeInput","#activeRun","#activeAbort","#expireActiveOverlays","#loaded","#loadPromise","#loadSessionState","#replaceWithStoredSession","#storeVersion","#history","#pluginState","#compactions","#running","#processQueuedInput","#withSteeringPlacement","#pluginLifecycle","#withRuntimeInputWindow","#commitHistory","#drainRuntimeInput","#invokeLlm","#summarizeForPlugins","#createPluginScope"],"sources":["../../src/session/session.ts"],"sourcesContent":["import type { ModelMessage } from \"ai\";\nimport { runAgentLoop } from \"../agent-loop\";\nimport type { Llm, LlmOutput } from \"../llm\";\nimport type { ResolvedAgentPlugins } from \"../plugins/runner\";\nimport {\n type AgentPluginScope,\n runWithAgentPluginScope,\n} from \"../plugins/scope\";\nimport type { UserInput } from \"./events\";\nimport { ModelMessageHistory } from \"./history\";\nimport type { AgentInput } from \"./input\";\nimport {\n type AgentPluginErrorHandler,\n type AgentSessionLifecycle,\n createRuntimeInputStepLifecycle,\n runPluginAfterTurnHandlers,\n runPluginBeforeTurnHandlers,\n} from \"./lifecycle\";\nimport { SessionOverlayState } from \"./overlay\";\nimport type { AgentRun } from \"./run\";\nimport { BufferedAgentRun } from \"./run\";\nimport {\n addRuntimeInput,\n closeRuntimeInput,\n createRuntimeInputState,\n normalizeAgentInput,\n type RuntimeInputPlacement,\n type RuntimeInputState,\n shiftRuntimeInput,\n} from \"./runtime-input\";\nimport {\n type AgentCompactionOverlay,\n decodeStoredSessionSnapshot,\n encodeSessionSnapshot,\n} from \"./snapshot\";\nimport type { SessionStore } from \"./store/types\";\n\nexport type { AgentInput, SessionInput, UserInput } from \"./input\";\nexport type { AgentRun } from \"./run\";\n\ninterface SessionPersistenceOptions {\n readonly key: string;\n readonly store: SessionStore;\n}\n\ninterface QueuedInput {\n readonly input: UserInput;\n readonly run: BufferedAgentRun;\n readonly runtimeInput: RuntimeInputState;\n}\n\nexport class AgentSession {\n readonly #inputQueue: QueuedInput[] = [];\n readonly #internalLlm: Llm;\n readonly #llm: Llm;\n readonly #onPluginError?: AgentPluginErrorHandler;\n readonly #persistence: SessionPersistenceOptions;\n readonly #plugins?: ResolvedAgentPlugins;\n #activeAbort?: AbortController;\n #activeRun?: BufferedAgentRun;\n #activeRuntimeInput?: RuntimeInputState;\n #history = new ModelMessageHistory();\n #killed = false;\n #loadPromise?: Promise<void>;\n #loaded = false;\n #pluginState: Record<string, unknown> = {};\n #compactions: AgentCompactionOverlay[] = [];\n readonly #overlays = new SessionOverlayState();\n #running = false;\n #storeVersion: string | undefined;\n\n constructor(\n llm: Llm,\n persistence: SessionPersistenceOptions,\n plugins?: ResolvedAgentPlugins,\n internalLlm: Llm = llm,\n onPluginError?: AgentPluginErrorHandler\n ) {\n this.#internalLlm = internalLlm;\n this.#onPluginError = onPluginError;\n this.#persistence = persistence;\n this.#plugins = plugins;\n this.#llm = llm;\n }\n\n async send(input: AgentInput): Promise<AgentRun> {\n if (this.#killed) {\n throw sessionKilledError();\n }\n\n await this.#ensureLoaded();\n\n if (this.#killed) {\n throw sessionKilledError();\n }\n\n const runtimeInput = createRuntimeInputState();\n const acceptedInput = normalizeAgentInput(input);\n const run = new BufferedAgentRun();\n run.emit(acceptedInput);\n this.#inputQueue.push({\n input: structuredClone(acceptedInput),\n run,\n runtimeInput,\n });\n this.#drainInputQueue().catch((error: unknown) => {\n run.emit({ type: \"turn-error\", message: errorMessage(error) });\n run.close();\n });\n return run;\n }\n\n async steer(input: AgentInput): Promise<AgentRun> {\n if (this.#killed) {\n throw sessionKilledError();\n }\n\n const runtimeInput = this.#activeRuntimeInput;\n const run = this.#activeRun;\n if (!(runtimeInput && run)) {\n return this.send(input);\n }\n\n await addRuntimeInput(runtimeInput, input);\n return run;\n }\n\n async overlay(input: AgentInput): Promise<AgentRun> {\n if (this.#killed) {\n throw sessionKilledError();\n }\n\n await this.#ensureLoaded();\n\n if (this.#killed) {\n throw sessionKilledError();\n }\n\n const activeRun = this.#activeRun;\n if (activeRun) {\n const placement =\n this.#activeRuntimeInput?.steerPlacement ??\n this.#activeRuntimeInput?.placement ??\n \"step-end\";\n const entry = this.#overlays.appendActiveOverlay(input, placement);\n if (!entry) {\n throw new Error(\"Active overlay frame is unavailable.\");\n }\n activeRun.emit({\n input: entry.summary,\n placement: entry.placement,\n type: \"overlay-accepted\",\n });\n return activeRun;\n }\n\n const entry = this.#overlays.appendPendingOverlay(input);\n const run = new BufferedAgentRun();\n run.emit({\n input: entry.summary,\n placement: entry.placement,\n type: \"overlay-accepted\",\n });\n run.close();\n return run;\n }\n\n interrupt(): void {\n this.#activeAbort?.abort();\n }\n\n kill(): void {\n if (this.#killed) {\n return;\n }\n\n this.#killed = true;\n this.#expireActiveOverlays(\"kill\");\n this.#activeAbort?.abort();\n closeRuntimeInput(this.#activeRuntimeInput, sessionKilledError().message);\n\n while (this.#inputQueue.length > 0) {\n const item = this.#inputQueue.shift();\n closeRuntimeInput(item?.runtimeInput, sessionKilledError().message);\n item?.run.emit({\n type: \"turn-error\",\n message: sessionKilledError().message,\n });\n item?.run.close(undefined, sessionKilledError().message);\n }\n }\n\n async #ensureLoaded(): Promise<void> {\n if (this.#loaded) {\n return;\n }\n\n this.#loadPromise ??= this.#loadSessionState();\n try {\n await this.#loadPromise;\n } catch (error) {\n this.#loadPromise = undefined;\n throw error;\n }\n }\n\n async #loadSessionState(): Promise<void> {\n if (this.#loaded) {\n return;\n }\n\n await this.#replaceWithStoredSession();\n this.#loaded = true;\n }\n\n async #replaceWithStoredSession(): Promise<void> {\n const stored = await this.#persistence.store.load(this.#persistence.key);\n this.#storeVersion = stored?.version;\n const snapshot = decodeStoredSessionSnapshot(stored);\n this.#history = new ModelMessageHistory(snapshot.history);\n this.#pluginState = structuredClone(snapshot.pluginState);\n this.#compactions = structuredClone(snapshot.compactions);\n }\n\n async #drainInputQueue(): Promise<void> {\n if (this.#running) {\n return;\n }\n\n this.#running = true;\n try {\n while (!this.#killed && this.#inputQueue.length > 0) {\n const item = this.#inputQueue.shift();\n if (item) {\n await this.#processQueuedInput(item);\n }\n }\n } finally {\n this.#running = false;\n }\n }\n\n async #processQueuedInput({\n input,\n run,\n runtimeInput,\n }: QueuedInput): Promise<void> {\n const activeAbort = new AbortController();\n this.#activeAbort = activeAbort;\n const historySnapshot = this.#history.modelSnapshot();\n this.#overlays.startTurn(input, historySnapshot);\n this.#activeRun = run;\n this.#activeRuntimeInput = runtimeInput;\n\n try {\n await this.#withSteeringPlacement(\n runtimeInput,\n \"turn-start\",\n async () => {\n await runPluginBeforeTurnHandlers(this.#pluginLifecycle(), {\n input,\n runtimeInput,\n signal: activeAbort.signal,\n });\n }\n );\n await this.#withRuntimeInputWindow(\n runtimeInput,\n \"turn-start\",\n async () => {\n await run.emitBoundary({ type: \"turn-start\" });\n }\n );\n this.#history.appendUserInput(input);\n await this.#commitHistory();\n await this.#drainRuntimeInput(run, runtimeInput, \"turn-start\");\n\n const result = await runAgentLoop({\n emit: async (event) => {\n if (event.type === \"step-start\" || event.type === \"step-end\") {\n await this.#withRuntimeInputWindow(\n runtimeInput,\n event.type,\n async () => {\n await run.emitBoundary(event);\n }\n );\n const overlayInputAdded =\n event.type === \"step-end\" &&\n this.#overlays.consumeStepEndOverlayInputAdded();\n const runtimeInputAdded = await this.#drainRuntimeInput(\n run,\n runtimeInput,\n event.type\n );\n\n if (event.type === \"step-end\") {\n return {\n overlayInputAdded,\n runtimeInputAdded,\n };\n }\n return;\n }\n\n run.emit(event);\n },\n history: this.#history,\n stepLifecycle: createRuntimeInputStepLifecycle({\n lifecycle: this.#pluginLifecycle(),\n runtimeInput,\n withSteeringPlacement: (placement, callback) =>\n this.#withSteeringPlacement(runtimeInput, placement, callback),\n }),\n llm: (context) => this.#invokeLlm(context),\n signal: activeAbort.signal,\n });\n\n await this.#commitHistory();\n const terminalEvent = result === \"aborted\" ? \"turn-abort\" : \"turn-end\";\n closeRuntimeInput(runtimeInput, terminalEvent);\n this.#expireActiveOverlays(terminalEvent);\n this.#activeRuntimeInput = undefined;\n this.#activeRun = undefined;\n const pluginHandlersRan = await runPluginAfterTurnHandlers(\n this.#pluginLifecycle(),\n {\n input,\n result,\n signal: activeAbort.signal,\n }\n );\n if (pluginHandlersRan) {\n await this.#commitHistory();\n }\n run.emit({ type: terminalEvent });\n } catch (error) {\n if (error instanceof SessionCommitConflictError) {\n run.emit({ type: \"turn-error\", message: error.message });\n closeRuntimeInput(runtimeInput, \"a session commit conflict\");\n this.#expireActiveOverlays(\"turn-error\");\n this.#activeAbort = undefined;\n return;\n }\n\n this.#history.rollback(historySnapshot);\n try {\n await this.#commitHistory();\n } catch (rollbackError) {\n run.emit({\n type: \"turn-error\",\n message: `${errorMessage(error)}; history rollback persistence failed: ${errorMessage(\n rollbackError\n )}`,\n });\n closeRuntimeInput(runtimeInput, \"turn-error\");\n this.#expireActiveOverlays(\"turn-error\");\n this.#activeAbort = undefined;\n return;\n }\n run.emit({ type: \"turn-error\", message: errorMessage(error) });\n closeRuntimeInput(runtimeInput, \"turn-error\");\n this.#expireActiveOverlays(\"turn-error\");\n } finally {\n closeRuntimeInput(runtimeInput);\n this.#activeAbort = undefined;\n this.#activeRun = undefined;\n this.#activeRuntimeInput = undefined;\n this.#overlays.resetActiveTurn();\n run.close(undefined, runtimeInput.closedReason);\n }\n }\n\n async #commitHistory(): Promise<void> {\n const result = await this.#persistence.store.commit(\n this.#persistence.key,\n {\n state: encodeSessionSnapshot({\n compactions: this.#compactions,\n history: this.#history.modelSnapshot(),\n pluginState: this.#pluginState,\n }),\n },\n { expectedVersion: this.#storeVersion ?? null }\n );\n\n if (!result.ok) {\n await this.#replaceWithStoredSession();\n throw new SessionCommitConflictError(this.#persistence.key);\n }\n\n this.#storeVersion = result.version;\n }\n\n #createPluginScope(signal: AbortSignal): AgentPluginScope {\n return {\n eventHandlers: this.#plugins?.eventHandlers,\n getCompactions: () => structuredClone(this.#compactions),\n getPluginState: (pluginName) => this.#pluginState[pluginName],\n history: () => this.#history.modelSnapshot(),\n sessionKey: this.#persistence.key,\n overlay: (input) => this.overlay(input),\n setCompactions: (compactions) => {\n this.#compactions = structuredClone([...compactions]);\n },\n setPluginState: (pluginName, state) => {\n this.#pluginState = {\n ...this.#pluginState,\n [pluginName]: structuredClone(state),\n };\n },\n signal,\n steer: (input) => this.steer(input),\n summarize: (messages) => this.#summarizeForPlugins(messages, signal),\n };\n }\n\n #pluginLifecycle(): AgentSessionLifecycle {\n return {\n createScope: (signal) => this.#createPluginScope(signal),\n history: () => this.#history.modelSnapshot(),\n onPluginError: this.#onPluginError,\n plugins: this.#plugins,\n sessionKey: this.#persistence.key,\n overlaySession: (input) => this.overlay(input),\n steerCurrentRun: async (runtimeInput, input) => {\n await addRuntimeInput(runtimeInput, input);\n if (!this.#activeRun) {\n throw new Error(\"Agent plugin steering requires an active run.\");\n }\n return this.#activeRun;\n },\n steerSession: (input) => this.steer(input),\n };\n }\n\n #invokeLlm({\n history,\n signal,\n }: {\n readonly history: readonly ModelMessage[];\n readonly signal?: AbortSignal;\n }): Promise<LlmOutput> {\n const activeSignal = signal ?? new AbortController().signal;\n const invoke = async () => {\n let transformedHistory = history;\n for (const transform of this.#plugins?.contextTransforms ?? []) {\n transformedHistory = await transform({\n history: transformedHistory,\n sessionKey: this.#persistence.key,\n signal: activeSignal,\n });\n }\n\n const modelHistory = this.#overlays.compose(transformedHistory, history);\n this.#overlays.markInferenceStarted();\n return this.#llm({\n history: modelHistory,\n signal: activeSignal,\n });\n };\n\n return runWithAgentPluginScope(\n this.#createPluginScope(activeSignal),\n invoke\n );\n }\n\n async #summarizeForPlugins(\n messages: readonly ModelMessage[],\n signal: AbortSignal\n ): Promise<string> {\n const output = await this.#internalLlm({\n history: [\n {\n content:\n \"Summarize these earlier session messages for future model context.\",\n role: \"system\",\n },\n ...messages,\n ],\n signal,\n });\n return outputToText(output) || `Summarized ${messages.length} messages.`;\n }\n\n async #withRuntimeInputWindow<T>(\n runtimeInput: RuntimeInputState,\n placement: RuntimeInputPlacement,\n callback: () => Promise<T>\n ): Promise<T> {\n const previousSteerPlacement = runtimeInput.steerPlacement;\n runtimeInput.placement = placement;\n runtimeInput.steerPlacement = placement;\n try {\n return await callback();\n } finally {\n runtimeInput.placement = undefined;\n runtimeInput.steerPlacement = previousSteerPlacement;\n }\n }\n\n async #withSteeringPlacement<T>(\n runtimeInput: RuntimeInputState,\n placement: RuntimeInputPlacement,\n callback: () => Promise<T>\n ): Promise<T> {\n const previousSteerPlacement = runtimeInput.steerPlacement;\n runtimeInput.steerPlacement = placement;\n try {\n return await callback();\n } finally {\n runtimeInput.steerPlacement = previousSteerPlacement;\n }\n }\n\n async #drainRuntimeInput(\n run: BufferedAgentRun,\n runtimeInput: RuntimeInputState,\n placement: RuntimeInputPlacement\n ): Promise<boolean> {\n let added = false;\n let next = shiftRuntimeInput(runtimeInput, placement);\n while (next) {\n added = true;\n run.emit({ type: \"runtime-input\", input: next.input, placement });\n this.#history.appendUserInput(next.input);\n await this.#commitHistory();\n next = shiftRuntimeInput(runtimeInput, placement);\n }\n\n return added;\n }\n\n #expireActiveOverlays(\n reason: \"kill\" | \"turn-abort\" | \"turn-end\" | \"turn-error\"\n ): void {\n const event = this.#overlays.expireActiveFrame(reason);\n if (!event) {\n return;\n }\n\n this.#activeRun?.emit(event);\n }\n}\n\nfunction errorMessage(error: unknown): string {\n if (error instanceof Error) {\n return error.message;\n }\n\n return String(error);\n}\n\nfunction outputToText(output: LlmOutput): string {\n const parts: string[] = [];\n for (const message of output) {\n if (message.role !== \"assistant\") {\n continue;\n }\n\n if (typeof message.content === \"string\") {\n parts.push(message.content);\n continue;\n }\n\n for (const part of message.content) {\n if (part.type === \"text\") {\n parts.push(part.text);\n }\n }\n }\n\n return parts.join(\"\\n\").trim();\n}\n\nfunction sessionKilledError(): Error {\n return new Error(\"Session killed\");\n}\n\nclass SessionCommitConflictError extends Error {\n constructor(key: string) {\n super(`Session ${JSON.stringify(key)} commit conflict`);\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"session.js","names":["#hooks","#inputQueue","#llm","#pendingRuntimeInputs","#state","#killed","#deletePromise","#drainInputQueue","#activeRuntimeInput","#activeRun","#activeAbort","#enqueuePendingRuntimeInput","#runToCloseOnKill","#running","#processQueuedInput"],"sources":["../../src/session/session.ts"],"sourcesContent":["import { runAgentLoop } from \"../agent-loop\";\nimport type { AgentHooks } from \"../hooks\";\nimport type { Llm } from \"../llm\";\nimport type { AgentEvent } from \"./events\";\nimport type { AgentInput, UserInput } from \"./input\";\nimport { normalizeAgentInput } from \"./input-normalization\";\nimport { type AgentRun, BufferedAgentRun } from \"./run\";\nimport {\n addSteeringInput,\n closeRuntimeInput,\n createRuntimeInputState,\n hooksForRuntimeInput,\n type QueuedInput,\n type QueuedRuntimeInput,\n type RuntimeInputPlacement,\n type RuntimeInputState,\n withRuntimeInputWindow,\n withSteeringPlacement,\n} from \"./runtime-input\";\nimport {\n errorMessage,\n runAfterTurnHook,\n sessionKilledError,\n sessionTerminalError,\n} from \"./session-errors\";\nimport { closeKilledRuntimeInputs } from \"./session-kill\";\nimport { drainRuntimeInput } from \"./session-runtime-drain\";\nimport { type SessionPersistenceOptions, SessionState } from \"./session-state\";\nimport { emitTurnErrorAfterRecovery } from \"./session-turn-error\";\n\nexport type { AgentInput, SessionInput, UserInput } from \"./input\";\nexport type { AgentRun } from \"./run\";\n\nexport class AgentSession {\n readonly #hooks?: AgentHooks;\n readonly #inputQueue: QueuedInput[] = [];\n readonly #llm: Llm;\n readonly #pendingRuntimeInputs: QueuedRuntimeInput[] = [];\n readonly #state: SessionState;\n #activeAbort?: AbortController;\n #activeRun?: BufferedAgentRun;\n #activeRuntimeInput?: RuntimeInputState;\n #deletePromise?: Promise<void>;\n #killed = false;\n #running = false;\n #runToCloseOnKill?: BufferedAgentRun;\n\n constructor(\n llm: Llm,\n persistence: SessionPersistenceOptions,\n hooks?: AgentHooks\n ) {\n this.#hooks = hooks;\n this.#llm = llm;\n this.#state = new SessionState(persistence);\n }\n\n async send(input: AgentInput): Promise<AgentRun> {\n if (this.#killed || this.#deletePromise) {\n throw sessionTerminalError(this.#killed);\n }\n\n await this.#state.ensureLoaded();\n\n if (this.#killed || this.#deletePromise) {\n throw sessionTerminalError(this.#killed);\n }\n\n const runtimeInput = createRuntimeInputState(\n this.#pendingRuntimeInputs.splice(0)\n );\n const acceptedInput = normalizeAgentInput(input);\n const run = new BufferedAgentRun();\n run.emit(acceptedInput);\n this.#inputQueue.push({\n input: structuredClone(acceptedInput),\n run,\n runtimeInput,\n });\n this.#drainInputQueue().catch((error: unknown) => {\n run.emit({ type: \"turn-error\", message: errorMessage(error) });\n run.close();\n });\n return run;\n }\n\n async steer(input: AgentInput): Promise<AgentRun> {\n if (this.#killed || this.#deletePromise) {\n throw sessionTerminalError(this.#killed);\n }\n\n const runtimeInput = this.#activeRuntimeInput;\n const run = this.#activeRun;\n if (!(runtimeInput && run)) {\n return this.send(input);\n }\n\n await addSteeringInput(runtimeInput, input);\n return run;\n }\n\n interrupt(): void {\n this.#activeAbort?.abort();\n }\n\n delete(): Promise<void> {\n this.#deletePromise ??= this.#state.delete().then(\n () => this.kill(),\n (error: unknown) => {\n this.#deletePromise = undefined;\n throw error;\n }\n );\n return this.#deletePromise;\n }\n\n enqueueRuntimeInput(\n input: UserInput,\n placement: RuntimeInputPlacement = \"turn-start\"\n ): void {\n if (this.#killed) {\n return;\n }\n\n const runtimeInput = this.#activeRuntimeInput;\n if (runtimeInput && !runtimeInput.closedReason) {\n if (placement === \"turn-start\" && runtimeInput.placement !== placement) {\n this.#enqueuePendingRuntimeInput({ input, placement });\n return;\n }\n\n runtimeInput.queue.push({ input, placement });\n return;\n }\n\n this.#enqueuePendingRuntimeInput({ input, placement });\n }\n\n emitObserverEvent(event: AgentEvent): void {\n this.#activeRun?.emit(event);\n }\n\n #enqueuePendingRuntimeInput(input: QueuedRuntimeInput): void {\n const queuedTurn = this.#inputQueue[0];\n if (input.placement === \"turn-start\" && queuedTurn) {\n queuedTurn.runtimeInput.queue.push(input);\n return;\n }\n\n this.#pendingRuntimeInputs.push(input);\n }\n\n kill(): void {\n if (this.#killed) {\n return;\n }\n\n this.#killed = true;\n const killedError = sessionKilledError();\n this.#pendingRuntimeInputs.length = 0;\n this.#activeAbort?.abort();\n closeKilledRuntimeInputs({\n activeRuntimeInput: this.#activeRuntimeInput,\n inputQueue: this.#inputQueue,\n message: killedError.message,\n runToClose: this.#runToCloseOnKill ?? this.#activeRun,\n });\n }\n\n async #drainInputQueue(): Promise<void> {\n if (this.#running) {\n return;\n }\n\n this.#running = true;\n try {\n while (!this.#killed && this.#inputQueue.length > 0) {\n const item = this.#inputQueue.shift();\n if (item) {\n await this.#processQueuedInput(item);\n }\n }\n } finally {\n this.#running = false;\n }\n }\n\n async #processQueuedInput({\n input,\n run,\n runtimeInput,\n }: QueuedInput): Promise<void> {\n const activeAbort = new AbortController();\n this.#activeAbort = activeAbort;\n this.#activeRun = run;\n this.#activeRuntimeInput = runtimeInput;\n this.#runToCloseOnKill = run;\n const historySnapshot = this.#state.modelSnapshot();\n\n try {\n await withSteeringPlacement(runtimeInput, \"turn-start\", async () => {\n await this.#hooks?.beforeTurn?.({\n history: this.#state.modelSnapshot(),\n input,\n signal: activeAbort.signal,\n });\n });\n await withRuntimeInputWindow(runtimeInput, \"turn-start\", async () => {\n await run.emitBoundary({ type: \"turn-start\" });\n });\n this.#state.appendUserInput(input);\n await this.#state.commit();\n await drainRuntimeInput({\n placement: \"turn-start\",\n run,\n runtimeInput,\n state: this.#state,\n });\n\n const result = await runAgentLoop({\n emit: async (event) => {\n if (event.type === \"step-start\" || event.type === \"step-end\") {\n await withRuntimeInputWindow(runtimeInput, event.type, async () => {\n await run.emitBoundary(event);\n });\n const runtimeInputAdded = await drainRuntimeInput({\n placement: event.type,\n run,\n runtimeInput,\n state: this.#state,\n });\n\n return event.type === \"step-end\"\n ? { runtimeInputAdded }\n : undefined;\n }\n\n run.emit(event);\n },\n history: this.#state.history,\n hooks: hooksForRuntimeInput(this.#hooks, runtimeInput),\n llm: this.#llm,\n signal: activeAbort.signal,\n });\n\n await this.#state.commit();\n const terminalEvent = result === \"aborted\" ? \"turn-abort\" : \"turn-end\";\n closeRuntimeInput(runtimeInput, terminalEvent);\n this.#activeRuntimeInput = undefined;\n this.#activeRun = undefined;\n await runAfterTurnHook(this.#hooks, {\n history: this.#state.modelSnapshot(),\n input,\n result,\n signal: activeAbort.signal,\n });\n run.emit({ type: terminalEvent });\n } catch (error) {\n const turnError =\n error instanceof Error ? error : new Error(String(error));\n await emitTurnErrorAfterRecovery({\n error: turnError,\n historySnapshot,\n run,\n runtimeInput,\n state: this.#state,\n });\n } finally {\n closeRuntimeInput(runtimeInput);\n this.#activeAbort = undefined;\n this.#activeRun = undefined;\n this.#activeRuntimeInput = undefined;\n this.#runToCloseOnKill = undefined;\n run.close(undefined, runtimeInput.closedReason);\n }\n }\n}\n"],"mappings":"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"}
@@ -1,45 +1,19 @@
1
1
  //#region src/session/snapshot.ts
2
- function encodeSessionSnapshot(state) {
2
+ function encodeSessionSnapshot(history) {
3
3
  return {
4
- compactions: structuredClone([...state.compactions ?? []]),
5
- history: structuredClone([...state.history]),
6
- pluginState: structuredClone({ ...state.pluginState ?? {} }),
7
- schemaVersion: 2
4
+ schemaVersion: 1,
5
+ history: structuredClone(history)
8
6
  };
9
7
  }
10
8
  function decodeStoredSessionSnapshot(stored) {
11
- if (!stored) return emptySnapshotState();
9
+ if (!stored) return [];
12
10
  const snapshot = stored.state;
13
- if (isSessionSnapshotV1(snapshot)) return {
14
- ...emptySnapshotState(),
15
- history: structuredClone(snapshot.history)
16
- };
17
- if (isSessionSnapshotV2(snapshot)) return {
18
- compactions: structuredClone(snapshot.compactions),
19
- history: structuredClone(snapshot.history),
20
- pluginState: structuredClone(snapshot.pluginState)
21
- };
11
+ if (isSessionSnapshotV1(snapshot)) return structuredClone(snapshot.history);
22
12
  throw new Error("Unsupported stored session state");
23
13
  }
24
- function emptySnapshotState() {
25
- return {
26
- compactions: [],
27
- history: [],
28
- pluginState: {}
29
- };
30
- }
31
14
  function isSessionSnapshotV1(value) {
32
15
  return value !== null && typeof value === "object" && "schemaVersion" in value && value.schemaVersion === 1 && "history" in value && Array.isArray(value.history);
33
16
  }
34
- function isSessionSnapshotV2(value) {
35
- return value !== null && typeof value === "object" && "schemaVersion" in value && value.schemaVersion === 2 && "history" in value && Array.isArray(value.history) && "pluginState" in value && isRecord(value.pluginState) && "compactions" in value && Array.isArray(value.compactions) && value.compactions.every(isCompactionOverlay);
36
- }
37
- function isCompactionOverlay(value) {
38
- return value !== null && typeof value === "object" && "createdAt" in value && typeof value.createdAt === "string" && "endIndex" in value && typeof value.endIndex === "number" && "id" in value && typeof value.id === "string" && "startIndex" in value && typeof value.startIndex === "number" && "summary" in value && typeof value.summary === "string";
39
- }
40
- function isRecord(value) {
41
- return value !== null && typeof value === "object" && !Array.isArray(value);
42
- }
43
17
  //#endregion
44
18
  export { decodeStoredSessionSnapshot, encodeSessionSnapshot };
45
19
 
@@ -1 +1 @@
1
- {"version":3,"file":"snapshot.js","names":[],"sources":["../../src/session/snapshot.ts"],"sourcesContent":["import type { ModelMessage } from \"ai\";\nimport type { StoredSession } from \"./store/types\";\n\nexport interface AgentSessionSnapshotV1 {\n readonly history: ModelMessage[];\n readonly schemaVersion: 1;\n}\n\nexport interface AgentCompactionOverlay {\n readonly createdAt: string;\n readonly endIndex: number;\n readonly id: string;\n readonly startIndex: number;\n readonly summary: string;\n}\n\nexport interface AgentSessionSnapshotV2 {\n readonly compactions: AgentCompactionOverlay[];\n readonly history: ModelMessage[];\n readonly pluginState: Record<string, unknown>;\n readonly schemaVersion: 2;\n}\n\nexport interface AgentSessionSnapshotState {\n readonly compactions?: readonly AgentCompactionOverlay[];\n readonly history: readonly ModelMessage[];\n readonly pluginState?: Readonly<Record<string, unknown>>;\n}\n\nexport type AgentSessionSnapshot = AgentSessionSnapshotV2;\n\nexport interface DecodedSessionSnapshot {\n readonly compactions: AgentCompactionOverlay[];\n readonly history: ModelMessage[];\n readonly pluginState: Record<string, unknown>;\n}\n\nexport function encodeSessionSnapshot(\n state: AgentSessionSnapshotState\n): AgentSessionSnapshot {\n return {\n compactions: structuredClone([...(state.compactions ?? [])]),\n history: structuredClone([...state.history]),\n pluginState: structuredClone({ ...(state.pluginState ?? {}) }),\n schemaVersion: 2,\n };\n}\n\nexport function decodeStoredSessionSnapshot(\n stored: StoredSession | null\n): DecodedSessionSnapshot {\n if (!stored) {\n return emptySnapshotState();\n }\n\n const snapshot = stored.state;\n if (isSessionSnapshotV1(snapshot)) {\n return {\n ...emptySnapshotState(),\n history: structuredClone(snapshot.history),\n };\n }\n\n if (isSessionSnapshotV2(snapshot)) {\n return {\n compactions: structuredClone(snapshot.compactions),\n history: structuredClone(snapshot.history),\n pluginState: structuredClone(snapshot.pluginState),\n };\n }\n\n throw new Error(\"Unsupported stored session state\");\n}\n\nfunction emptySnapshotState(): DecodedSessionSnapshot {\n return { compactions: [], history: [], pluginState: {} };\n}\n\nfunction isSessionSnapshotV1(value: unknown): value is AgentSessionSnapshotV1 {\n return (\n value !== null &&\n typeof value === \"object\" &&\n \"schemaVersion\" in value &&\n value.schemaVersion === 1 &&\n \"history\" in value &&\n Array.isArray(value.history)\n );\n}\n\nfunction isSessionSnapshotV2(value: unknown): value is AgentSessionSnapshotV2 {\n return (\n value !== null &&\n typeof value === \"object\" &&\n \"schemaVersion\" in value &&\n value.schemaVersion === 2 &&\n \"history\" in value &&\n Array.isArray(value.history) &&\n \"pluginState\" in value &&\n isRecord(value.pluginState) &&\n \"compactions\" in value &&\n Array.isArray(value.compactions) &&\n value.compactions.every(isCompactionOverlay)\n );\n}\n\nfunction isCompactionOverlay(value: unknown): value is AgentCompactionOverlay {\n return (\n value !== null &&\n typeof value === \"object\" &&\n \"createdAt\" in value &&\n typeof value.createdAt === \"string\" &&\n \"endIndex\" in value &&\n typeof value.endIndex === \"number\" &&\n \"id\" in value &&\n typeof value.id === \"string\" &&\n \"startIndex\" in value &&\n typeof value.startIndex === \"number\" &&\n \"summary\" in value &&\n typeof value.summary === \"string\"\n );\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return value !== null && typeof value === \"object\" && !Array.isArray(value);\n}\n"],"mappings":";AAqCA,SAAgB,sBACd,OACsB;CACtB,OAAO;EACL,aAAa,gBAAgB,CAAC,GAAI,MAAM,eAAe,CAAC,CAAE,CAAC;EAC3D,SAAS,gBAAgB,CAAC,GAAG,MAAM,OAAO,CAAC;EAC3C,aAAa,gBAAgB,EAAE,GAAI,MAAM,eAAe,CAAC,EAAG,CAAC;EAC7D,eAAe;CACjB;AACF;AAEA,SAAgB,4BACd,QACwB;CACxB,IAAI,CAAC,QACH,OAAO,mBAAmB;CAG5B,MAAM,WAAW,OAAO;CACxB,IAAI,oBAAoB,QAAQ,GAC9B,OAAO;EACL,GAAG,mBAAmB;EACtB,SAAS,gBAAgB,SAAS,OAAO;CAC3C;CAGF,IAAI,oBAAoB,QAAQ,GAC9B,OAAO;EACL,aAAa,gBAAgB,SAAS,WAAW;EACjD,SAAS,gBAAgB,SAAS,OAAO;EACzC,aAAa,gBAAgB,SAAS,WAAW;CACnD;CAGF,MAAM,IAAI,MAAM,kCAAkC;AACpD;AAEA,SAAS,qBAA6C;CACpD,OAAO;EAAE,aAAa,CAAC;EAAG,SAAS,CAAC;EAAG,aAAa,CAAC;CAAE;AACzD;AAEA,SAAS,oBAAoB,OAAiD;CAC5E,OACE,UAAU,QACV,OAAO,UAAU,YACjB,mBAAmB,SACnB,MAAM,kBAAkB,KACxB,aAAa,SACb,MAAM,QAAQ,MAAM,OAAO;AAE/B;AAEA,SAAS,oBAAoB,OAAiD;CAC5E,OACE,UAAU,QACV,OAAO,UAAU,YACjB,mBAAmB,SACnB,MAAM,kBAAkB,KACxB,aAAa,SACb,MAAM,QAAQ,MAAM,OAAO,KAC3B,iBAAiB,SACjB,SAAS,MAAM,WAAW,KAC1B,iBAAiB,SACjB,MAAM,QAAQ,MAAM,WAAW,KAC/B,MAAM,YAAY,MAAM,mBAAmB;AAE/C;AAEA,SAAS,oBAAoB,OAAiD;CAC5E,OACE,UAAU,QACV,OAAO,UAAU,YACjB,eAAe,SACf,OAAO,MAAM,cAAc,YAC3B,cAAc,SACd,OAAO,MAAM,aAAa,YAC1B,QAAQ,SACR,OAAO,MAAM,OAAO,YACpB,gBAAgB,SAChB,OAAO,MAAM,eAAe,YAC5B,aAAa,SACb,OAAO,MAAM,YAAY;AAE7B;AAEA,SAAS,SAAS,OAAkD;CAClE,OAAO,UAAU,QAAQ,OAAO,UAAU,YAAY,CAAC,MAAM,QAAQ,KAAK;AAC5E"}
1
+ {"version":3,"file":"snapshot.js","names":[],"sources":["../../src/session/snapshot.ts"],"sourcesContent":["import type { ModelMessage } from \"ai\";\nimport type { StoredSession } from \"./store/types\";\n\nexport interface AgentSessionSnapshotV1 {\n readonly history: ModelMessage[];\n readonly schemaVersion: 1;\n}\n\nexport type AgentSessionSnapshot = AgentSessionSnapshotV1;\n\nexport function encodeSessionSnapshot(\n history: ModelMessage[]\n): AgentSessionSnapshot {\n return { schemaVersion: 1, history: structuredClone(history) };\n}\n\nexport function decodeStoredSessionSnapshot(\n stored: StoredSession | null\n): ModelMessage[] {\n if (!stored) {\n return [];\n }\n\n const snapshot = stored.state;\n if (isSessionSnapshotV1(snapshot)) {\n return structuredClone(snapshot.history);\n }\n\n throw new Error(\"Unsupported stored session state\");\n}\n\nfunction isSessionSnapshotV1(value: unknown): value is AgentSessionSnapshotV1 {\n return (\n value !== null &&\n typeof value === \"object\" &&\n \"schemaVersion\" in value &&\n value.schemaVersion === 1 &&\n \"history\" in value &&\n Array.isArray(value.history)\n );\n}\n"],"mappings":";AAUA,SAAgB,sBACd,SACsB;CACtB,OAAO;EAAE,eAAe;EAAG,SAAS,gBAAgB,OAAO;CAAE;AAC/D;AAEA,SAAgB,4BACd,QACgB;CAChB,IAAI,CAAC,QACH,OAAO,CAAC;CAGV,MAAM,WAAW,OAAO;CACxB,IAAI,oBAAoB,QAAQ,GAC9B,OAAO,gBAAgB,SAAS,OAAO;CAGzC,MAAM,IAAI,MAAM,kCAAkC;AACpD;AAEA,SAAS,oBAAoB,OAAiD;CAC5E,OACE,UAAU,QACV,OAAO,UAAU,YACjB,mBAAmB,SACnB,MAAM,kBAAkB,KACxB,aAAa,SACb,MAAM,QAAQ,MAAM,OAAO;AAE/B"}
@@ -8,6 +8,7 @@ declare class FileSessionStore implements SessionStore {
8
8
  commit(key: string, next: SessionStoreCommit, options: {
9
9
  expectedVersion: string | null;
10
10
  }): Promise<CommitResult>;
11
+ delete(key: string): Promise<void>;
11
12
  }
12
13
  //#endregion
13
14
  export { FileSessionStore };
@@ -57,6 +57,20 @@ var FileSessionStore = class {
57
57
  });
58
58
  }
59
59
  }
60
+ async delete(key) {
61
+ const file = this.#fileForKey(key);
62
+ const lockDirectory = `${file}.lock`;
63
+ await mkdir(dirname(file), { recursive: true });
64
+ await acquireFileLock(lockDirectory);
65
+ try {
66
+ await rm(file, { force: true });
67
+ } finally {
68
+ await rm(lockDirectory, {
69
+ force: true,
70
+ recursive: true
71
+ });
72
+ }
73
+ }
60
74
  #fileForKey(key) {
61
75
  return join(this.#directory, `${Buffer.from(key).toString("base64url")}.json`);
62
76
  }