@minpeter/pss-runtime 0.0.11 → 0.1.0-next.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +67 -5
- package/dist/agent-namespace.js +17 -0
- package/dist/agent-namespace.js.map +1 -0
- package/dist/agent-validation.js +35 -0
- package/dist/agent-validation.js.map +1 -0
- package/dist/agent.d.ts +11 -2
- package/dist/agent.js +79 -14
- package/dist/agent.js.map +1 -1
- package/dist/child-session-cleanups.js +61 -0
- package/dist/child-session-cleanups.js.map +1 -0
- package/dist/session/events.d.ts +21 -1
- package/dist/session/history.d.ts +1 -0
- package/dist/session/input-normalization.js +66 -0
- package/dist/session/input-normalization.js.map +1 -0
- package/dist/session/runtime-input.d.ts +1 -0
- package/dist/session/runtime-input.js +69 -0
- package/dist/session/runtime-input.js.map +1 -0
- package/dist/session/session-errors.js +23 -0
- package/dist/session/session-errors.js.map +1 -0
- package/dist/session/session-kill.js +23 -0
- package/dist/session/session-kill.js.map +1 -0
- package/dist/session/session-runtime-drain.js +22 -0
- package/dist/session/session-runtime-drain.js.map +1 -0
- package/dist/session/session-state.d.ts +1 -0
- package/dist/session/session-state.js +102 -0
- package/dist/session/session-state.js.map +1 -0
- package/dist/session/session-turn-error.js +35 -0
- package/dist/session/session-turn-error.js.map +1 -0
- package/dist/session/session.js +95 -240
- package/dist/session/session.js.map +1 -1
- package/dist/session/store/file.d.ts +1 -0
- package/dist/session/store/file.js +14 -0
- package/dist/session/store/file.js.map +1 -1
- package/dist/session/store/memory.d.ts +1 -0
- package/dist/session/store/memory.js +5 -0
- package/dist/session/store/memory.js.map +1 -1
- package/dist/session/store/types.d.ts +1 -0
- package/dist/subagent-job-cancel.js +28 -0
- package/dist/subagent-job-cancel.js.map +1 -0
- package/dist/subagent-job-output.js +63 -0
- package/dist/subagent-job-output.js.map +1 -0
- package/dist/subagent-jobs.js +151 -0
- package/dist/subagent-jobs.js.map +1 -0
- package/dist/subagent-prompt-schema.js +114 -0
- package/dist/subagent-prompt-schema.js.map +1 -0
- package/dist/subagent-run.js +111 -0
- package/dist/subagent-run.js.map +1 -0
- package/dist/subagents.js +92 -0
- package/dist/subagents.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { normalizeAgentInput } from "./input-normalization.js";
|
|
2
|
+
//#region src/session/runtime-input.ts
|
|
3
|
+
function createRuntimeInputState(queue) {
|
|
4
|
+
return {
|
|
5
|
+
pending: Promise.resolve(),
|
|
6
|
+
queue
|
|
7
|
+
};
|
|
8
|
+
}
|
|
9
|
+
function addSteeringInput(runtimeInput, input) {
|
|
10
|
+
const next = runtimeInput.pending.then(() => {
|
|
11
|
+
if (runtimeInput.closedReason) throw runtimeInputClosedError(runtimeInput.closedReason);
|
|
12
|
+
runtimeInput.queue.push({
|
|
13
|
+
input: normalizeAgentInput(input),
|
|
14
|
+
placement: runtimeInput.steerPlacement ?? runtimeInput.placement ?? "step-end"
|
|
15
|
+
});
|
|
16
|
+
});
|
|
17
|
+
runtimeInput.pending = next.catch(() => void 0);
|
|
18
|
+
return next;
|
|
19
|
+
}
|
|
20
|
+
function closeRuntimeInput(runtimeInput, reason = "the run reached a terminal state") {
|
|
21
|
+
if (runtimeInput && !runtimeInput.closedReason) {
|
|
22
|
+
runtimeInput.closedReason = reason;
|
|
23
|
+
runtimeInput.placement = void 0;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
async function withRuntimeInputWindow(runtimeInput, placement, callback) {
|
|
27
|
+
const previousSteerPlacement = runtimeInput.steerPlacement;
|
|
28
|
+
runtimeInput.placement = placement;
|
|
29
|
+
runtimeInput.steerPlacement = placement;
|
|
30
|
+
try {
|
|
31
|
+
return await callback();
|
|
32
|
+
} finally {
|
|
33
|
+
runtimeInput.placement = void 0;
|
|
34
|
+
runtimeInput.steerPlacement = previousSteerPlacement;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
async function withSteeringPlacement(runtimeInput, placement, callback) {
|
|
38
|
+
const previousSteerPlacement = runtimeInput.steerPlacement;
|
|
39
|
+
runtimeInput.steerPlacement = placement;
|
|
40
|
+
try {
|
|
41
|
+
return await callback();
|
|
42
|
+
} finally {
|
|
43
|
+
runtimeInput.steerPlacement = previousSteerPlacement;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
function hooksForRuntimeInput(hooks, runtimeInput) {
|
|
47
|
+
if (!hooks) return;
|
|
48
|
+
return {
|
|
49
|
+
...hooks,
|
|
50
|
+
afterStep: (context) => withSteeringPlacement(runtimeInput, "step-end", async () => {
|
|
51
|
+
await hooks.afterStep?.(context);
|
|
52
|
+
}),
|
|
53
|
+
beforeStep: (context) => withSteeringPlacement(runtimeInput, "step-start", async () => {
|
|
54
|
+
await hooks.beforeStep?.(context);
|
|
55
|
+
})
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
function shiftRuntimeInput(runtimeInput, placement) {
|
|
59
|
+
const index = runtimeInput.queue.findIndex((input) => input.placement === placement);
|
|
60
|
+
if (index === -1) return;
|
|
61
|
+
return runtimeInput.queue.splice(index, 1)[0];
|
|
62
|
+
}
|
|
63
|
+
function runtimeInputClosedError(reason) {
|
|
64
|
+
return /* @__PURE__ */ new Error(`session.steer() cannot be used after ${reason}`);
|
|
65
|
+
}
|
|
66
|
+
//#endregion
|
|
67
|
+
export { addSteeringInput, closeRuntimeInput, createRuntimeInputState, hooksForRuntimeInput, shiftRuntimeInput, withRuntimeInputWindow, withSteeringPlacement };
|
|
68
|
+
|
|
69
|
+
//# sourceMappingURL=runtime-input.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runtime-input.js","names":[],"sources":["../../src/session/runtime-input.ts"],"sourcesContent":["import type { AgentHooks } from \"../hooks\";\nimport type { RuntimeInput } from \"./events\";\nimport type { AgentInput, UserInput } from \"./input\";\nimport { normalizeAgentInput } from \"./input-normalization\";\nimport type { BufferedAgentRun } from \"./run\";\n\nexport type RuntimeInputPlacement = RuntimeInput[\"placement\"];\n\nexport interface QueuedRuntimeInput {\n readonly input: UserInput;\n readonly placement: RuntimeInputPlacement;\n}\n\nexport interface RuntimeInputState {\n closedReason?: string;\n pending: Promise<void>;\n placement?: RuntimeInputPlacement;\n readonly queue: QueuedRuntimeInput[];\n steerPlacement?: RuntimeInputPlacement;\n}\n\nexport interface QueuedInput {\n readonly input: UserInput;\n readonly run: BufferedAgentRun;\n readonly runtimeInput: RuntimeInputState;\n}\n\nexport function createRuntimeInputState(\n queue: QueuedRuntimeInput[]\n): RuntimeInputState {\n return {\n pending: Promise.resolve(),\n queue,\n };\n}\n\nexport function 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\nexport function closeRuntimeInput(\n runtimeInput: RuntimeInputState | undefined,\n reason = \"the run reached a terminal state\"\n): void {\n if (runtimeInput && !runtimeInput.closedReason) {\n runtimeInput.closedReason = reason;\n runtimeInput.placement = undefined;\n }\n}\n\nexport async function 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\nexport async function 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\nexport function hooksForRuntimeInput(\n hooks: AgentHooks | undefined,\n runtimeInput: RuntimeInputState\n): AgentHooks | undefined {\n if (!hooks) {\n return;\n }\n\n return {\n ...hooks,\n afterStep: (context) =>\n withSteeringPlacement(runtimeInput, \"step-end\", async () => {\n await hooks.afterStep?.(context);\n }),\n beforeStep: (context) =>\n withSteeringPlacement(runtimeInput, \"step-start\", async () => {\n await hooks.beforeStep?.(context);\n }),\n };\n}\n\nexport function 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\nfunction runtimeInputClosedError(reason: string): Error {\n return new Error(`session.steer() cannot be used after ${reason}`);\n}\n"],"mappings":";;AA2BA,SAAgB,wBACd,OACmB;CACnB,OAAO;EACL,SAAS,QAAQ,QAAQ;EACzB;CACF;AACF;AAEA,SAAgB,iBACd,cACA,OACe;CACf,MAAM,OAAO,aAAa,QAAQ,WAAW;EAC3C,IAAI,aAAa,cACf,MAAM,wBAAwB,aAAa,YAAY;EAGzD,aAAa,MAAM,KAAK;GACtB,OAAO,oBAAoB,KAAK;GAChC,WACE,aAAa,kBAAkB,aAAa,aAAa;EAC7D,CAAC;CACH,CAAC;CACD,aAAa,UAAU,KAAK,YAAY,KAAA,CAAS;CACjD,OAAO;AACT;AAEA,SAAgB,kBACd,cACA,SAAS,oCACH;CACN,IAAI,gBAAgB,CAAC,aAAa,cAAc;EAC9C,aAAa,eAAe;EAC5B,aAAa,YAAY,KAAA;CAC3B;AACF;AAEA,eAAsB,uBACpB,cACA,WACA,UACY;CACZ,MAAM,yBAAyB,aAAa;CAC5C,aAAa,YAAY;CACzB,aAAa,iBAAiB;CAC9B,IAAI;EACF,OAAO,MAAM,SAAS;CACxB,UAAU;EACR,aAAa,YAAY,KAAA;EACzB,aAAa,iBAAiB;CAChC;AACF;AAEA,eAAsB,sBACpB,cACA,WACA,UACY;CACZ,MAAM,yBAAyB,aAAa;CAC5C,aAAa,iBAAiB;CAC9B,IAAI;EACF,OAAO,MAAM,SAAS;CACxB,UAAU;EACR,aAAa,iBAAiB;CAChC;AACF;AAEA,SAAgB,qBACd,OACA,cACwB;CACxB,IAAI,CAAC,OACH;CAGF,OAAO;EACL,GAAG;EACH,YAAY,YACV,sBAAsB,cAAc,YAAY,YAAY;GAC1D,MAAM,MAAM,YAAY,OAAO;EACjC,CAAC;EACH,aAAa,YACX,sBAAsB,cAAc,cAAc,YAAY;GAC5D,MAAM,MAAM,aAAa,OAAO;EAClC,CAAC;CACL;AACF;AAEA,SAAgB,kBACd,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,SAAS,wBAAwB,QAAuB;CACtD,uBAAO,IAAI,MAAM,wCAAwC,QAAQ;AACnE"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
//#region src/session/session-errors.ts
|
|
2
|
+
async function runAfterTurnHook(hooks, context) {
|
|
3
|
+
const hook = hooks?.afterTurn;
|
|
4
|
+
if (!hook) return;
|
|
5
|
+
await Promise.allSettled([Promise.resolve().then(() => hook(context))]);
|
|
6
|
+
}
|
|
7
|
+
function errorMessage(error) {
|
|
8
|
+
if (error instanceof Error) return error.message;
|
|
9
|
+
return String(error);
|
|
10
|
+
}
|
|
11
|
+
function sessionKilledError() {
|
|
12
|
+
return /* @__PURE__ */ new Error("Session killed");
|
|
13
|
+
}
|
|
14
|
+
function sessionDeleteInProgressError() {
|
|
15
|
+
return /* @__PURE__ */ new Error("Session delete in progress");
|
|
16
|
+
}
|
|
17
|
+
function sessionTerminalError(killed) {
|
|
18
|
+
return killed ? sessionKilledError() : sessionDeleteInProgressError();
|
|
19
|
+
}
|
|
20
|
+
//#endregion
|
|
21
|
+
export { errorMessage, runAfterTurnHook, sessionKilledError, sessionTerminalError };
|
|
22
|
+
|
|
23
|
+
//# sourceMappingURL=session-errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session-errors.js","names":[],"sources":["../../src/session/session-errors.ts"],"sourcesContent":["import type { AgentHooks } from \"../hooks\";\n\nexport async 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 errorMessage(error: unknown): string {\n if (error instanceof Error) {\n return error.message;\n }\n\n return String(error);\n}\n\nexport function sessionKilledError(): Error {\n return new Error(\"Session killed\");\n}\n\nexport function sessionDeleteInProgressError(): Error {\n return new Error(\"Session delete in progress\");\n}\n\nexport function sessionTerminalError(killed: boolean): Error {\n return killed ? sessionKilledError() : sessionDeleteInProgressError();\n}\n"],"mappings":";AAEA,eAAsB,iBACpB,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,aAAa,OAAwB;CACnD,IAAI,iBAAiB,OACnB,OAAO,MAAM;CAGf,OAAO,OAAO,KAAK;AACrB;AAEA,SAAgB,qBAA4B;CAC1C,uBAAO,IAAI,MAAM,gBAAgB;AACnC;AAEA,SAAgB,+BAAsC;CACpD,uBAAO,IAAI,MAAM,4BAA4B;AAC/C;AAEA,SAAgB,qBAAqB,QAAwB;CAC3D,OAAO,SAAS,mBAAmB,IAAI,6BAA6B;AACtE"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { closeRuntimeInput } from "./runtime-input.js";
|
|
2
|
+
//#region src/session/session-kill.ts
|
|
3
|
+
function closeKilledRuntimeInputs({ activeRuntimeInput, inputQueue, message, runToClose }) {
|
|
4
|
+
closeRuntimeInput(activeRuntimeInput, message);
|
|
5
|
+
runToClose?.emit({
|
|
6
|
+
type: "turn-error",
|
|
7
|
+
message
|
|
8
|
+
});
|
|
9
|
+
runToClose?.close(void 0, message);
|
|
10
|
+
while (inputQueue.length > 0) {
|
|
11
|
+
const item = inputQueue.shift();
|
|
12
|
+
closeRuntimeInput(item?.runtimeInput, message);
|
|
13
|
+
item?.run.emit({
|
|
14
|
+
type: "turn-error",
|
|
15
|
+
message
|
|
16
|
+
});
|
|
17
|
+
item?.run.close(void 0, message);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
//#endregion
|
|
21
|
+
export { closeKilledRuntimeInputs };
|
|
22
|
+
|
|
23
|
+
//# sourceMappingURL=session-kill.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session-kill.js","names":[],"sources":["../../src/session/session-kill.ts"],"sourcesContent":["import type { BufferedAgentRun } from \"./run\";\nimport {\n closeRuntimeInput,\n type QueuedInput,\n type RuntimeInputState,\n} from \"./runtime-input\";\n\ninterface CloseKilledRuntimeInputsOptions {\n readonly activeRuntimeInput: RuntimeInputState | undefined;\n readonly inputQueue: QueuedInput[];\n readonly message: string;\n readonly runToClose: BufferedAgentRun | undefined;\n}\n\nexport function closeKilledRuntimeInputs({\n activeRuntimeInput,\n inputQueue,\n message,\n runToClose,\n}: CloseKilledRuntimeInputsOptions): void {\n closeRuntimeInput(activeRuntimeInput, message);\n runToClose?.emit({ type: \"turn-error\", message });\n runToClose?.close(undefined, message);\n\n while (inputQueue.length > 0) {\n const item = inputQueue.shift();\n closeRuntimeInput(item?.runtimeInput, message);\n item?.run.emit({ type: \"turn-error\", message });\n item?.run.close(undefined, message);\n }\n}\n"],"mappings":";;AAcA,SAAgB,yBAAyB,EACvC,oBACA,YACA,SACA,cACwC;CACxC,kBAAkB,oBAAoB,OAAO;CAC7C,YAAY,KAAK;EAAE,MAAM;EAAc;CAAQ,CAAC;CAChD,YAAY,MAAM,KAAA,GAAW,OAAO;CAEpC,OAAO,WAAW,SAAS,GAAG;EAC5B,MAAM,OAAO,WAAW,MAAM;EAC9B,kBAAkB,MAAM,cAAc,OAAO;EAC7C,MAAM,IAAI,KAAK;GAAE,MAAM;GAAc;EAAQ,CAAC;EAC9C,MAAM,IAAI,MAAM,KAAA,GAAW,OAAO;CACpC;AACF"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { shiftRuntimeInput } from "./runtime-input.js";
|
|
2
|
+
//#region src/session/session-runtime-drain.ts
|
|
3
|
+
async function drainRuntimeInput({ placement, run, runtimeInput, state }) {
|
|
4
|
+
let added = false;
|
|
5
|
+
let next = shiftRuntimeInput(runtimeInput, placement);
|
|
6
|
+
while (next) {
|
|
7
|
+
added = true;
|
|
8
|
+
run.emit({
|
|
9
|
+
type: "runtime-input",
|
|
10
|
+
input: next.input,
|
|
11
|
+
placement
|
|
12
|
+
});
|
|
13
|
+
state.appendUserInput(next.input);
|
|
14
|
+
await state.commit();
|
|
15
|
+
next = shiftRuntimeInput(runtimeInput, placement);
|
|
16
|
+
}
|
|
17
|
+
return added;
|
|
18
|
+
}
|
|
19
|
+
//#endregion
|
|
20
|
+
export { drainRuntimeInput };
|
|
21
|
+
|
|
22
|
+
//# sourceMappingURL=session-runtime-drain.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session-runtime-drain.js","names":[],"sources":["../../src/session/session-runtime-drain.ts"],"sourcesContent":["import type { BufferedAgentRun } from \"./run\";\nimport {\n type RuntimeInputPlacement,\n type RuntimeInputState,\n shiftRuntimeInput,\n} from \"./runtime-input\";\nimport type { SessionState } from \"./session-state\";\n\nexport async function drainRuntimeInput({\n placement,\n run,\n runtimeInput,\n state,\n}: {\n readonly placement: RuntimeInputPlacement;\n readonly run: BufferedAgentRun;\n readonly runtimeInput: RuntimeInputState;\n readonly state: SessionState;\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 state.appendUserInput(next.input);\n await state.commit();\n next = shiftRuntimeInput(runtimeInput, placement);\n }\n\n return added;\n}\n"],"mappings":";;AAQA,eAAsB,kBAAkB,EACtC,WACA,KACA,cACA,SAMmB;CACnB,IAAI,QAAQ;CACZ,IAAI,OAAO,kBAAkB,cAAc,SAAS;CACpD,OAAO,MAAM;EACX,QAAQ;EACR,IAAI,KAAK;GAAE,MAAM;GAAiB,OAAO,KAAK;GAAO;EAAU,CAAC;EAChE,MAAM,gBAAgB,KAAK,KAAK;EAChC,MAAM,MAAM,OAAO;EACnB,OAAO,kBAAkB,cAAc,SAAS;CAClD;CAEA,OAAO;AACT"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import { ModelMessage } from "ai";
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { ModelMessageHistory } from "./history.js";
|
|
2
|
+
import { decodeStoredSessionSnapshot, encodeSessionSnapshot } from "./snapshot.js";
|
|
3
|
+
//#region src/session/session-state.ts
|
|
4
|
+
var SessionCommitConflictError = class extends Error {
|
|
5
|
+
constructor(key) {
|
|
6
|
+
super(`Session ${JSON.stringify(key)} commit conflict`);
|
|
7
|
+
}
|
|
8
|
+
};
|
|
9
|
+
var SessionState = class {
|
|
10
|
+
#persistence;
|
|
11
|
+
#deleteRequested = false;
|
|
12
|
+
#history = new ModelMessageHistory();
|
|
13
|
+
#deleted = false;
|
|
14
|
+
#loadPromise;
|
|
15
|
+
#loaded = false;
|
|
16
|
+
#storeVersion;
|
|
17
|
+
#writeQueue = Promise.resolve();
|
|
18
|
+
constructor(persistence) {
|
|
19
|
+
this.#persistence = persistence;
|
|
20
|
+
}
|
|
21
|
+
get history() {
|
|
22
|
+
return this.#history;
|
|
23
|
+
}
|
|
24
|
+
async ensureLoaded() {
|
|
25
|
+
if (this.#deleteRequested || this.#deleted) return;
|
|
26
|
+
if (this.#loaded) return;
|
|
27
|
+
this.#loadPromise ??= this.#loadSessionState();
|
|
28
|
+
try {
|
|
29
|
+
await this.#loadPromise;
|
|
30
|
+
} catch (error) {
|
|
31
|
+
this.#loadPromise = void 0;
|
|
32
|
+
throw error;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
modelSnapshot() {
|
|
36
|
+
return this.#history.modelSnapshot();
|
|
37
|
+
}
|
|
38
|
+
appendUserInput(input) {
|
|
39
|
+
this.#history.appendUserInput(input);
|
|
40
|
+
}
|
|
41
|
+
rollback(snapshot) {
|
|
42
|
+
this.#history.rollback(snapshot);
|
|
43
|
+
}
|
|
44
|
+
async commit() {
|
|
45
|
+
if (this.#deleteRequested || this.#deleted) return;
|
|
46
|
+
const snapshot = this.#history.modelSnapshot();
|
|
47
|
+
await this.#enqueueWrite(async () => {
|
|
48
|
+
if (this.#deleteRequested || this.#deleted) return;
|
|
49
|
+
const result = await this.#persistence.store.commit(this.#persistence.key, { state: encodeSessionSnapshot(snapshot) }, { expectedVersion: this.#storeVersion ?? null });
|
|
50
|
+
if (!result.ok) {
|
|
51
|
+
await this.#replaceWithStoredSession();
|
|
52
|
+
throw new SessionCommitConflictError(this.#persistence.key);
|
|
53
|
+
}
|
|
54
|
+
this.#storeVersion = result.version;
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
async delete() {
|
|
58
|
+
if (this.#deleted) return;
|
|
59
|
+
const previous = {
|
|
60
|
+
history: this.#history.modelSnapshot(),
|
|
61
|
+
loaded: this.#loaded,
|
|
62
|
+
storeVersion: this.#storeVersion
|
|
63
|
+
};
|
|
64
|
+
this.#deleteRequested = true;
|
|
65
|
+
this.#loadPromise = void 0;
|
|
66
|
+
await this.#enqueueWrite(async () => {
|
|
67
|
+
try {
|
|
68
|
+
await this.#persistence.store.delete(this.#persistence.key);
|
|
69
|
+
} catch (error) {
|
|
70
|
+
this.#deleteRequested = false;
|
|
71
|
+
this.#loaded = previous.loaded;
|
|
72
|
+
this.#storeVersion = previous.storeVersion;
|
|
73
|
+
this.#history = new ModelMessageHistory(previous.history);
|
|
74
|
+
throw error;
|
|
75
|
+
}
|
|
76
|
+
this.#deleted = true;
|
|
77
|
+
this.#loadPromise = void 0;
|
|
78
|
+
this.#loaded = true;
|
|
79
|
+
this.#storeVersion = void 0;
|
|
80
|
+
this.#history = new ModelMessageHistory();
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
#enqueueWrite(operation) {
|
|
84
|
+
const next = this.#writeQueue.then(operation, operation);
|
|
85
|
+
this.#writeQueue = next.catch(() => void 0);
|
|
86
|
+
return next;
|
|
87
|
+
}
|
|
88
|
+
async #loadSessionState() {
|
|
89
|
+
if (this.#loaded) return;
|
|
90
|
+
await this.#replaceWithStoredSession();
|
|
91
|
+
this.#loaded = true;
|
|
92
|
+
}
|
|
93
|
+
async #replaceWithStoredSession() {
|
|
94
|
+
const stored = await this.#persistence.store.load(this.#persistence.key);
|
|
95
|
+
this.#storeVersion = stored?.version;
|
|
96
|
+
this.#history = new ModelMessageHistory(decodeStoredSessionSnapshot(stored));
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
//#endregion
|
|
100
|
+
export { SessionCommitConflictError, SessionState };
|
|
101
|
+
|
|
102
|
+
//# sourceMappingURL=session-state.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session-state.js","names":["#persistence","#history","#deleteRequested","#deleted","#loaded","#loadPromise","#loadSessionState","#enqueueWrite","#storeVersion","#replaceWithStoredSession","#writeQueue"],"sources":["../../src/session/session-state.ts"],"sourcesContent":["import type { ModelMessage } from \"ai\";\nimport { ModelMessageHistory } from \"./history\";\nimport { decodeStoredSessionSnapshot, encodeSessionSnapshot } from \"./snapshot\";\nimport type { SessionStore } from \"./store/types\";\n\nexport interface SessionPersistenceOptions {\n readonly key: string;\n readonly store: SessionStore;\n}\n\nexport class SessionCommitConflictError extends Error {\n constructor(key: string) {\n super(`Session ${JSON.stringify(key)} commit conflict`);\n }\n}\n\nexport class SessionState {\n readonly #persistence: SessionPersistenceOptions;\n #deleteRequested = false;\n #history = new ModelMessageHistory();\n #deleted = false;\n #loadPromise?: Promise<void>;\n #loaded = false;\n #storeVersion: string | undefined;\n #writeQueue: Promise<void> = Promise.resolve();\n\n constructor(persistence: SessionPersistenceOptions) {\n this.#persistence = persistence;\n }\n\n get history(): ModelMessageHistory {\n return this.#history;\n }\n\n async ensureLoaded(): Promise<void> {\n if (this.#deleteRequested || this.#deleted) {\n return;\n }\n\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 modelSnapshot(): ModelMessage[] {\n return this.#history.modelSnapshot();\n }\n\n appendUserInput(\n input: Parameters<ModelMessageHistory[\"appendUserInput\"]>[0]\n ) {\n this.#history.appendUserInput(input);\n }\n\n rollback(snapshot: ModelMessage[]): void {\n this.#history.rollback(snapshot);\n }\n\n async commit(): Promise<void> {\n if (this.#deleteRequested || this.#deleted) {\n return;\n }\n\n const snapshot = this.#history.modelSnapshot();\n await this.#enqueueWrite(async () => {\n if (this.#deleteRequested || this.#deleted) {\n return;\n }\n\n const result = await this.#persistence.store.commit(\n this.#persistence.key,\n { state: encodeSessionSnapshot(snapshot) },\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\n async delete(): Promise<void> {\n if (this.#deleted) {\n return;\n }\n\n const previous = {\n history: this.#history.modelSnapshot(),\n loaded: this.#loaded,\n storeVersion: this.#storeVersion,\n };\n this.#deleteRequested = true;\n this.#loadPromise = undefined;\n\n await this.#enqueueWrite(async () => {\n try {\n await this.#persistence.store.delete(this.#persistence.key);\n } catch (error) {\n this.#deleteRequested = false;\n this.#loaded = previous.loaded;\n this.#storeVersion = previous.storeVersion;\n this.#history = new ModelMessageHistory(previous.history);\n throw error;\n }\n\n this.#deleted = true;\n this.#loadPromise = undefined;\n this.#loaded = true;\n this.#storeVersion = undefined;\n this.#history = new ModelMessageHistory();\n });\n }\n\n #enqueueWrite(operation: () => Promise<void>): Promise<void> {\n const next = this.#writeQueue.then(operation, operation);\n this.#writeQueue = next.catch(() => undefined);\n return next;\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"],"mappings":";;;AAUA,IAAa,6BAAb,cAAgD,MAAM;CACpD,YAAY,KAAa;EACvB,MAAM,WAAW,KAAK,UAAU,GAAG,EAAE,iBAAiB;CACxD;AACF;AAEA,IAAa,eAAb,MAA0B;CACxB;CACA,mBAAmB;CACnB,WAAW,IAAI,oBAAoB;CACnC,WAAW;CACX;CACA,UAAU;CACV;CACA,cAA6B,QAAQ,QAAQ;CAE7C,YAAY,aAAwC;EAClD,KAAKA,eAAe;CACtB;CAEA,IAAI,UAA+B;EACjC,OAAO,KAAKC;CACd;CAEA,MAAM,eAA8B;EAClC,IAAI,KAAKC,oBAAoB,KAAKC,UAChC;EAGF,IAAI,KAAKC,SACP;EAGF,KAAKC,iBAAiB,KAAKC,kBAAkB;EAC7C,IAAI;GACF,MAAM,KAAKD;EACb,SAAS,OAAO;GACd,KAAKA,eAAe,KAAA;GACpB,MAAM;EACR;CACF;CAEA,gBAAgC;EAC9B,OAAO,KAAKJ,SAAS,cAAc;CACrC;CAEA,gBACE,OACA;EACA,KAAKA,SAAS,gBAAgB,KAAK;CACrC;CAEA,SAAS,UAAgC;EACvC,KAAKA,SAAS,SAAS,QAAQ;CACjC;CAEA,MAAM,SAAwB;EAC5B,IAAI,KAAKC,oBAAoB,KAAKC,UAChC;EAGF,MAAM,WAAW,KAAKF,SAAS,cAAc;EAC7C,MAAM,KAAKM,cAAc,YAAY;GACnC,IAAI,KAAKL,oBAAoB,KAAKC,UAChC;GAGF,MAAM,SAAS,MAAM,KAAKH,aAAa,MAAM,OAC3C,KAAKA,aAAa,KAClB,EAAE,OAAO,sBAAsB,QAAQ,EAAE,GACzC,EAAE,iBAAiB,KAAKQ,iBAAiB,KAAK,CAChD;GAEA,IAAI,CAAC,OAAO,IAAI;IACd,MAAM,KAAKC,0BAA0B;IACrC,MAAM,IAAI,2BAA2B,KAAKT,aAAa,GAAG;GAC5D;GAEA,KAAKQ,gBAAgB,OAAO;EAC9B,CAAC;CACH;CAEA,MAAM,SAAwB;EAC5B,IAAI,KAAKL,UACP;EAGF,MAAM,WAAW;GACf,SAAS,KAAKF,SAAS,cAAc;GACrC,QAAQ,KAAKG;GACb,cAAc,KAAKI;EACrB;EACA,KAAKN,mBAAmB;EACxB,KAAKG,eAAe,KAAA;EAEpB,MAAM,KAAKE,cAAc,YAAY;GACnC,IAAI;IACF,MAAM,KAAKP,aAAa,MAAM,OAAO,KAAKA,aAAa,GAAG;GAC5D,SAAS,OAAO;IACd,KAAKE,mBAAmB;IACxB,KAAKE,UAAU,SAAS;IACxB,KAAKI,gBAAgB,SAAS;IAC9B,KAAKP,WAAW,IAAI,oBAAoB,SAAS,OAAO;IACxD,MAAM;GACR;GAEA,KAAKE,WAAW;GAChB,KAAKE,eAAe,KAAA;GACpB,KAAKD,UAAU;GACf,KAAKI,gBAAgB,KAAA;GACrB,KAAKP,WAAW,IAAI,oBAAoB;EAC1C,CAAC;CACH;CAEA,cAAc,WAA+C;EAC3D,MAAM,OAAO,KAAKS,YAAY,KAAK,WAAW,SAAS;EACvD,KAAKA,cAAc,KAAK,YAAY,KAAA,CAAS;EAC7C,OAAO;CACT;CAEA,MAAMJ,oBAAmC;EACvC,IAAI,KAAKF,SACP;EAGF,MAAM,KAAKK,0BAA0B;EACrC,KAAKL,UAAU;CACjB;CAEA,MAAMK,4BAA2C;EAC/C,MAAM,SAAS,MAAM,KAAKT,aAAa,MAAM,KAAK,KAAKA,aAAa,GAAG;EACvE,KAAKQ,gBAAgB,QAAQ;EAC7B,KAAKP,WAAW,IAAI,oBAClB,4BAA4B,MAAM,CACpC;CACF;AACF"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { closeRuntimeInput } from "./runtime-input.js";
|
|
2
|
+
import { errorMessage } from "./session-errors.js";
|
|
3
|
+
import { SessionCommitConflictError } from "./session-state.js";
|
|
4
|
+
//#region src/session/session-turn-error.ts
|
|
5
|
+
async function emitTurnErrorAfterRecovery({ error, historySnapshot, run, runtimeInput, state }) {
|
|
6
|
+
if (error instanceof SessionCommitConflictError) {
|
|
7
|
+
run.emit({
|
|
8
|
+
type: "turn-error",
|
|
9
|
+
message: error.message
|
|
10
|
+
});
|
|
11
|
+
closeRuntimeInput(runtimeInput, "a session commit conflict");
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
state.rollback(historySnapshot);
|
|
15
|
+
try {
|
|
16
|
+
await state.commit();
|
|
17
|
+
} catch (rollbackError) {
|
|
18
|
+
const rollbackMessage = rollbackError instanceof Error ? rollbackError.message : String(rollbackError);
|
|
19
|
+
run.emit({
|
|
20
|
+
type: "turn-error",
|
|
21
|
+
message: `${errorMessage(error)}; history rollback persistence failed: ${rollbackMessage}`
|
|
22
|
+
});
|
|
23
|
+
closeRuntimeInput(runtimeInput, "turn-error");
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
run.emit({
|
|
27
|
+
type: "turn-error",
|
|
28
|
+
message: errorMessage(error)
|
|
29
|
+
});
|
|
30
|
+
closeRuntimeInput(runtimeInput, "turn-error");
|
|
31
|
+
}
|
|
32
|
+
//#endregion
|
|
33
|
+
export { emitTurnErrorAfterRecovery };
|
|
34
|
+
|
|
35
|
+
//# sourceMappingURL=session-turn-error.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session-turn-error.js","names":[],"sources":["../../src/session/session-turn-error.ts"],"sourcesContent":["import type { ModelMessage } from \"ai\";\nimport type { BufferedAgentRun } from \"./run\";\nimport { closeRuntimeInput, type RuntimeInputState } from \"./runtime-input\";\nimport { errorMessage } from \"./session-errors\";\nimport { SessionCommitConflictError, type SessionState } from \"./session-state\";\n\nexport async function emitTurnErrorAfterRecovery({\n error,\n historySnapshot,\n run,\n runtimeInput,\n state,\n}: {\n readonly error: unknown;\n readonly historySnapshot: ModelMessage[];\n readonly run: BufferedAgentRun;\n readonly runtimeInput: RuntimeInputState;\n readonly state: SessionState;\n}): Promise<void> {\n if (error instanceof SessionCommitConflictError) {\n run.emit({ type: \"turn-error\", message: error.message });\n closeRuntimeInput(runtimeInput, \"a session commit conflict\");\n return;\n }\n\n state.rollback(historySnapshot);\n try {\n await state.commit();\n } catch (rollbackError) {\n const rollbackMessage =\n rollbackError instanceof Error\n ? rollbackError.message\n : String(rollbackError);\n run.emit({\n type: \"turn-error\",\n message: `${errorMessage(error)}; history rollback persistence failed: ${rollbackMessage}`,\n });\n closeRuntimeInput(runtimeInput, \"turn-error\");\n return;\n }\n\n run.emit({ type: \"turn-error\", message: errorMessage(error) });\n closeRuntimeInput(runtimeInput, \"turn-error\");\n}\n"],"mappings":";;;;AAMA,eAAsB,2BAA2B,EAC/C,OACA,iBACA,KACA,cACA,SAOgB;CAChB,IAAI,iBAAiB,4BAA4B;EAC/C,IAAI,KAAK;GAAE,MAAM;GAAc,SAAS,MAAM;EAAQ,CAAC;EACvD,kBAAkB,cAAc,2BAA2B;EAC3D;CACF;CAEA,MAAM,SAAS,eAAe;CAC9B,IAAI;EACF,MAAM,MAAM,OAAO;CACrB,SAAS,eAAe;EACtB,MAAM,kBACJ,yBAAyB,QACrB,cAAc,UACd,OAAO,aAAa;EAC1B,IAAI,KAAK;GACP,MAAM;GACN,SAAS,GAAG,aAAa,KAAK,EAAE,yCAAyC;EAC3E,CAAC;EACD,kBAAkB,cAAc,YAAY;EAC5C;CACF;CAEA,IAAI,KAAK;EAAE,MAAM;EAAc,SAAS,aAAa,KAAK;CAAE,CAAC;CAC7D,kBAAkB,cAAc,YAAY;AAC9C"}
|