@minpeter/pss-runtime 0.0.11 → 0.1.0-next.0

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 (60) hide show
  1. package/README.md +191 -20
  2. package/dist/agent-loop.d.ts +1 -0
  3. package/dist/agent-loop.js +14 -8
  4. package/dist/agent-loop.js.map +1 -1
  5. package/dist/agent.d.ts +8 -10
  6. package/dist/agent.js +34 -13
  7. package/dist/agent.js.map +1 -1
  8. package/dist/index.d.ts +8 -4
  9. package/dist/index.js +6 -1
  10. package/dist/llm.js +7 -1
  11. package/dist/llm.js.map +1 -1
  12. package/dist/plugins/compaction.d.ts +15 -0
  13. package/dist/plugins/compaction.js +98 -0
  14. package/dist/plugins/compaction.js.map +1 -0
  15. package/dist/plugins/index.d.ts +5 -0
  16. package/dist/plugins/index.js +5 -0
  17. package/dist/plugins/memory.d.ts +11 -0
  18. package/dist/plugins/memory.js +146 -0
  19. package/dist/plugins/memory.js.map +1 -0
  20. package/dist/plugins/runner.d.ts +1 -0
  21. package/dist/plugins/runner.js +83 -0
  22. package/dist/plugins/runner.js.map +1 -0
  23. package/dist/plugins/scope.d.ts +1 -0
  24. package/dist/plugins/scope.js +13 -0
  25. package/dist/plugins/scope.js.map +1 -0
  26. package/dist/plugins/sessions.d.ts +12 -0
  27. package/dist/plugins/sessions.js +34 -0
  28. package/dist/plugins/sessions.js.map +1 -0
  29. package/dist/plugins/tool-hook-handlers.js +77 -0
  30. package/dist/plugins/tool-hook-handlers.js.map +1 -0
  31. package/dist/plugins/tool-hook-results.js +64 -0
  32. package/dist/plugins/tool-hook-results.js.map +1 -0
  33. package/dist/plugins/tool-hooks.js +111 -0
  34. package/dist/plugins/tool-hooks.js.map +1 -0
  35. package/dist/plugins/types.d.ts +105 -0
  36. package/dist/plugins/types.js +20 -0
  37. package/dist/plugins/types.js.map +1 -0
  38. package/dist/session/events.d.ts +19 -2
  39. package/dist/session/input.d.ts +4 -0
  40. package/dist/session/lifecycle.d.ts +12 -0
  41. package/dist/session/lifecycle.js +126 -0
  42. package/dist/session/lifecycle.js.map +1 -0
  43. package/dist/session/mapping.js +2 -1
  44. package/dist/session/mapping.js.map +1 -1
  45. package/dist/session/overlay-anchor.js +151 -0
  46. package/dist/session/overlay-anchor.js.map +1 -0
  47. package/dist/session/overlay.js +141 -0
  48. package/dist/session/overlay.js.map +1 -0
  49. package/dist/session/run.js +0 -1
  50. package/dist/session/run.js.map +1 -1
  51. package/dist/session/runtime-input.d.ts +1 -0
  52. package/dist/session/runtime-input.js +89 -0
  53. package/dist/session/runtime-input.js.map +1 -0
  54. package/dist/session/session.js +166 -129
  55. package/dist/session/session.js.map +1 -1
  56. package/dist/session/snapshot.d.ts +1 -0
  57. package/dist/session/snapshot.js +31 -5
  58. package/dist/session/snapshot.js.map +1 -1
  59. package/package.json +6 -1
  60. package/dist/hooks.d.ts +0 -32
@@ -1,13 +1,19 @@
1
+ import { runWithAgentPluginScope } from "../plugins/scope.js";
1
2
  import { runAgentLoop } from "../agent-loop.js";
2
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";
3
7
  import { BufferedAgentRun } from "./run.js";
4
8
  import { decodeStoredSessionSnapshot, encodeSessionSnapshot } from "./snapshot.js";
5
9
  //#region src/session/session.ts
