@theoremjs/web 0.3.4-next.602.gb5a7fab → 0.3.4-next.604.ge4d5866
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 +8 -8
- package/package.json +2 -2
- package/server/mod.d.ts +0 -1
- package/server/mod.js +0 -1
- package/server/session-authority.d.ts +1 -1
- package/server/session-authority.js +3 -2
- package/server/session-limits.d.ts +6 -5
- package/server/session-limits.js +7 -7
- package/server/session-store.d.ts +7 -4
- package/server/session-store.js +3 -3
- package/server/tool-operations.d.ts +1 -1
- package/server/tool-operations.js +1 -1
package/README.md
CHANGED
|
@@ -379,23 +379,23 @@ Each saved outcome records its absolute retention deadline. Changing a handler's
|
|
|
379
379
|
Each issued gate records its absolute expiry. Changing `gateTtlMs` does not extend an issued gate.
|
|
380
380
|
Ready, running, and uncertain operations do not expire.
|
|
381
381
|
|
|
382
|
-
A session store declares its `capacity`: what it holds for one session, in bytes of UTF-8 JSON.
|
|
382
|
+
A session store with a real limit declares its `capacity`: what it holds for one session, in bytes of UTF-8 JSON.
|
|
383
383
|
|
|
384
|
-
| Field | What it bounds |
|
|
385
|
-
| --- | --- |
|
|
386
|
-
| `maxStateBytes` | One session's saved state |
|
|
387
|
-
| `maxOutcomeBytes` | One tool result |
|
|
384
|
+
| Field | What it bounds |
|
|
385
|
+
| --- | --- |
|
|
386
|
+
| `maxStateBytes` | One session's saved state |
|
|
387
|
+
| `maxOutcomeBytes` | One tool result |
|
|
388
388
|
|
|
389
|
-
|
|
389
|
+
A store that declares no `capacity` holds any size. `createMemorySessionStore` declares none unless you pass `capacity`, with both fields. A store you write declares the capacity of its own storage, if it has one.
|
|
390
390
|
|
|
391
391
|
Set `maxRequestBytes` to bound browser JSON before parsing. Its default is 16 MiB.
|
|
392
392
|
The handler rejects oversized requests before provider access or tool preparation.
|
|
393
393
|
Provider host options also accept `limits` for deadlines and upstream output.
|
|
394
|
-
|
|
394
|
+
When the store declares a capacity, the handler keeps room for one `maxOutcomeBytes` result for each gate and each call that has not settled.
|
|
395
395
|
When a session is full, the handler drops its oldest settled results, then its oldest provider checkpoints.
|
|
396
396
|
It never drops gates, permissions, or calls that have not settled. When those alone do not fit, the new call is refused before it runs, and the user reads `session.full`.
|
|
397
397
|
A result larger than `maxOutcomeBytes` settles as the call's `result_too_large` failure. The call is never left unresolved because of its size.
|
|
398
|
-
The handler fits each state to the store's capacity before `compareAndSwap`.
|
|
398
|
+
The handler fits each state to the store's capacity, when it has one, before `compareAndSwap`.
|
|
399
399
|
|
|
400
400
|
The default memory store coordinates handlers that share the same store object.
|
|
401
401
|
It retains unexpired gates, unresolved operations, and unexpired outcomes during idle and capacity eviction.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@theoremjs/web",
|
|
3
|
-
"version": "0.3.4-next.
|
|
3
|
+
"version": "0.3.4-next.604.ge4d5866",
|
|
4
4
|
"description": "Theorem on the web platform, with no UI framework: Web-standard server handlers that serve a profile, and the browser client that talks to them.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -25,6 +25,6 @@
|
|
|
25
25
|
},
|
|
26
26
|
"peerDependencies": {
|
|
27
27
|
"zod": "^4.6.5",
|
|
28
|
-
"@theoremjs/agents": "^0.3.4-next.
|
|
28
|
+
"@theoremjs/agents": "^0.3.4-next.604.ge4d5866"
|
|
29
29
|
}
|
|
30
30
|
}
|
package/server/mod.d.ts
CHANGED
|
@@ -20,7 +20,6 @@ export { checkRequest, parseLiveClientMessage, parseLiveOpenMessage } from './re
|
|
|
20
20
|
export { sessionStateStore } from './session-authority.ts';
|
|
21
21
|
export { createTheoremSessionBoundary, type PreparedLiveOpen, type SessionBoundaryOptions, type TheoremSessionBoundary, } from './session-boundary.ts';
|
|
22
22
|
export type { TheoremSessionCapacity } from './session-limits.ts';
|
|
23
|
-
export { DEFAULT_SESSION_CAPACITY } from './session-limits.ts';
|
|
24
23
|
export { createMemorySessionStore, DEFAULT_OPERATION_RETENTION_MS, type MemorySessionStoreOptions, type PendingToolGate, type SessionSnapshot, type SessionToolOperation, type SessionWriteResult, type TheoremSessionState, type TheoremSessionStore, theoremSessionStateSchema, } from './session-store.ts';
|
|
25
24
|
export { createMemorySteerInbox, type SteerInbox, type SteerUnit, steerStage, steerUnitOf, stopOnRequest, } from './steer-inbox.ts';
|
|
26
25
|
export { sessionToolCoordinator } from './tool-operations.ts';
|
package/server/mod.js
CHANGED
|
@@ -18,7 +18,6 @@ export { createMemoryPageToolBroker, pageToolResultSchema, sessionPageDispatch,
|
|
|
18
18
|
export { checkRequest, parseLiveClientMessage, parseLiveOpenMessage } from "./request-check.js";
|
|
19
19
|
export { sessionStateStore } from "./session-authority.js";
|
|
20
20
|
export { createTheoremSessionBoundary, } from "./session-boundary.js";
|
|
21
|
-
export { DEFAULT_SESSION_CAPACITY } from "./session-limits.js";
|
|
22
21
|
export { createMemorySessionStore, DEFAULT_OPERATION_RETENTION_MS, theoremSessionStateSchema, } from "./session-store.js";
|
|
23
22
|
export { createMemorySteerInbox, steerStage, steerUnitOf, stopOnRequest, } from "./steer-inbox.js";
|
|
24
23
|
export { sessionToolCoordinator } from "./tool-operations.js";
|
|
@@ -6,7 +6,7 @@ export type MutableStore<T> = {
|
|
|
6
6
|
};
|
|
7
7
|
/** Session state with the capacity its store declared. */
|
|
8
8
|
export type SessionStateStore = MutableStore<TheoremSessionState> & {
|
|
9
|
-
readonly capacity
|
|
9
|
+
readonly capacity?: TheoremSessionCapacity;
|
|
10
10
|
};
|
|
11
11
|
/** Session state, with expired gates dropped as it loads so they can't be answered. */
|
|
12
12
|
export declare function sessionStateStore(store: TheoremSessionStore, gateTtlMs: number, operationRetentionMs: number): SessionStateStore;
|
|
@@ -35,7 +35,7 @@ export function sessionStateStore(store, gateTtlMs, operationRetentionMs) {
|
|
|
35
35
|
return { revision: snapshot?.revision ?? null, state };
|
|
36
36
|
};
|
|
37
37
|
return {
|
|
38
|
-
capacity,
|
|
38
|
+
...(capacity ? { capacity } : {}),
|
|
39
39
|
async read(sessionId) {
|
|
40
40
|
return (await load(sessionId, Date.now())).state;
|
|
41
41
|
},
|
|
@@ -50,7 +50,8 @@ export function sessionStateStore(store, gateTtlMs, operationRetentionMs) {
|
|
|
50
50
|
if (operation.status === 'settled')
|
|
51
51
|
operation.retainUntil ??= operation.settledAt + operationRetentionMs;
|
|
52
52
|
}
|
|
53
|
-
|
|
53
|
+
if (capacity)
|
|
54
|
+
fitSession(state, capacity);
|
|
54
55
|
const next = theoremSessionStateSchema.safeParse(state);
|
|
55
56
|
if (!next.success) {
|
|
56
57
|
throw new TheoremError('config', labelText('error.config'), {
|
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
import type { TheoremSessionState } from './session-store.ts';
|
|
2
|
-
/** What a session store holds for one session, in bytes of UTF-8 JSON.
|
|
2
|
+
/** What a session store holds for one session, in bytes of UTF-8 JSON. A store with a real limit declares it. */
|
|
3
3
|
export interface TheoremSessionCapacity {
|
|
4
4
|
/** The most one session's saved state may take. */
|
|
5
5
|
maxStateBytes: number;
|
|
6
6
|
/** The most one tool result may take. Room for one is kept for each call that has not settled. */
|
|
7
7
|
maxOutcomeBytes: number;
|
|
8
8
|
}
|
|
9
|
-
/**
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
9
|
+
/**
|
|
10
|
+
* The store's declared capacity, refused as `config` unless both are positive and one result fits.
|
|
11
|
+
* Undefined when the store declares none: then it holds any size.
|
|
12
|
+
*/
|
|
13
|
+
export declare function checkedCapacity(capacity: unknown): TheoremSessionCapacity | undefined;
|
|
13
14
|
/**
|
|
14
15
|
* Fits the state in the store's capacity: drops the oldest settled results, then the oldest
|
|
15
16
|
* provider checkpoints, and refuses with `session.full` when open work alone does not fit.
|
package/server/session-limits.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import {
|
|
2
|
-
/**
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
};
|
|
7
|
-
/** The store's declared capacity, refused as `config` unless both are positive and one result fits. */
|
|
1
|
+
import { labelText, TheoremError } from '@theoremjs/agents';
|
|
2
|
+
/**
|
|
3
|
+
* The store's declared capacity, refused as `config` unless both are positive and one result fits.
|
|
4
|
+
* Undefined when the store declares none: then it holds any size.
|
|
5
|
+
*/
|
|
8
6
|
export function checkedCapacity(capacity) {
|
|
7
|
+
if (capacity === undefined)
|
|
8
|
+
return undefined;
|
|
9
9
|
const { maxStateBytes, maxOutcomeBytes } = (capacity ?? {});
|
|
10
10
|
if (!Number.isSafeInteger(maxStateBytes) ||
|
|
11
11
|
!Number.isSafeInteger(maxOutcomeBytes) ||
|
|
@@ -88,8 +88,11 @@ export type SessionWriteResult = {
|
|
|
88
88
|
* store (KV, Redis, a database row) when requests can reach different instances.
|
|
89
89
|
*/
|
|
90
90
|
export interface TheoremSessionStore {
|
|
91
|
-
/**
|
|
92
|
-
|
|
91
|
+
/**
|
|
92
|
+
* What it holds for one session, when it has a limit. The handler fits each write to it before
|
|
93
|
+
* `compareAndSwap`. Unset, the handler writes the state whole.
|
|
94
|
+
*/
|
|
95
|
+
readonly capacity?: TheoremSessionCapacity;
|
|
93
96
|
load(sessionId: string): Promise<SessionSnapshot | undefined>;
|
|
94
97
|
/** Compare and replace atomically; null creates only an absent session. */
|
|
95
98
|
compareAndSwap(sessionId: string, expectedRevision: string | null, next: TheoremSessionState): Promise<SessionWriteResult>;
|
|
@@ -101,8 +104,8 @@ export declare function pruneGates<Gate extends {
|
|
|
101
104
|
expiresAt?: number;
|
|
102
105
|
}>(gates: Record<string, Gate>, now: number, ttlMs: number): Record<string, Gate>;
|
|
103
106
|
export type MemorySessionStoreOptions = {
|
|
104
|
-
/** What it holds for one session.
|
|
105
|
-
capacity?:
|
|
107
|
+
/** What it holds for one session. Unset, it holds any size. */
|
|
108
|
+
capacity?: TheoremSessionCapacity;
|
|
106
109
|
/** invariant: Idle retention is in milliseconds. Protected authority remains. Default 24h. */
|
|
107
110
|
ttlMs?: number;
|
|
108
111
|
/** Oldest sessions are evicted past this count. Default 10 000. */
|
package/server/session-store.js
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
*/
|
|
11
11
|
import { jsonObjectSchema, jsonValueSchema, labelText, savedToolInvocationSchema, TheoremError, TOOL_AUTH_TYPES, TOOL_GATE_KINDS, TOOL_PERMISSION, toolOperationOutcomeSchema, turnHistoryMessageSchema, turnToolSnapshotSchema, z, } from '@theoremjs/agents';
|
|
12
12
|
import { gateExpired } from '@theoremjs/agents/kernel';
|
|
13
|
-
import { checkedCapacity
|
|
13
|
+
import { checkedCapacity } from "./session-limits.js";
|
|
14
14
|
export const DEFAULT_OPERATION_RETENTION_MS = 24 * 60 * 60 * 1000;
|
|
15
15
|
const blobSchema = z.strictObject({
|
|
16
16
|
data: z.string(),
|
|
@@ -219,7 +219,7 @@ export function createMemorySessionMap(options = {}) {
|
|
|
219
219
|
}
|
|
220
220
|
export function createMemorySessionStore(options = {}) {
|
|
221
221
|
const { ttlMs, maxSessions } = memoryStoreLimits(options);
|
|
222
|
-
const capacity = checkedCapacity(
|
|
222
|
+
const capacity = checkedCapacity(options.capacity);
|
|
223
223
|
const sessions = new Map();
|
|
224
224
|
const held = (entry) => Object.values(entry.snapshot.state.gates).some((gate) => gate.expiresAt === undefined || Date.now() < gate.expiresAt) ||
|
|
225
225
|
Object.values(entry.snapshot.state.operations).some((operation) => operation.status !== 'settled' ||
|
|
@@ -234,7 +234,7 @@ export function createMemorySessionStore(options = {}) {
|
|
|
234
234
|
return entry?.snapshot;
|
|
235
235
|
};
|
|
236
236
|
return {
|
|
237
|
-
capacity,
|
|
237
|
+
...(capacity ? { capacity } : {}),
|
|
238
238
|
load(sessionId) {
|
|
239
239
|
return Promise.resolve(structuredClone(current(sessionId)));
|
|
240
240
|
},
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { type ToolExecutionCoordinator } from '@theoremjs/agents';
|
|
2
2
|
import type { TheoremSessionState } from './session-store.ts';
|
|
3
3
|
export declare function sessionToolCoordinator(store: {
|
|
4
|
-
readonly capacity
|
|
4
|
+
readonly capacity?: {
|
|
5
5
|
maxOutcomeBytes: number;
|
|
6
6
|
};
|
|
7
7
|
mutate<T>(id: string, change: (state: TheoremSessionState) => T): Promise<T>;
|
|
@@ -69,7 +69,7 @@ function saveOutcome(state, identity, outcome) {
|
|
|
69
69
|
}
|
|
70
70
|
export function sessionToolCoordinator(store, sessionId) {
|
|
71
71
|
return {
|
|
72
|
-
maxOutcomeBytes: store.capacity.maxOutcomeBytes,
|
|
72
|
+
...(store.capacity ? { maxOutcomeBytes: store.capacity.maxOutcomeBytes } : {}),
|
|
73
73
|
lookup(identity) {
|
|
74
74
|
return store.mutate(sessionId, (state) => {
|
|
75
75
|
const record = checkedRecord(state, identity);
|