@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.
- package/README.md +191 -20
- package/dist/agent-loop.d.ts +1 -0
- package/dist/agent-loop.js +14 -8
- package/dist/agent-loop.js.map +1 -1
- package/dist/agent.d.ts +8 -10
- package/dist/agent.js +34 -13
- package/dist/agent.js.map +1 -1
- package/dist/index.d.ts +8 -4
- package/dist/index.js +6 -1
- package/dist/llm.js +7 -1
- package/dist/llm.js.map +1 -1
- package/dist/plugins/compaction.d.ts +15 -0
- package/dist/plugins/compaction.js +98 -0
- package/dist/plugins/compaction.js.map +1 -0
- package/dist/plugins/index.d.ts +5 -0
- package/dist/plugins/index.js +5 -0
- package/dist/plugins/memory.d.ts +11 -0
- package/dist/plugins/memory.js +146 -0
- package/dist/plugins/memory.js.map +1 -0
- package/dist/plugins/runner.d.ts +1 -0
- package/dist/plugins/runner.js +83 -0
- package/dist/plugins/runner.js.map +1 -0
- package/dist/plugins/scope.d.ts +1 -0
- package/dist/plugins/scope.js +13 -0
- package/dist/plugins/scope.js.map +1 -0
- package/dist/plugins/sessions.d.ts +12 -0
- package/dist/plugins/sessions.js +34 -0
- package/dist/plugins/sessions.js.map +1 -0
- package/dist/plugins/tool-hook-handlers.js +77 -0
- package/dist/plugins/tool-hook-handlers.js.map +1 -0
- package/dist/plugins/tool-hook-results.js +64 -0
- package/dist/plugins/tool-hook-results.js.map +1 -0
- package/dist/plugins/tool-hooks.js +111 -0
- package/dist/plugins/tool-hooks.js.map +1 -0
- package/dist/plugins/types.d.ts +105 -0
- package/dist/plugins/types.js +20 -0
- package/dist/plugins/types.js.map +1 -0
- package/dist/session/events.d.ts +19 -2
- package/dist/session/input.d.ts +4 -0
- package/dist/session/lifecycle.d.ts +12 -0
- package/dist/session/lifecycle.js +126 -0
- package/dist/session/lifecycle.js.map +1 -0
- package/dist/session/mapping.js +2 -1
- package/dist/session/mapping.js.map +1 -1
- package/dist/session/overlay-anchor.js +151 -0
- package/dist/session/overlay-anchor.js.map +1 -0
- package/dist/session/overlay.js +141 -0
- package/dist/session/overlay.js.map +1 -0
- package/dist/session/run.js +0 -1
- package/dist/session/run.js.map +1 -1
- package/dist/session/runtime-input.d.ts +1 -0
- package/dist/session/runtime-input.js +89 -0
- package/dist/session/runtime-input.js.map +1 -0
- package/dist/session/session.js +166 -129
- package/dist/session/session.js.map +1 -1
- package/dist/session/snapshot.d.ts +1 -0
- package/dist/session/snapshot.js +31 -5
- package/dist/session/snapshot.js.map +1 -1
- package/package.json +6 -1
- package/dist/hooks.d.ts +0 -32
package/dist/session/session.js
CHANGED
|
@@ -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,
|
|
22
|
-
this.#
|
|
23
|
-
this.#
|
|
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
|
|
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
|
-
|
|
98
|
+
this.#expireActiveOverlays("kill");
|
|
66
99
|
this.#activeAbort?.abort();
|
|
67
|
-
|
|
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
|
-
|
|
103
|
+
closeRuntimeInput(item?.runtimeInput, sessionKilledError().message);
|
|
77
104
|
item?.run.emit({
|
|
78
105
|
type: "turn-error",
|
|
79
|
-
message:
|
|
106
|
+
message: sessionKilledError().message
|
|
80
107
|
});
|
|
81
|
-
item?.run.close(void 0,
|
|
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
|
-
|
|
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.#
|
|
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 {
|
|
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
|
-
|
|
151
|
-
|
|
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
|
-
|
|
194
|
+
closeRuntimeInput(runtimeInput, terminalEvent);
|
|
195
|
+
this.#expireActiveOverlays(terminalEvent);
|
|
157
196
|
this.#activeRuntimeInput = void 0;
|
|
158
197
|
this.#activeRun = void 0;
|
|
159
|
-
await
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
232
|
+
closeRuntimeInput(runtimeInput, "turn-error");
|
|
233
|
+
this.#expireActiveOverlays("turn-error");
|
|
193
234
|
} finally {
|
|
194
|
-
|
|
235
|
+
closeRuntimeInput(runtimeInput);
|
|
195
236
|
this.#activeAbort = void 0;
|
|
196
237
|
this.#activeRun = void 0;
|
|
197
238
|
this.#activeRuntimeInput = void 0;
|
|
198
|
-
this.#
|
|
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(
|
|
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
|
-
|
|
278
|
-
|
|
279
|
-
|
|
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
|
-
|
|
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";
|
package/dist/session/snapshot.js
CHANGED
|
@@ -1,19 +1,45 @@
|
|
|
1
1
|
//#region src/session/snapshot.ts
|
|
2
|
-
function encodeSessionSnapshot(
|
|
2
|
+
function encodeSessionSnapshot(state) {
|
|
3
3
|
return {
|
|
4
|
-
|
|
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
|
|
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 =
|
|
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.
|
|
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",
|