6
10
  var AgentSession = class {
7
- #hooks;
8
11
  #inputQueue = [];
12
+ #internalLlm;
9
13
  #llm;
14
+ #onPluginError;
10
15
  #persistence;
16
+ #plugins;
11
17
  #activeAbort;
12
18
  #activeRun;
13
19
  #activeRuntimeInput;
@@ -15,22 +21,23 @@ var AgentSession = class {
15
21
  #killed = false;
16
22
  #loadPromise;
17
23
  #loaded = false;
24
+ #pluginState = {};
25
+ #compactions = [];
26
+ #overlays = new SessionOverlayState();
18
27
  #running = false;
19
- #runToCloseOnKill;
20
28
  #storeVersion;
21
- constructor(llm, persistence, hooks) {
22
- this.#hooks = hooks;
23
- this.#llm = llm;
29
+ constructor(llm, persistence, plugins, internalLlm = llm, onPluginError) {
30
+ this.#internalLlm = internalLlm;
31
+ this.#onPluginError = onPluginError;
24
32
  this.#persistence = persistence;
33
+ this.#plugins = plugins;
34
+ this.#llm = llm;
25
35
  }
26
36
  async send(input) {
27
37
  if (this.#killed) throw sessionKilledError();
28
38
  await this.#ensureLoaded();
29
39
  if (this.#killed) throw sessionKilledError();
30
- const runtimeInput = {
31
- pending: Promise.resolve(),
32
- queue: []
33
- };
40
+ const runtimeInput = createRuntimeInputState();
34
41
  const acceptedInput = normalizeAgentInput(input);
35
42
  const run = new BufferedAgentRun();
36
43
  run.emit(acceptedInput);
@@ -53,7 +60,33 @@ var AgentSession = class {
53
60
  const runtimeInput = this.#activeRuntimeInput;
54
61
  const run = this.#activeRun;
55
62
  if (!(runtimeInput && run)) return this.send(input);
56
- await this.#addSteeringInput(runtimeInput, 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();
57
90
  return run;
58
91
  }
59
92
  interrupt() {
@@ -62,23 +95,17 @@ var AgentSession = class {
62
95
  kill() {
63
96
  if (this.#killed) return;
64
97
  this.#killed = true;
65
- const killedError = sessionKilledError();
98
+ this.#expireActiveOverlays("kill");
66
99
  this.#activeAbort?.abort();
67
- this.#closeRuntimeInput(this.#activeRuntimeInput, killedError.message);
68
- const runToClose = this.#runToCloseOnKill ?? this.#activeRun;
69
- runToClose?.emit({
70
- type: "turn-error",
71
- message: killedError.message
72
- });
73
- runToClose?.close(void 0, killedError.message);
100
+ closeRuntimeInput(this.#activeRuntimeInput, sessionKilledError().message);
74
101
  while (this.#inputQueue.length > 0) {
75
102
  const item = this.#inputQueue.shift();
76
- this.#closeRuntimeInput(item?.runtimeInput, killedError.message);
103
+ closeRuntimeInput(item?.runtimeInput, sessionKilledError().message);
77
104
  item?.run.emit({
78
105
  type: "turn-error",
79
- message: killedError.message
106
+ message: sessionKilledError().message
80
107
  });
81
- item?.run.close(void 0, killedError.message);
108
+ item?.run.close(void 0, sessionKilledError().message);
82
109
  }
83
110
  }
84
111
  async #ensureLoaded() {
@@ -99,7 +126,10 @@ var AgentSession = class {
99
126
  async #replaceWithStoredSession() {
100
127
  const stored = await this.#persistence.store.load(this.#persistence.key);
101
128
  this.#storeVersion = stored?.version;
102
- this.#history = new ModelMessageHistory(decodeStoredSessionSnapshot(stored));
129
+ const snapshot = decodeStoredSessionSnapshot(stored);
130
+ this.#history = new ModelMessageHistory(snapshot.history);
131
+ this.#pluginState = structuredClone(snapshot.pluginState);
132
+ this.#compactions = structuredClone(snapshot.compactions);
103
133
  }
104
134
  async #drainInputQueue() {
105
135
  if (this.#running) return;
@@ -116,15 +146,15 @@ var AgentSession = class {
116
146
  async #processQueuedInput({ input, run, runtimeInput }) {
117
147
  const activeAbort = new AbortController();
118
148
  this.#activeAbort = activeAbort;
149
+ const historySnapshot = this.#history.modelSnapshot();
150
+ this.#overlays.startTurn(input, historySnapshot);
119
151
  this.#activeRun = run;
120
152
  this.#activeRuntimeInput = runtimeInput;
121
- this.#runToCloseOnKill = run;
122
- const historySnapshot = this.#history.modelSnapshot();
123
153
  try {
124
154
  await this.#withSteeringPlacement(runtimeInput, "turn-start", async () => {
125
- await this.#hooks?.beforeTurn?.({
126
- history: this.#history.modelSnapshot(),
155
+ await runPluginBeforeTurnHandlers(this.#pluginLifecycle(), {
127
156
  input,
157
+ runtimeInput,
128
158
  signal: activeAbort.signal
129
159
  });
130
160
  });
@@ -140,28 +170,36 @@ var AgentSession = class {
140
170
  await this.#withRuntimeInputWindow(runtimeInput, event.type, async () => {
141
171
  await run.emitBoundary(event);
142
172
  });
173
+ const overlayInputAdded = event.type === "step-end" && this.#overlays.consumeStepEndOverlayInputAdded();
143
174
  const runtimeInputAdded = await this.#drainRuntimeInput(run, runtimeInput, event.type);
144
- if (event.type === "step-end") return { runtimeInputAdded };
175
+ if (event.type === "step-end") return {
176
+ overlayInputAdded,
177
+ runtimeInputAdded
178
+ };
145
179
  return;
146
180
  }
147
181
  run.emit(event);
148
182
  },
149
183
  history: this.#history,
150
- hooks: this.#hooksForRuntimeInput(runtimeInput),
151
- llm: this.#llm,
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),
152
190
  signal: activeAbort.signal
153
191
  });
154
192
  await this.#commitHistory();
155
193
  const terminalEvent = result === "aborted" ? "turn-abort" : "turn-end";
156
- this.#closeRuntimeInput(runtimeInput, terminalEvent);
194
+ closeRuntimeInput(runtimeInput, terminalEvent);
195
+ this.#expireActiveOverlays(terminalEvent);
157
196
  this.#activeRuntimeInput = void 0;
158
197
  this.#activeRun = void 0;
159
- await runAfterTurnHook(this.#hooks, {
160
- history: this.#history.modelSnapshot(),
198
+ if (await runPluginAfterTurnHandlers(this.#pluginLifecycle(), {
161
199
  input,
162
200
  result,
163
201
  signal: activeAbort.signal
164
- });
202
+ })) await this.#commitHistory();
165
203
  run.emit({ type: terminalEvent });
166
204
  } catch (error) {
167
205
  if (error instanceof SessionCommitConflictError) {
@@ -169,7 +207,8 @@ var AgentSession = class {
169
207
  type: "turn-error",
170
208
  message: error.message
171
209
  });
172
- this.#closeRuntimeInput(runtimeInput, "a session commit conflict");
210
+ closeRuntimeInput(runtimeInput, "a session commit conflict");
211
+ this.#expireActiveOverlays("turn-error");
173
212
  this.#activeAbort = void 0;
174
213
  return;
175
214
  }
@@ -181,7 +220,8 @@ var AgentSession = class {
181
220
  type: "turn-error",
182
221
  message: `${errorMessage(error)}; history rollback persistence failed: ${errorMessage(rollbackError)}`
183
222
  });
184
- this.#closeRuntimeInput(runtimeInput, "turn-error");
223
+ closeRuntimeInput(runtimeInput, "turn-error");
224
+ this.#expireActiveOverlays("turn-error");
185
225
  this.#activeAbort = void 0;
186
226
  return;
187
227
  }
@@ -189,41 +229,94 @@ var AgentSession = class {
189
229
  type: "turn-error",
190
230
  message: errorMessage(error)
191
231
  });
192
- this.#closeRuntimeInput(runtimeInput, "turn-error");
232
+ closeRuntimeInput(runtimeInput, "turn-error");
233
+ this.#expireActiveOverlays("turn-error");
193
234
  } finally {
194
- this.#closeRuntimeInput(runtimeInput);
235
+ closeRuntimeInput(runtimeInput);
195
236
  this.#activeAbort = void 0;
196
237
  this.#activeRun = void 0;
197
238
  this.#activeRuntimeInput = void 0;
198
- this.#runToCloseOnKill = void 0;
239
+ this.#overlays.resetActiveTurn();
199
240
  run.close(void 0, runtimeInput.closedReason);
200
241
  }
