@minpeter/pss-runtime 0.0.10 → 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/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 +164 -117
- 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,21 +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
28
|
#storeVersion;
|
|
20
|
-
constructor(llm, persistence,
|
|
21
|
-
this.#
|
|
22
|
-
this.#
|
|
29
|
+
constructor(llm, persistence, plugins, internalLlm = llm, onPluginError) {
|
|
30
|
+
this.#internalLlm = internalLlm;
|
|
31
|
+
this.#onPluginError = onPluginError;
|
|
23
32
|
this.#persistence = persistence;
|
|
33
|
+
this.#plugins = plugins;
|
|
34
|
+
this.#llm = llm;
|
|
24
35
|
}
|
|
25
36
|
async send(input) {
|
|
26
37
|
if (this.#killed) throw sessionKilledError();
|
|
27
38
|
await this.#ensureLoaded();
|
|
28
39
|
if (this.#killed) throw sessionKilledError();
|
|
29
|
-
const runtimeInput =
|
|
30
|
-
pending: Promise.resolve(),
|
|
31
|
-
queue: []
|
|
32
|
-
};
|
|
40
|
+
const runtimeInput = createRuntimeInputState();
|
|
33
41
|
const acceptedInput = normalizeAgentInput(input);
|
|
34
42
|
const run = new BufferedAgentRun();
|
|
35
43
|
run.emit(acceptedInput);
|
|
@@ -52,7 +60,33 @@ var AgentSession = class {
|
|
|
52
60
|
const runtimeInput = this.#activeRuntimeInput;
|
|
53
61
|
const run = this.#activeRun;
|
|
54
62
|
if (!(runtimeInput && run)) return this.send(input);
|
|
55
|
-
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();
|
|
56
90
|
return run;
|
|
57
91
|
}
|
|
58
92
|
interrupt() {
|
|
@@ -61,11 +95,12 @@ var AgentSession = class {
|
|
|
61
95
|
kill() {
|
|
62
96
|
if (this.#killed) return;
|
|
63
97
|
this.#killed = true;
|
|
98
|
+
this.#expireActiveOverlays("kill");
|
|
64
99
|
this.#activeAbort?.abort();
|
|
65
|
-
|
|
100
|
+
closeRuntimeInput(this.#activeRuntimeInput, sessionKilledError().message);
|
|
66
101
|
while (this.#inputQueue.length > 0) {
|
|
67
102
|
const item = this.#inputQueue.shift();
|
|
68
|
-
|
|
103
|
+
closeRuntimeInput(item?.runtimeInput, sessionKilledError().message);
|
|
69
104
|
item?.run.emit({
|
|
70
105
|
type: "turn-error",
|
|
71
106
|
message: sessionKilledError().message
|
|
@@ -91,7 +126,10 @@ var AgentSession = class {
|
|
|
91
126
|
async #replaceWithStoredSession() {
|
|
92
127
|
const stored = await this.#persistence.store.load(this.#persistence.key);
|
|
93
128
|
this.#storeVersion = stored?.version;
|
|
94
|
-
|
|
129
|
+
const snapshot = decodeStoredSessionSnapshot(stored);
|
|
130
|
+
this.#history = new ModelMessageHistory(snapshot.history);
|
|
131
|
+
this.#pluginState = structuredClone(snapshot.pluginState);
|
|
132
|
+
this.#compactions = structuredClone(snapshot.compactions);
|
|
95
133
|
}
|
|
96
134
|
async #drainInputQueue() {
|
|
97
135
|
if (this.#running) return;
|
|
@@ -108,14 +146,15 @@ var AgentSession = class {
|
|
|
108
146
|
async #processQueuedInput({ input, run, runtimeInput }) {
|
|
109
147
|
const activeAbort = new AbortController();
|
|
110
148
|
this.#activeAbort = activeAbort;
|
|
149
|
+
const historySnapshot = this.#history.modelSnapshot();
|
|
150
|
+
this.#overlays.startTurn(input, historySnapshot);
|
|
111
151
|
this.#activeRun = run;
|
|
112
152
|
this.#activeRuntimeInput = runtimeInput;
|
|
113
|
-
const historySnapshot = this.#history.modelSnapshot();
|
|
114
153
|
try {
|
|
115
154
|
await this.#withSteeringPlacement(runtimeInput, "turn-start", async () => {
|
|
116
|
-
await this.#
|
|
117
|
-
history: this.#history.modelSnapshot(),
|
|
155
|
+
await runPluginBeforeTurnHandlers(this.#pluginLifecycle(), {
|
|
118
156
|
input,
|
|
157
|
+
runtimeInput,
|
|
119
158
|
signal: activeAbort.signal
|
|
120
159
|
});
|
|
121
160
|
});
|
|
@@ -131,28 +170,36 @@ var AgentSession = class {
|
|
|
131
170
|
await this.#withRuntimeInputWindow(runtimeInput, event.type, async () => {
|
|
132
171
|
await run.emitBoundary(event);
|
|
133
172
|
});
|
|
173
|
+
const overlayInputAdded = event.type === "step-end" && this.#overlays.consumeStepEndOverlayInputAdded();
|
|
134
174
|
const runtimeInputAdded = await this.#drainRuntimeInput(run, runtimeInput, event.type);
|
|
135
|
-
if (event.type === "step-end") return {
|
|
175
|
+
if (event.type === "step-end") return {
|
|
176
|
+
overlayInputAdded,
|
|
177
|
+
runtimeInputAdded
|
|
178
|
+
};
|
|
136
179
|
return;
|
|
137
180
|
}
|
|
138
181
|
run.emit(event);
|
|
139
182
|
},
|
|
140
183
|
history: this.#history,
|
|
141
|
-
|
|
142
|
-
|
|
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),
|
|
143
190
|
signal: activeAbort.signal
|
|
144
191
|
});
|
|
145
192
|
await this.#commitHistory();
|
|
146
193
|
const terminalEvent = result === "aborted" ? "turn-abort" : "turn-end";
|
|
147
|
-
|
|
194
|
+
closeRuntimeInput(runtimeInput, terminalEvent);
|
|
195
|
+
this.#expireActiveOverlays(terminalEvent);
|
|
148
196
|
this.#activeRuntimeInput = void 0;
|
|
149
197
|
this.#activeRun = void 0;
|
|
150
|
-
await
|
|
151
|
-
history: this.#history.modelSnapshot(),
|
|
198
|
+
if (await runPluginAfterTurnHandlers(this.#pluginLifecycle(), {
|
|
152
199
|
input,
|
|
153
200
|
result,
|
|
154
201
|
signal: activeAbort.signal
|
|
155
|
-
});
|
|
202
|
+
})) await this.#commitHistory();
|
|
156
203
|
run.emit({ type: terminalEvent });
|
|
157
204
|
} catch (error) {
|
|
158
205
|
if (error instanceof SessionCommitConflictError) {
|
|
@@ -160,7 +207,8 @@ var AgentSession = class {
|
|
|
160
207
|
type: "turn-error",
|
|
161
208
|
message: error.message
|
|
162
209
|
});
|
|
163
|
-
|
|
210
|
+
closeRuntimeInput(runtimeInput, "a session commit conflict");
|
|
211
|
+
this.#expireActiveOverlays("turn-error");
|
|
164
212
|
this.#activeAbort = void 0;
|
|
165
213
|
return;
|
|
166
214
|
}
|
|
@@ -172,7 +220,8 @@ var AgentSession = class {
|
|
|
172
220
|
type: "turn-error",
|
|
173
221
|
message: `${errorMessage(error)}; history rollback persistence failed: ${errorMessage(rollbackError)}`
|
|
174
222
|
});
|
|
175
|
-
|
|
223
|
+
closeRuntimeInput(runtimeInput, "turn-error");
|
|
224
|
+
this.#expireActiveOverlays("turn-error");
|
|
176
225
|
this.#activeAbort = void 0;
|
|
177
226
|
return;
|
|
178
227
|
}
|
|
@@ -180,40 +229,94 @@ var AgentSession = class {
|
|
|
180
229
|
type: "turn-error",
|
|
181
230
|
message: errorMessage(error)
|
|
182
231
|
});
|
|
183
|
-
|
|
232
|
+
closeRuntimeInput(runtimeInput, "turn-error");
|
|
233
|
+
this.#expireActiveOverlays("turn-error");
|
|
184
234
|
} finally {
|
|
185
|
-
|
|
235
|
+
closeRuntimeInput(runtimeInput);
|
|
186
236
|
this.#activeAbort = void 0;
|
|
187
237
|
this.#activeRun = void 0;
|
|
188
238
|
this.#activeRuntimeInput = void 0;
|
|
239
|
+
this.#overlays.resetActiveTurn();
|
|
189
240
|
run.close(void 0, runtimeInput.closedReason);
|
|
190
241
|
}
|
|
191
242
|
}
|
|
192
|
-
#addSteeringInput(runtimeInput, input) {
|
|
193
|
-
const next = runtimeInput.pending.then(() => {
|
|
194
|
-
if (runtimeInput.closedReason) throw runtimeInputClosedError(runtimeInput.closedReason);
|
|
195
|
-
runtimeInput.queue.push({
|
|
196
|
-
input: normalizeAgentInput(input),
|
|
197
|
-
placement: runtimeInput.steerPlacement ?? runtimeInput.placement ?? "step-end"
|
|
198
|
-
});
|
|
199
|
-
});
|
|
200
|
-
runtimeInput.pending = next.catch(() => void 0);
|
|
201
|
-
return next;
|
|
202
|
-
}
|
|
203
|
-
#closeRuntimeInput(runtimeInput, reason = "the run reached a terminal state") {
|
|
204
|
-
if (!runtimeInput?.closedReason && runtimeInput) {
|
|
205
|
-
runtimeInput.closedReason = reason;
|
|
206
|
-
runtimeInput.placement = void 0;
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
243
|
async #commitHistory() {
|
|
210
|
-
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 });
|
|
211
249
|
if (!result.ok) {
|
|
212
250
|
await this.#replaceWithStoredSession();
|
|
213
251
|
throw new SessionCommitConflictError(this.#persistence.key);
|
|
214
252
|
}
|
|
215
253
|
this.#storeVersion = result.version;
|
|
216
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
|
+
}
|
|
217
320
|
async #withRuntimeInputWindow(runtimeInput, placement, callback) {
|
|
218
321
|
const previousSteerPlacement = runtimeInput.steerPlacement;
|
|
219
322
|
runtimeInput.placement = placement;
|
|
@@ -234,19 +337,6 @@ var AgentSession = class {
|
|
|
234
337
|
runtimeInput.steerPlacement = previousSteerPlacement;
|
|
235
338
|
}
|
|
236
339
|
}
|
|
237
|
-
#hooksForRuntimeInput(runtimeInput) {
|
|
238
|
-
const hooks = this.#hooks;
|
|
239
|
-
if (!hooks) return;
|
|
240
|
-
return {
|
|
241
|
-
...hooks,
|
|
242
|
-
afterStep: (context) => this.#withSteeringPlacement(runtimeInput, "step-end", async () => {
|
|
243
|
-
await hooks.afterStep?.(context);
|
|
244
|
-
}),
|
|
245
|
-
beforeStep: (context) => this.#withSteeringPlacement(runtimeInput, "step-start", async () => {
|
|
246
|
-
await hooks.beforeStep?.(context);
|
|
247
|
-
})
|
|
248
|
-
};
|
|
249
|
-
}
|
|
250
340
|
async #drainRuntimeInput(run, runtimeInput, placement) {
|
|
251
341
|
let added = false;
|
|
252
342
|
let next = shiftRuntimeInput(runtimeInput, placement);
|
|
@@ -263,74 +353,31 @@ var AgentSession = class {
|
|
|
263
353
|
}
|
|
264
354
|
return added;
|
|
265
355
|
}
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
return runtimeInput.queue.splice(index, 1)[0];
|
|
271
|
-
}
|
|
272
|
-
async function runAfterTurnHook(hooks, context) {
|
|
273
|
-
const hook = hooks?.afterTurn;
|
|
274
|
-
if (!hook) return;
|
|
275
|
-
await Promise.allSettled([Promise.resolve().then(() => hook(context))]);
|
|
276
|
-
}
|
|
277
|
-
function normalizeAgentInput(input) {
|
|
278
|
-
if (typeof input === "string") return {
|
|
279
|
-
type: "user-text",
|
|
280
|
-
text: input
|
|
281
|
-
};
|
|
282
|
-
if (isStringArrayInput(input)) return {
|
|
283
|
-
type: "user-text",
|
|
284
|
-
text: structuredClone(input)
|
|
285
|
-
};
|
|
286
|
-
if (isArrayInput(input)) {
|
|
287
|
-
assertUserMessageContent(input);
|
|
288
|
-
return {
|
|
289
|
-
type: "user-message",
|
|
290
|
-
content: structuredClone(input)
|
|
291
|
-
};
|
|
356
|
+
#expireActiveOverlays(reason) {
|
|
357
|
+
const event = this.#overlays.expireActiveFrame(reason);
|
|
358
|
+
if (!event) return;
|
|
359
|
+
this.#activeRun?.emit(event);
|
|
292
360
|
}
|
|
293
|
-
|
|
294
|
-
return structuredClone(input);
|
|
295
|
-
}
|
|
296
|
-
function isStringArrayInput(input) {
|
|
297
|
-
return isArrayInput(input) && input.every((part) => typeof part === "string");
|
|
298
|
-
}
|
|
299
|
-
function isArrayInput(input) {
|
|
300
|
-
return Array.isArray(input);
|
|
301
|
-
}
|
|
302
|
-
function isUserMessage(input) {
|
|
303
|
-
return input.type === "user-message";
|
|
304
|
-
}
|
|
305
|
-
function assertUserMessageContent(input) {
|
|
306
|
-
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 }.");
|
|
307
|
-
}
|
|
308
|
-
function isUserMessageContentPart(part) {
|
|
309
|
-
if (part === null || typeof part !== "object" || !("type" in part)) return false;
|
|
310
|
-
if (part.type === "text") return "text" in part && typeof part.text === "string";
|
|
311
|
-
if (part.type === "image") return "image" in part && typeof part.image === "string" && (!("mediaType" in part) || typeof part.mediaType === "string");
|
|
312
|
-
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");
|
|
313
|
-
return false;
|
|
314
|
-
}
|
|
315
|
-
function isUserMessageFileData(data) {
|
|
316
|
-
if (typeof data === "string") return true;
|
|
317
|
-
if (data === null || typeof data !== "object" || !("type" in data)) return false;
|
|
318
|
-
if (data.type === "data") return "data" in data && typeof data.data === "string";
|
|
319
|
-
if (data.type === "reference") return "reference" in data && data.reference !== null && typeof data.reference === "object" && Object.values(data.reference).every((value) => typeof value === "string");
|
|
320
|
-
if (data.type === "text") return "text" in data && typeof data.text === "string";
|
|
321
|
-
if (data.type === "url") return "url" in data && typeof data.url === "string";
|
|
322
|
-
return false;
|
|
323
|
-
}
|
|
361
|
+
};
|
|
324
362
|
function errorMessage(error) {
|
|
325
363
|
if (error instanceof Error) return error.message;
|
|
326
364
|
return String(error);
|
|
327
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
|
+
}
|
|
328
378
|
function sessionKilledError() {
|
|
329
379
|
return /* @__PURE__ */ new Error("Session killed");
|
|
330
380
|
}
|
|
331
|
-
function runtimeInputClosedError(reason) {
|
|
332
|
-
return /* @__PURE__ */ new Error(`session.steer() cannot be used after ${reason}`);
|
|
333
|
-
}
|
|
334
381
|
var SessionCommitConflictError = class extends Error {
|
|
335
382
|
constructor(key) {
|
|
336
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","#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 #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 this.#activeAbort?.abort();\n this.#closeRuntimeInput(\n this.#activeRuntimeInput,\n sessionKilledError().message\n );\n\n while (this.#inputQueue.length > 0) {\n const item = this.#inputQueue.shift();\n this.#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 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 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 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":"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"}
|
|
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",
|