201
242
  }
202
- #addSteeringInput(runtimeInput, input) {
203
- const next = runtimeInput.pending.then(() => {
204
- if (runtimeInput.closedReason) throw runtimeInputClosedError(runtimeInput.closedReason);
205
- runtimeInput.queue.push({
206
- input: normalizeAgentInput(input),
207
- placement: runtimeInput.steerPlacement ?? runtimeInput.placement ?? "step-end"
208
- });
209
- });
210
- runtimeInput.pending = next.catch(() => void 0);
211
- return next;
212
- }
213
- #closeRuntimeInput(runtimeInput, reason = "the run reached a terminal state") {
214
- if (!runtimeInput?.closedReason && runtimeInput) {
215
- runtimeInput.closedReason = reason;
216
- runtimeInput.placement = void 0;
217
- }
218
- }
219
243
  async #commitHistory() {
220
- const result = await this.#persistence.store.commit(this.#persistence.key, { state: encodeSessionSnapshot(this.#history.modelSnapshot()) }, { expectedVersion: this.#storeVersion ?? null });
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 });
221
249
  if (!result.ok) {
222
250
  await this.#replaceWithStoredSession();
223
251
  throw new SessionCommitConflictError(this.#persistence.key);
224
252
  }
225
253
  this.#storeVersion = result.version;
226
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
+ }
227
320
  async #withRuntimeInputWindow(runtimeInput, placement, callback) {
228
321
  const previousSteerPlacement = runtimeInput.steerPlacement;
229
322
  runtimeInput.placement = placement;
@@ -244,19 +337,6 @@ var AgentSession = class {
244
337
  runtimeInput.steerPlacement = previousSteerPlacement;
245
338
  }
246
339
  }
247
- #hooksForRuntimeInput(runtimeInput) {
248
- const hooks = this.#hooks;
249
- if (!hooks) return;
250
- return {
251
- ...hooks,
252
- afterStep: (context) => this.#withSteeringPlacement(runtimeInput, "step-end", async () => {
253
- await hooks.afterStep?.(context);
254
- }),
255
- beforeStep: (context) => this.#withSteeringPlacement(runtimeInput, "step-start", async () => {
256
- await hooks.beforeStep?.(context);
257
- })
258
- };
259
- }
260
340
  async #drainRuntimeInput(run, runtimeInput, placement) {
261
341
  let added = false;
262
342
  let next = shiftRuntimeInput(runtimeInput, placement);
@@ -273,74 +353,31 @@ var AgentSession = class {
273
353
  }
274
354
  return added;
275
355
  }
276
- };
277
- function shiftRuntimeInput(runtimeInput, placement) {
278
- const index = runtimeInput.queue.findIndex((input) => input.placement === placement);
279
- if (index === -1) return;
280
- return runtimeInput.queue.splice(index, 1)[0];
281
- }
282
- async function runAfterTurnHook(hooks, context) {
283
- const hook = hooks?.afterTurn;
284
- if (!hook) return;
285
- await Promise.allSettled([Promise.resolve().then(() => hook(context))]);
286
- }
287
- function normalizeAgentInput(input) {
288
- if (typeof input === "string") return {
289
- type: "user-text",
290
- text: input
291
- };
292
- if (isStringArrayInput(input)) return {
293
- type: "user-text",
294
- text: structuredClone(input)
295
- };
296
- if (isArrayInput(input)) {
297
- assertUserMessageContent(input);
298
- return {
299
- type: "user-message",
300
- content: structuredClone(input)
301
- };
356
+ #expireActiveOverlays(reason) {
357
+ const event = this.#overlays.expireActiveFrame(reason);
358
+ if (!event) return;
359
+ this.#activeRun?.emit(event);
302
360
  }
303
- if (isUserMessage(input)) assertUserMessageContent(input.content);
304
- return structuredClone(input);
305
- }
306
- function isStringArrayInput(input) {
307
- return isArrayInput(input) && input.every((part) => typeof part === "string");
308
- }
309
- function isArrayInput(input) {
310
- return Array.isArray(input);
311
- }
312
- function isUserMessage(input) {
313
- return input.type === "user-message";
314
- }
315
- function assertUserMessageContent(input) {
316
- for (const part of input) if (!isUserMessageContentPart(part)) throw new TypeError("Agent input content parts must be { type: \"text\", text }, { type: \"image\", image }, or { type: \"file\", data, mediaType }.");
317
- }
318
- function isUserMessageContentPart(part) {
319
- if (part === null || typeof part !== "object" || !("type" in part)) return false;
320
- if (part.type === "text") return "text" in part && typeof part.text === "string";
321
- if (part.type === "image") return "image" in part && typeof part.image === "string" && (!("mediaType" in part) || typeof part.mediaType === "string");
322
- if (part.type === "file") return "data" in part && isUserMessageFileData(part.data) && "mediaType" in part && typeof part.mediaType === "string" && (!("filename" in part) || typeof part.filename === "string");
323
- return false;
324
- }
325
- function isUserMessageFileData(data) {
326
- if (typeof data === "string") return true;
327
- if (data === null || typeof data !== "object" || !("type" in data)) return false;
328
- if (data.type === "data") return "data" in data && typeof data.data === "string";
329
- if (data.type === "reference") return "reference" in data && data.reference !== null && typeof data.reference === "object" && Object.values(data.reference).every((value) => typeof value === "string");
330
- if (data.type === "text") return "text" in data && typeof data.text === "string";
331
- if (data.type === "url") return "url" in data && typeof data.url === "string";
332
- return false;
333
- }
361
+ };
334
362
  function errorMessage(error) {
335
363
  if (error instanceof Error) return error.message;
336
364
  return String(error);
337
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
+ }
338
378
  function sessionKilledError() {
339
379
  return /* @__PURE__ */ new Error("Session killed");
340
380
  }
341
- function runtimeInputClosedError(reason) {
342
- return /* @__PURE__ */ new Error(`session.steer() cannot be used after ${reason}`);
343
- }
344
381
  var SessionCommitConflictError = class extends Error {
345
382
  constructor(key) {
346
383
  super(`Session ${JSON.stringify(key)} commit conflict`);
@@ -1 +1 @@
1
- {"version":3,"file":"session.js","names":["#hooks","#inputQueue","#llm","#persistence","#killed","#ensureLoaded","#drainInputQueue","#activeRuntimeInput","#activeRun","#addSteeringInput","#activeAbort","#closeRuntimeInput","#runToCloseOnKill","#loaded","#loadPromise","#loadSessionState","#replaceWithStoredSession","#storeVersion","#history","#running","#processQueuedInput","#withSteeringPlacement","#withRuntimeInputWindow","#commitHistory","#drainRuntimeInput","#hooksForRuntimeInput"],"sources":["../../src/session/session.ts"],"sourcesContent":["import { runAgentLoop } from \"../agent-loop\";\nimport type { AgentHooks } from \"../hooks\";\nimport type { Llm } from \"../llm\";\nimport type {\n RuntimeInput,\n UserMessage,\n UserMessageContentPart,\n} from \"./events\";\nimport { ModelMessageHistory } from \"./history\";\nimport type { AgentInput, UserInput } from \"./input\";\nimport type { AgentRun } from \"./run\";\nimport { BufferedAgentRun } from \"./run\";\nimport { decodeStoredSessionSnapshot, encodeSessionSnapshot } 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\ntype RuntimeInputPlacement = RuntimeInput[\"placement\"];\nconst noBoundaryDecision = undefined;\n\ninterface QueuedRuntimeInput {\n readonly input: UserInput;\n readonly placement: RuntimeInputPlacement;\n}\n\ninterface RuntimeInputState {\n closedReason?: string;\n pending: Promise<void>;\n placement?: RuntimeInputPlacement;\n readonly queue: QueuedRuntimeInput[];\n steerPlacement?: RuntimeInputPlacement;\n}\n\nexport class AgentSession {\n readonly #hooks?: AgentHooks;\n readonly #inputQueue: QueuedInput[] = [];\n readonly #llm: Llm;\n readonly #persistence: SessionPersistenceOptions;\n #activeAbort?: AbortController;\n #activeRun?: BufferedAgentRun;\n #activeRuntimeInput?: RuntimeInputState;\n #history = new ModelMessageHistory();\n #killed = false;\n #loadPromise?: Promise<void>;\n #loaded = false;\n #running = false;\n #runToCloseOnKill?: BufferedAgentRun;\n #storeVersion: string | undefined;\n\n constructor(\n llm: Llm,\n persistence: SessionPersistenceOptions,\n hooks?: AgentHooks\n ) {\n this.#hooks = hooks;\n this.#llm = llm;\n this.#persistence = persistence;\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: RuntimeInputState = {\n pending: Promise.resolve(),\n queue: [],\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) {\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 this.#addSteeringInput(runtimeInput, input);\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 const killedError = sessionKilledError();\n this.#activeAbort?.abort();\n this.#closeRuntimeInput(this.#activeRuntimeInput, killedError.message);\n const runToClose = this.#runToCloseOnKill ?? this.#activeRun;\n runToClose?.emit({\n type: \"turn-error\",\n message: killedError.message,\n });\n runToClose?.close(undefined, killedError.message);\n\n while (this.#inputQueue.length > 0) {\n const item = this.#inputQueue.shift();\n this.#closeRuntimeInput(item?.runtimeInput, killedError.message);\n item?.run.emit({\n type: \"turn-error\",\n message: killedError.message,\n });\n item?.run.close(undefined, killedError.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 this.#history = new ModelMessageHistory(\n decodeStoredSessionSnapshot(stored)\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.#history.modelSnapshot();\n\n try {\n await this.#withSteeringPlacement(\n runtimeInput,\n \"turn-start\",\n async () => {\n await this.#hooks?.beforeTurn?.({\n history: this.#history.modelSnapshot(),\n input,\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 runtimeInputAdded = await this.#drainRuntimeInput(\n run,\n runtimeInput,\n event.type\n );\n\n if (event.type === \"step-end\") {\n return { runtimeInputAdded };\n }\n return noBoundaryDecision;\n }\n\n run.emit(event);\n },\n history: this.#history,\n hooks: this.#hooksForRuntimeInput(runtimeInput),\n llm: this.#llm,\n signal: activeAbort.signal,\n });\n\n await this.#commitHistory();\n const terminalEvent = result === \"aborted\" ? \"turn-abort\" : \"turn-end\";\n this.#closeRuntimeInput(runtimeInput, terminalEvent);\n this.#activeRuntimeInput = undefined;\n this.#activeRun = undefined;\n await runAfterTurnHook(this.#hooks, {\n history: this.#history.modelSnapshot(),\n input,\n result,\n signal: activeAbort.signal,\n });\n run.emit({ type: terminalEvent });\n } catch (error) {\n if (error instanceof SessionCommitConflictError) {\n run.emit({ type: \"turn-error\", message: error.message });\n this.#closeRuntimeInput(runtimeInput, \"a session commit conflict\");\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 this.#closeRuntimeInput(runtimeInput, \"turn-error\");\n this.#activeAbort = undefined;\n return;\n }\n run.emit({ type: \"turn-error\", message: errorMessage(error) });\n this.#closeRuntimeInput(runtimeInput, \"turn-error\");\n } finally {\n this.#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 #addSteeringInput(\n runtimeInput: RuntimeInputState,\n input: AgentInput\n ): Promise<void> {\n const next = runtimeInput.pending.then(() => {\n if (runtimeInput.closedReason) {\n throw runtimeInputClosedError(runtimeInput.closedReason);\n }\n\n runtimeInput.queue.push({\n input: normalizeAgentInput(input),\n placement:\n runtimeInput.steerPlacement ?? runtimeInput.placement ?? \"step-end\",\n });\n });\n runtimeInput.pending = next.catch(() => undefined);\n return next;\n }\n\n #closeRuntimeInput(\n runtimeInput: RuntimeInputState | undefined,\n reason = \"the run reached a terminal state\"\n ): void {\n if (!runtimeInput?.closedReason && runtimeInput) {\n runtimeInput.closedReason = reason;\n runtimeInput.placement = undefined;\n }\n }\n\n async #commitHistory(): Promise<void> {\n const result = await this.#persistence.store.commit(\n this.#persistence.key,\n {\n state: encodeSessionSnapshot(this.#history.modelSnapshot()),\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 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 #hooksForRuntimeInput(\n runtimeInput: RuntimeInputState\n ): AgentHooks | undefined {\n const hooks = this.#hooks;\n if (!hooks) {\n return;\n }\n\n return {\n ...hooks,\n afterStep: (context) =>\n this.#withSteeringPlacement(runtimeInput, \"step-end\", async () => {\n await hooks.afterStep?.(context);\n }),\n beforeStep: (context) =>\n this.#withSteeringPlacement(runtimeInput, \"step-start\", async () => {\n await hooks.beforeStep?.(context);\n }),\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\nfunction shiftRuntimeInput(\n runtimeInput: RuntimeInputState,\n placement: RuntimeInputPlacement\n): QueuedRuntimeInput | undefined {\n const index = runtimeInput.queue.findIndex(\n (input) => input.placement === placement\n );\n if (index === -1) {\n return;\n }\n\n return runtimeInput.queue.splice(index, 1)[0];\n}\n\nasync function runAfterTurnHook(\n hooks: AgentHooks | undefined,\n context: Parameters<NonNullable<AgentHooks[\"afterTurn\"]>>[0]\n): Promise<void> {\n const hook = hooks?.afterTurn;\n if (!hook) {\n return;\n }\n\n await Promise.allSettled([Promise.resolve().then(() => hook(context))]);\n}\n\nexport function normalizeAgentInput(input: AgentInput): UserInput {\n if (typeof input === \"string\") {\n return {\n type: \"user-text\",\n text: input,\n };\n }\n\n if (isStringArrayInput(input)) {\n return {\n type: \"user-text\",\n text: structuredClone(input) as readonly string[],\n };\n }\n\n if (isArrayInput(input)) {\n assertUserMessageContent(input);\n return {\n type: \"user-message\",\n content: structuredClone(input) as readonly UserMessageContentPart[],\n };\n }\n\n if (isUserMessage(input)) {\n assertUserMessageContent(input.content);\n }\n\n return structuredClone(input);\n}\n\nfunction isStringArrayInput(input: AgentInput): input is readonly string[] {\n return isArrayInput(input) && input.every((part) => typeof part === \"string\");\n}\n\nfunction isArrayInput(\n input: AgentInput\n): input is readonly string[] | readonly UserMessageContentPart[] {\n return Array.isArray(input);\n}\n\nfunction isUserMessage(input: UserInput): input is UserMessage {\n return input.type === \"user-message\";\n}\n\nfunction assertUserMessageContent(\n input: readonly unknown[]\n): asserts input is readonly UserMessageContentPart[] {\n for (const part of input) {\n if (!isUserMessageContentPart(part)) {\n throw new TypeError(\n 'Agent input content parts must be { type: \"text\", text }, { type: \"image\", image }, or { type: \"file\", data, mediaType }.'\n );\n }\n }\n}\n\nfunction isUserMessageContentPart(\n part: unknown\n): part is UserMessageContentPart {\n if (part === null || typeof part !== \"object\" || !(\"type\" in part)) {\n return false;\n }\n\n if (part.type === \"text\") {\n return \"text\" in part && typeof part.text === \"string\";\n }\n\n if (part.type === \"image\") {\n return (\n \"image\" in part &&\n typeof part.image === \"string\" &&\n (!(\"mediaType\" in part) || typeof part.mediaType === \"string\")\n );\n }\n\n if (part.type === \"file\") {\n return (\n \"data\" in part &&\n isUserMessageFileData(part.data) &&\n \"mediaType\" in part &&\n typeof part.mediaType === \"string\" &&\n (!(\"filename\" in part) || typeof part.filename === \"string\")\n );\n }\n\n return false;\n}\n\nfunction isUserMessageFileData(data: unknown): boolean {\n if (typeof data === \"string\") {\n return true;\n }\n\n if (data === null || typeof data !== \"object\" || !(\"type\" in data)) {\n return false;\n }\n\n if (data.type === \"data\") {\n return \"data\" in data && typeof data.data === \"string\";\n }\n\n if (data.type === \"reference\") {\n return (\n \"reference\" in data &&\n data.reference !== null &&\n typeof data.reference === \"object\" &&\n Object.values(data.reference).every((value) => typeof value === \"string\")\n );\n }\n\n if (data.type === \"text\") {\n return \"text\" in data && typeof data.text === \"string\";\n }\n\n if (data.type === \"url\") {\n return \"url\" in data && typeof data.url === \"string\";\n }\n\n return false;\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 sessionKilledError(): Error {\n return new Error(\"Session killed\");\n}\n\nfunction runtimeInputClosedError(reason: string): Error {\n return new Error(`session.steer() cannot be used after ${reason}`);\n}\n\nclass SessionCommitConflictError extends Error {\n constructor(key: string) {\n super(`Session ${JSON.stringify(key)} commit conflict`);\n }\n}\n"],"mappings":";;;;;AA6CA,IAAa,eAAb,MAA0B;CACxB;CACA,cAAsC,CAAC;CACvC;CACA;CACA;CACA;CACA;CACA,WAAW,IAAI,oBAAoB;CACnC,UAAU;CACV;CACA,UAAU;CACV,WAAW;CACX;CACA;CAEA,YACE,KACA,aACA,OACA;EACA,KAAKA,SAAS;EACd,KAAKE,OAAO;EACZ,KAAKC,eAAe;CACtB;CAEA,MAAM,KAAK,OAAsC;EAC/C,IAAI,KAAKC,SACP,MAAM,mBAAmB;EAG3B,MAAM,KAAKC,cAAc;EAEzB,IAAI,KAAKD,SACP,MAAM,mBAAmB;EAG3B,MAAM,eAAkC;GACtC,SAAS,QAAQ,QAAQ;GACzB,OAAO,CAAC;EACV;EACA,MAAM,gBAAgB,oBAAoB,KAAK;EAC/C,MAAM,MAAM,IAAI,iBAAiB;EACjC,IAAI,KAAK,aAAa;EACtB,KAAKH,YAAY,KAAK;GACpB,OAAO,gBAAgB,aAAa;GACpC;GACA;EACF,CAAC;EACD,KAAKK,iBAAiB,EAAE,OAAO,UAAmB;GAChD,IAAI,KAAK;IAAE,MAAM;IAAc,SAAS,aAAa,KAAK;GAAE,CAAC;GAC7D,IAAI,MAAM;EACZ,CAAC;EACD,OAAO;CACT;CAEA,MAAM,MAAM,OAAsC;EAChD,IAAI,KAAKF,SACP,MAAM,mBAAmB;EAG3B,MAAM,eAAe,KAAKG;EAC1B,MAAM,MAAM,KAAKC;EACjB,IAAI,EAAE,gBAAgB,MACpB,OAAO,KAAK,KAAK,KAAK;EAGxB,MAAM,KAAKC,kBAAkB,cAAc,KAAK;EAChD,OAAO;CACT;CAEA,YAAkB;EAChB,KAAKC,cAAc,MAAM;CAC3B;CAEA,OAAa;EACX,IAAI,KAAKN,SACP;EAGF,KAAKA,UAAU;EACf,MAAM,cAAc,mBAAmB;EACvC,KAAKM,cAAc,MAAM;EACzB,KAAKC,mBAAmB,KAAKJ,qBAAqB,YAAY,OAAO;EACrE,MAAM,aAAa,KAAKK,qBAAqB,KAAKJ;EAClD,YAAY,KAAK;GACf,MAAM;GACN,SAAS,YAAY;EACvB,CAAC;EACD,YAAY,MAAM,KAAA,GAAW,YAAY,OAAO;EAEhD,OAAO,KAAKP,YAAY,SAAS,GAAG;GAClC,MAAM,OAAO,KAAKA,YAAY,MAAM;GACpC,KAAKU,mBAAmB,MAAM,cAAc,YAAY,OAAO;GAC/D,MAAM,IAAI,KAAK;IACb,MAAM;IACN,SAAS,YAAY;GACvB,CAAC;GACD,MAAM,IAAI,MAAM,KAAA,GAAW,YAAY,OAAO;EAChD;CACF;CAEA,MAAMN,gBAA+B;EACnC,IAAI,KAAKQ,SACP;EAGF,KAAKC,iBAAiB,KAAKC,kBAAkB;EAC7C,IAAI;GACF,MAAM,KAAKD;EACb,SAAS,OAAO;GACd,KAAKA,eAAe,KAAA;GACpB,MAAM;EACR;CACF;CAEA,MAAMC,oBAAmC;EACvC,IAAI,KAAKF,SACP;EAGF,MAAM,KAAKG,0BAA0B;EACrC,KAAKH,UAAU;CACjB;CAEA,MAAMG,4BAA2C;EAC/C,MAAM,SAAS,MAAM,KAAKb,aAAa,MAAM,KAAK,KAAKA,aAAa,GAAG;EACvE,KAAKc,gBAAgB,QAAQ;EAC7B,KAAKC,WAAW,IAAI,oBAClB,4BAA4B,MAAM,CACpC;CACF;CAEA,MAAMZ,mBAAkC;EACtC,IAAI,KAAKa,UACP;EAGF,KAAKA,WAAW;EAChB,IAAI;GACF,OAAO,CAAC,KAAKf,WAAW,KAAKH,YAAY,SAAS,GAAG;IACnD,MAAM,OAAO,KAAKA,YAAY,MAAM;IACpC,IAAI,MACF,MAAM,KAAKmB,oBAAoB,IAAI;GAEvC;EACF,UAAU;GACR,KAAKD,WAAW;EAClB;CACF;CAEA,MAAMC,oBAAoB,EACxB,OACA,KACA,gBAC6B;EAC7B,MAAM,cAAc,IAAI,gBAAgB;EACxC,KAAKV,eAAe;EACpB,KAAKF,aAAa;EAClB,KAAKD,sBAAsB;EAC3B,KAAKK,oBAAoB;EACzB,MAAM,kBAAkB,KAAKM,SAAS,cAAc;EAEpD,IAAI;GACF,MAAM,KAAKG,uBACT,cACA,cACA,YAAY;IACV,MAAM,KAAKrB,QAAQ,aAAa;KAC9B,SAAS,KAAKkB,SAAS,cAAc;KACrC;KACA,QAAQ,YAAY;IACtB,CAAC;GACH,CACF;GACA,MAAM,KAAKI,wBACT,cACA,cACA,YAAY;IACV,MAAM,IAAI,aAAa,EAAE,MAAM,aAAa,CAAC;GAC/C,CACF;GACA,KAAKJ,SAAS,gBAAgB,KAAK;GACnC,MAAM,KAAKK,eAAe;GAC1B,MAAM,KAAKC,mBAAmB,KAAK,cAAc,YAAY;GAE7D,MAAM,SAAS,MAAM,aAAa;IAChC,MAAM,OAAO,UAAU;KACrB,IAAI,MAAM,SAAS,gBAAgB,MAAM,SAAS,YAAY;MAC5D,MAAM,KAAKF,wBACT,cACA,MAAM,MACN,YAAY;OACV,MAAM,IAAI,aAAa,KAAK;MAC9B,CACF;MACA,MAAM,oBAAoB,MAAM,KAAKE,mBACnC,KACA,cACA,MAAM,IACR;MAEA,IAAI,MAAM,SAAS,YACjB,OAAO,EAAE,kBAAkB;MAE7B;KACF;KAEA,IAAI,KAAK,KAAK;IAChB;IACA,SAAS,KAAKN;IACd,OAAO,KAAKO,sBAAsB,YAAY;IAC9C,KAAK,KAAKvB;IACV,QAAQ,YAAY;GACtB,CAAC;GAED,MAAM,KAAKqB,eAAe;GAC1B,MAAM,gBAAgB,WAAW,YAAY,eAAe;GAC5D,KAAKZ,mBAAmB,cAAc,aAAa;GACnD,KAAKJ,sBAAsB,KAAA;GAC3B,KAAKC,aAAa,KAAA;GAClB,MAAM,iBAAiB,KAAKR,QAAQ;IAClC,SAAS,KAAKkB,SAAS,cAAc;IACrC;IACA;IACA,QAAQ,YAAY;GACtB,CAAC;GACD,IAAI,KAAK,EAAE,MAAM,cAAc,CAAC;EAClC,SAAS,OAAO;GACd,IAAI,iBAAiB,4BAA4B;IAC/C,IAAI,KAAK;KAAE,MAAM;KAAc,SAAS,MAAM;IAAQ,CAAC;IACvD,KAAKP,mBAAmB,cAAc,2BAA2B;IACjE,KAAKD,eAAe,KAAA;IACpB;GACF;GAEA,KAAKQ,SAAS,SAAS,eAAe;GACtC,IAAI;IACF,MAAM,KAAKK,eAAe;GAC5B,SAAS,eAAe;IACtB,IAAI,KAAK;KACP,MAAM;KACN,SAAS,GAAG,aAAa,KAAK,EAAE,yCAAyC,aACvE,aACF;IACF,CAAC;IACD,KAAKZ,mBAAmB,cAAc,YAAY;IAClD,KAAKD,eAAe,KAAA;IACpB;GACF;GACA,IAAI,KAAK;IAAE,MAAM;IAAc,SAAS,aAAa,KAAK;GAAE,CAAC;GAC7D,KAAKC,mBAAmB,cAAc,YAAY;EACpD,UAAU;GACR,KAAKA,mBAAmB,YAAY;GACpC,KAAKD,eAAe,KAAA;GACpB,KAAKF,aAAa,KAAA;GAClB,KAAKD,sBAAsB,KAAA;GAC3B,KAAKK,oBAAoB,KAAA;GACzB,IAAI,MAAM,KAAA,GAAW,aAAa,YAAY;EAChD;CACF;CAEA,kBACE,cACA,OACe;EACf,MAAM,OAAO,aAAa,QAAQ,WAAW;GAC3C,IAAI,aAAa,cACf,MAAM,wBAAwB,aAAa,YAAY;GAGzD,aAAa,MAAM,KAAK;IACtB,OAAO,oBAAoB,KAAK;IAChC,WACE,aAAa,kBAAkB,aAAa,aAAa;GAC7D,CAAC;EACH,CAAC;EACD,aAAa,UAAU,KAAK,YAAY,KAAA,CAAS;EACjD,OAAO;CACT;CAEA,mBACE,cACA,SAAS,oCACH;EACN,IAAI,CAAC,cAAc,gBAAgB,cAAc;GAC/C,aAAa,eAAe;GAC5B,aAAa,YAAY,KAAA;EAC3B;CACF;CAEA,MAAMW,iBAAgC;EACpC,MAAM,SAAS,MAAM,KAAKpB,aAAa,MAAM,OAC3C,KAAKA,aAAa,KAClB,EACE,OAAO,sBAAsB,KAAKe,SAAS,cAAc,CAAC,EAC5D,GACA,EAAE,iBAAiB,KAAKD,iBAAiB,KAAK,CAChD;EAEA,IAAI,CAAC,OAAO,IAAI;GACd,MAAM,KAAKD,0BAA0B;GACrC,MAAM,IAAI,2BAA2B,KAAKb,aAAa,GAAG;EAC5D;EAEA,KAAKc,gBAAgB,OAAO;CAC9B;CAEA,MAAMK,wBACJ,cACA,WACA,UACY;EACZ,MAAM,yBAAyB,aAAa;EAC5C,aAAa,YAAY;EACzB,aAAa,iBAAiB;EAC9B,IAAI;GACF,OAAO,MAAM,SAAS;EACxB,UAAU;GACR,aAAa,YAAY,KAAA;GACzB,aAAa,iBAAiB;EAChC;CACF;CAEA,MAAMD,uBACJ,cACA,WACA,UACY;EACZ,MAAM,yBAAyB,aAAa;EAC5C,aAAa,iBAAiB;EAC9B,IAAI;GACF,OAAO,MAAM,SAAS;EACxB,UAAU;GACR,aAAa,iBAAiB;EAChC;CACF;CAEA,sBACE,cACwB;EACxB,MAAM,QAAQ,KAAKrB;EACnB,IAAI,CAAC,OACH;EAGF,OAAO;GACL,GAAG;GACH,YAAY,YACV,KAAKqB,uBAAuB,cAAc,YAAY,YAAY;IAChE,MAAM,MAAM,YAAY,OAAO;GACjC,CAAC;GACH,aAAa,YACX,KAAKA,uBAAuB,cAAc,cAAc,YAAY;IAClE,MAAM,MAAM,aAAa,OAAO;GAClC,CAAC;EACL;CACF;CAEA,MAAMG,mBACJ,KACA,cACA,WACkB;EAClB,IAAI,QAAQ;EACZ,IAAI,OAAO,kBAAkB,cAAc,SAAS;EACpD,OAAO,MAAM;GACX,QAAQ;GACR,IAAI,KAAK;IAAE,MAAM;IAAiB,OAAO,KAAK;IAAO;GAAU,CAAC;GAChE,KAAKN,SAAS,gBAAgB,KAAK,KAAK;GACxC,MAAM,KAAKK,eAAe;GAC1B,OAAO,kBAAkB,cAAc,SAAS;EAClD;EAEA,OAAO;CACT;AACF;AAEA,SAAS,kBACP,cACA,WACgC;CAChC,MAAM,QAAQ,aAAa,MAAM,WAC9B,UAAU,MAAM,cAAc,SACjC;CACA,IAAI,UAAU,IACZ;CAGF,OAAO,aAAa,MAAM,OAAO,OAAO,CAAC,EAAE;AAC7C;AAEA,eAAe,iBACb,OACA,SACe;CACf,MAAM,OAAO,OAAO;CACpB,IAAI,CAAC,MACH;CAGF,MAAM,QAAQ,WAAW,CAAC,QAAQ,QAAQ,EAAE,WAAW,KAAK,OAAO,CAAC,CAAC,CAAC;AACxE;AAEA,SAAgB,oBAAoB,OAA8B;CAChE,IAAI,OAAO,UAAU,UACnB,OAAO;EACL,MAAM;EACN,MAAM;CACR;CAGF,IAAI,mBAAmB,KAAK,GAC1B,OAAO;EACL,MAAM;EACN,MAAM,gBAAgB,KAAK;CAC7B;CAGF,IAAI,aAAa,KAAK,GAAG;EACvB,yBAAyB,KAAK;EAC9B,OAAO;GACL,MAAM;GACN,SAAS,gBAAgB,KAAK;EAChC;CACF;CAEA,IAAI,cAAc,KAAK,GACrB,yBAAyB,MAAM,OAAO;CAGxC,OAAO,gBAAgB,KAAK;AAC9B;AAEA,SAAS,mBAAmB,OAA+C;CACzE,OAAO,aAAa,KAAK,KAAK,MAAM,OAAO,SAAS,OAAO,SAAS,QAAQ;AAC9E;AAEA,SAAS,aACP,OACgE;CAChE,OAAO,MAAM,QAAQ,KAAK;AAC5B;AAEA,SAAS,cAAc,OAAwC;CAC7D,OAAO,MAAM,SAAS;AACxB;AAEA,SAAS,yBACP,OACoD;CACpD,KAAK,MAAM,QAAQ,OACjB,IAAI,CAAC,yBAAyB,IAAI,GAChC,MAAM,IAAI,UACR,iIACF;AAGN;AAEA,SAAS,yBACP,MACgC;CAChC,IAAI,SAAS,QAAQ,OAAO,SAAS,YAAY,EAAE,UAAU,OAC3D,OAAO;CAGT,IAAI,KAAK,SAAS,QAChB,OAAO,UAAU,QAAQ,OAAO,KAAK,SAAS;CAGhD,IAAI,KAAK,SAAS,SAChB,OACE,WAAW,QACX,OAAO,KAAK,UAAU,aACrB,EAAE,eAAe,SAAS,OAAO,KAAK,cAAc;CAIzD,IAAI,KAAK,SAAS,QAChB,OACE,UAAU,QACV,sBAAsB,KAAK,IAAI,KAC/B,eAAe,QACf,OAAO,KAAK,cAAc,aACzB,EAAE,cAAc,SAAS,OAAO,KAAK,aAAa;CAIvD,OAAO;AACT;AAEA,SAAS,sBAAsB,MAAwB;CACrD,IAAI,OAAO,SAAS,UAClB,OAAO;CAGT,IAAI,SAAS,QAAQ,OAAO,SAAS,YAAY,EAAE,UAAU,OAC3D,OAAO;CAGT,IAAI,KAAK,SAAS,QAChB,OAAO,UAAU,QAAQ,OAAO,KAAK,SAAS;CAGhD,IAAI,KAAK,SAAS,aAChB,OACE,eAAe,QACf,KAAK,cAAc,QACnB,OAAO,KAAK,cAAc,YAC1B,OAAO,OAAO,KAAK,SAAS,EAAE,OAAO,UAAU,OAAO,UAAU,QAAQ;CAI5E,IAAI,KAAK,SAAS,QAChB,OAAO,UAAU,QAAQ,OAAO,KAAK,SAAS;CAGhD,IAAI,KAAK,SAAS,OAChB,OAAO,SAAS,QAAQ,OAAO,KAAK,QAAQ;CAG9C,OAAO;AACT;AAEA,SAAS,aAAa,OAAwB;CAC5C,IAAI,iBAAiB,OACnB,OAAO,MAAM;CAGf,OAAO,OAAO,KAAK;AACrB;AAEA,SAAS,qBAA4B;CACnC,uBAAO,IAAI,MAAM,gBAAgB;AACnC;AAEA,SAAS,wBAAwB,QAAuB;CACtD,uBAAO,IAAI,MAAM,wCAAwC,QAAQ;AACnE;AAEA,IAAM,6BAAN,cAAyC,MAAM;CAC7C,YAAY,KAAa;EACvB,MAAM,WAAW,KAAK,UAAU,GAAG,EAAE,iBAAiB;CACxD;AACF"}
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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"}
@@ -0,0 +1 @@
1
+ import { ModelMessage } from "ai";
@@ -1,19 +1,45 @@
1
1
  //#region src/session/snapshot.ts
2
- function encodeSessionSnapshot(history) {
2
+ function encodeSessionSnapshot(state) {
3
3
  return {
4
- schemaVersion: 1,
5
- history: structuredClone(history)
4
+ compactions: structuredClone([...state.compactions ?? []]),
5
+ history: structuredClone([...state.history]),
6
+ pluginState: structuredClone({ ...state.pluginState ?? {} }),
7
+ schemaVersion: 2
6
8
  };
7
9
  }
8
10
  function decodeStoredSessionSnapshot(stored) {
9
- if (!stored) return [];
11
+ if (!stored) return emptySnapshotState();
10
12
  const snapshot = stored.state;
11
- if (isSessionSnapshotV1(snapshot)) return structuredClone(snapshot.history);
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
+ };
12
22
  throw new Error("Unsupported stored session state");
13
23
  }
24
+ function emptySnapshotState() {
25
+ return {
26
+ compactions: [],
27
+ history: [],
28
+ pluginState: {}
29
+ };
30
+ }
14
31
  function isSessionSnapshotV1(value) {
15
32
  return value !== null && typeof value === "object" && "schemaVersion" in value && value.schemaVersion === 1 && "history" in value && Array.isArray(value.history);
16
33
  }
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
+ }
17
43
  //#endregion
18
44
  export { decodeStoredSessionSnapshot, encodeSessionSnapshot };
19
45
 
@@ -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 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"}
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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@minpeter/pss-runtime",
3
- "version": "0.0.11",
3
+ "version": "0.1.0-next.0",
4
4
  "description": "Generic agent runtime for sessions, model loops, and synchronized run events.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -11,6 +11,11 @@
11
11
  "types": "./dist/index.d.ts",
12
12
  "import": "./dist/index.js"
13
13
  },
14
+ "./plugins": {
15
+ "@minpeter/pss-source": "./src/plugins/index.ts",
16
+ "types": "./dist/plugins/index.d.ts",
17
+ "import": "./dist/plugins/index.js"
18
+ },
14
19
  "./session-store/memory": {
15
20
  "@minpeter/pss-source": "./src/session/store/memory.ts",
16
21
  "types": "./dist/session/store/memory.d.ts",