@iworkforces/tracelattice 2.0.6 → 2.0.7
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 +27 -0
- package/dist/cli.js +108 -32
- package/dist/core/compression/CompressionService.d.ts +4 -3
- package/dist/core/compression/CompressionService.d.ts.map +1 -1
- package/dist/core/compression/CompressionService.js +19 -10
- package/dist/core/compression/CompressionService.js.map +1 -1
- package/dist/core/compression/DehydrationPolicy.d.ts +4 -4
- package/dist/core/compression/DehydrationPolicy.d.ts.map +1 -1
- package/dist/core/compression/DehydrationPolicy.js +3 -6
- package/dist/core/compression/DehydrationPolicy.js.map +1 -1
- package/dist/lib.d.ts +6 -6
- package/dist/lib.d.ts.map +1 -1
- package/dist/lib.js +1 -0
- package/dist/lib.js.map +1 -1
- package/dist/transport/StreamableHttpTransport.d.ts +12 -0
- package/dist/transport/StreamableHttpTransport.d.ts.map +1 -1
- package/dist/transport/StreamableHttpTransport.js +95 -24
- package/dist/transport/StreamableHttpTransport.js.map +1 -1
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -204,6 +204,33 @@ Set `TRANSPORT_TYPE` to pick one:
|
|
|
204
204
|
|
|
205
205
|
The Streamable HTTP endpoint defaults to `POST /mcp` for JSON-RPC requests and supports stateful sessions via the `Mcp-Session-Id` header. In stateful mode, `GET /mcp` may expose `text/event-stream` notifications for that session. The library also exposes `HttpTransport` for stateless JSON-RPC over HTTP, but the CLI does not select it with `TRANSPORT_TYPE`.
|
|
206
206
|
|
|
207
|
+
### Stateless HTTP library API
|
|
208
|
+
|
|
209
|
+
Import the stateless transport from the package root. The package does not expose transport internals or deep import paths.
|
|
210
|
+
|
|
211
|
+
```typescript
|
|
212
|
+
import {
|
|
213
|
+
createHttpTransport,
|
|
214
|
+
type HttpTransportOptions,
|
|
215
|
+
type ITransport,
|
|
216
|
+
} from '@iworkforces/tracelattice';
|
|
217
|
+
import type { McpServer } from 'tmcp';
|
|
218
|
+
|
|
219
|
+
const options: HttpTransportOptions = {
|
|
220
|
+
host: '127.0.0.1',
|
|
221
|
+
port: 9108,
|
|
222
|
+
path: '/messages',
|
|
223
|
+
};
|
|
224
|
+
|
|
225
|
+
export async function startHttpTransport(mcpServer: McpServer): Promise<ITransport> {
|
|
226
|
+
const transport = createHttpTransport(options);
|
|
227
|
+
await transport.connect(mcpServer);
|
|
228
|
+
return transport;
|
|
229
|
+
}
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
Call and await `transport.stop()` during application shutdown.
|
|
233
|
+
|
|
207
234
|
## Development
|
|
208
235
|
|
|
209
236
|
```bash
|
package/dist/cli.js
CHANGED
|
@@ -1993,6 +1993,20 @@ class AcceptedWorkTracker {
|
|
|
1993
1993
|
|
|
1994
1994
|
|
|
1995
1995
|
|
|
1996
|
+
function parseSessionRetentionOptions(options) {
|
|
1997
|
+
const { maxSessions, sessionIdleTimeoutMs, sessionSweepIntervalMs } = options;
|
|
1998
|
+
if (maxSessions === undefined && sessionIdleTimeoutMs === undefined && sessionSweepIntervalMs === undefined) {
|
|
1999
|
+
return null;
|
|
2000
|
+
}
|
|
2001
|
+
if (maxSessions === undefined || !Number.isFinite(maxSessions) || !Number.isInteger(maxSessions) || maxSessions <= 0 || sessionIdleTimeoutMs === undefined || !Number.isFinite(sessionIdleTimeoutMs) || !Number.isInteger(sessionIdleTimeoutMs) || sessionIdleTimeoutMs <= 0 || sessionSweepIntervalMs === undefined || !Number.isFinite(sessionSweepIntervalMs) || !Number.isInteger(sessionSweepIntervalMs) || sessionSweepIntervalMs <= 0) {
|
|
2002
|
+
throw new TypeError('maxSessions, sessionIdleTimeoutMs, and sessionSweepIntervalMs must be provided together as positive integers');
|
|
2003
|
+
}
|
|
2004
|
+
return {
|
|
2005
|
+
maxSessions,
|
|
2006
|
+
sessionIdleTimeoutMs,
|
|
2007
|
+
sessionSweepIntervalMs
|
|
2008
|
+
};
|
|
2009
|
+
}
|
|
1996
2010
|
/**
|
|
1997
2011
|
* Streamable HTTP Transport for MCP server.
|
|
1998
2012
|
*
|
|
@@ -2046,8 +2060,11 @@ class AcceptedWorkTracker {
|
|
|
2046
2060
|
_metricsProvider;
|
|
2047
2061
|
_lifecycleFailureReporter;
|
|
2048
2062
|
_acceptedWork;
|
|
2063
|
+
_sessionRetention;
|
|
2064
|
+
_sessionSweepIntervalId = null;
|
|
2049
2065
|
_stopPromise = null;
|
|
2050
2066
|
constructor(options = {}){
|
|
2067
|
+
const sessionRetention = parseSessionRetentionOptions(options);
|
|
2051
2068
|
super(options);
|
|
2052
2069
|
this._path = options.path ?? '/mcp';
|
|
2053
2070
|
this._stateful = options.stateful ?? true;
|
|
@@ -2057,12 +2074,17 @@ class AcceptedWorkTracker {
|
|
|
2057
2074
|
this._requestTimeout = options.requestTimeout ?? 30000;
|
|
2058
2075
|
this._metrics = options.metrics;
|
|
2059
2076
|
this._metricsProvider = options.metricsProvider ?? null;
|
|
2077
|
+
this._sessionRetention = sessionRetention;
|
|
2060
2078
|
this._lifecycleFailureReporter = new LifecycleFailureReporter((error)=>{
|
|
2061
2079
|
this.log('error', 'Streamable HTTP request lifecycle failed', {
|
|
2062
2080
|
error: (0,errors/* .getErrorMessage */.u1)(error)
|
|
2063
2081
|
});
|
|
2064
2082
|
});
|
|
2065
2083
|
this._acceptedWork = new AcceptedWorkTracker(this._lifecycleFailureReporter);
|
|
2084
|
+
if (this._stateful && sessionRetention) {
|
|
2085
|
+
this._sessionSweepIntervalId = setInterval(()=>this._sweepExpiredSessions(), sessionRetention.sessionSweepIntervalMs);
|
|
2086
|
+
this._sessionSweepIntervalId.unref();
|
|
2087
|
+
}
|
|
2066
2088
|
}
|
|
2067
2089
|
_requireMcpServer() {
|
|
2068
2090
|
if (!this._mcpServer) {
|
|
@@ -2234,6 +2256,7 @@ class AcceptedWorkTracker {
|
|
|
2234
2256
|
this._requestCount++;
|
|
2235
2257
|
this._activeRequests++;
|
|
2236
2258
|
const responseFinalizer = new ResponseFinalizer(res, this._lifecycleFailureReporter);
|
|
2259
|
+
let acceptedSession = null;
|
|
2237
2260
|
const timeout = setTimeout(()=>{
|
|
2238
2261
|
responseFinalizer.finalize((response)=>{
|
|
2239
2262
|
this._sendJsonRpcError(response, 500, -32603, 'Request timeout');
|
|
@@ -2270,18 +2293,9 @@ class AcceptedWorkTracker {
|
|
|
2270
2293
|
return;
|
|
2271
2294
|
}
|
|
2272
2295
|
const jsonRpcRequest = parseResult.output;
|
|
2273
|
-
|
|
2274
|
-
|
|
2275
|
-
|
|
2276
|
-
const sessionResult = this._resolveSession(req);
|
|
2277
|
-
if (typeof sessionResult !== 'string') {
|
|
2278
|
-
responseFinalizer.finalize((response)=>{
|
|
2279
|
-
this._sendJsonRpcError(response, sessionResult.statusCode, sessionResult.code, sessionResult.message);
|
|
2280
|
-
});
|
|
2281
|
-
return;
|
|
2282
|
-
}
|
|
2283
|
-
sessionId = sessionResult;
|
|
2284
|
-
}
|
|
2296
|
+
const session = this._acceptPostSession(req, responseFinalizer);
|
|
2297
|
+
if (!session) return;
|
|
2298
|
+
acceptedSession = session.state;
|
|
2285
2299
|
// Check if MCP server is ready
|
|
2286
2300
|
if (!this._mcpServer) {
|
|
2287
2301
|
responseFinalizer.finalize((response)=>{
|
|
@@ -2289,7 +2303,7 @@ class AcceptedWorkTracker {
|
|
|
2289
2303
|
});
|
|
2290
2304
|
return;
|
|
2291
2305
|
}
|
|
2292
|
-
await this._receiveAndFinalize(jsonRpcRequest,
|
|
2306
|
+
await this._receiveAndFinalize(jsonRpcRequest, session.id, responseFinalizer);
|
|
2293
2307
|
} catch (error) {
|
|
2294
2308
|
responseFinalizer.finalize((response)=>{
|
|
2295
2309
|
this._sendJsonRpcError(response, 200, -32603, 'Internal error', null, {
|
|
@@ -2297,10 +2311,35 @@ class AcceptedWorkTracker {
|
|
|
2297
2311
|
});
|
|
2298
2312
|
});
|
|
2299
2313
|
} finally{
|
|
2314
|
+
if (acceptedSession) acceptedSession.acceptedPostCount--;
|
|
2300
2315
|
clearTimeout(timeout);
|
|
2301
2316
|
this._activeRequests--;
|
|
2302
2317
|
}
|
|
2303
2318
|
}
|
|
2319
|
+
_acceptPostSession(req, responseFinalizer) {
|
|
2320
|
+
if (!this._stateful) return {
|
|
2321
|
+
id: undefined,
|
|
2322
|
+
state: null
|
|
2323
|
+
};
|
|
2324
|
+
if (this.isShuttingDown) {
|
|
2325
|
+
responseFinalizer.finalize((response)=>{
|
|
2326
|
+
this._sendJsonRpcError(response, 503, -32603, 'Server is shutting down');
|
|
2327
|
+
});
|
|
2328
|
+
return null;
|
|
2329
|
+
}
|
|
2330
|
+
const session = this._resolveSession(req);
|
|
2331
|
+
if (!('state' in session)) {
|
|
2332
|
+
responseFinalizer.finalize((response)=>{
|
|
2333
|
+
this._sendJsonRpcError(response, session.statusCode, session.code, session.message);
|
|
2334
|
+
});
|
|
2335
|
+
return null;
|
|
2336
|
+
}
|
|
2337
|
+
session.state.acceptedPostCount++;
|
|
2338
|
+
return {
|
|
2339
|
+
id: session.id,
|
|
2340
|
+
state: session.state
|
|
2341
|
+
};
|
|
2342
|
+
}
|
|
2304
2343
|
async _receiveAndFinalize(jsonRpcRequest, sessionId, responseFinalizer) {
|
|
2305
2344
|
const owner = this._stateful ? sessionId ?? (0,__rspack_external_node_crypto_2e7c4b46.randomUUID)() : (0,__rspack_external_node_crypto_2e7c4b46.randomUUID)();
|
|
2306
2345
|
const response = await (0,RequestContext/* .runWithContext */.Vo)({
|
|
@@ -2378,6 +2417,7 @@ class AcceptedWorkTracker {
|
|
|
2378
2417
|
}));
|
|
2379
2418
|
return;
|
|
2380
2419
|
}
|
|
2420
|
+
session.lastActivityAt = Date.now();
|
|
2381
2421
|
// Set SSE headers
|
|
2382
2422
|
res.writeHead(200, {
|
|
2383
2423
|
'Content-Type': 'text/event-stream',
|
|
@@ -2392,7 +2432,6 @@ class AcceptedWorkTracker {
|
|
|
2392
2432
|
});
|
|
2393
2433
|
// Track this notification stream
|
|
2394
2434
|
session.notificationStreams.add(res);
|
|
2395
|
-
session.lastActivityAt = Date.now();
|
|
2396
2435
|
this._updateSessionMetrics();
|
|
2397
2436
|
// Handle client disconnect
|
|
2398
2437
|
req.on('close', ()=>{
|
|
@@ -2419,7 +2458,10 @@ class AcceptedWorkTracker {
|
|
|
2419
2458
|
const session = this._sessions.get(asSessionId(headerSessionId));
|
|
2420
2459
|
if (session) {
|
|
2421
2460
|
session.lastActivityAt = Date.now();
|
|
2422
|
-
return
|
|
2461
|
+
return {
|
|
2462
|
+
id: session.id,
|
|
2463
|
+
state: session
|
|
2464
|
+
};
|
|
2423
2465
|
}
|
|
2424
2466
|
// Unknown session ID — per spec, return 404
|
|
2425
2467
|
return {
|
|
@@ -2429,17 +2471,59 @@ class AcceptedWorkTracker {
|
|
|
2429
2471
|
};
|
|
2430
2472
|
}
|
|
2431
2473
|
// No session header — create new session
|
|
2432
|
-
|
|
2474
|
+
if (this._sessionRetention && this._sessions.size >= this._sessionRetention.maxSessions) {
|
|
2475
|
+
return {
|
|
2476
|
+
statusCode: 503,
|
|
2477
|
+
code: -32000,
|
|
2478
|
+
message: 'Session capacity reached'
|
|
2479
|
+
};
|
|
2480
|
+
}
|
|
2481
|
+
const newSessionId = asSessionId(this._sessionIdGenerator());
|
|
2482
|
+
const now = Date.now();
|
|
2433
2483
|
const sessionState = {
|
|
2434
2484
|
id: newSessionId,
|
|
2435
|
-
createdAt:
|
|
2436
|
-
lastActivityAt:
|
|
2437
|
-
notificationStreams: new Set()
|
|
2485
|
+
createdAt: now,
|
|
2486
|
+
lastActivityAt: now,
|
|
2487
|
+
notificationStreams: new Set(),
|
|
2488
|
+
acceptedPostCount: 0
|
|
2438
2489
|
};
|
|
2439
|
-
this._sessions.set(
|
|
2490
|
+
this._sessions.set(newSessionId, sessionState);
|
|
2440
2491
|
this.log('info', `New session created: ${newSessionId}`);
|
|
2441
2492
|
this._updateSessionMetrics();
|
|
2442
|
-
return
|
|
2493
|
+
return {
|
|
2494
|
+
id: newSessionId,
|
|
2495
|
+
state: sessionState
|
|
2496
|
+
};
|
|
2497
|
+
}
|
|
2498
|
+
_sweepExpiredSessions() {
|
|
2499
|
+
if (!this._sessionRetention) return;
|
|
2500
|
+
const now = Date.now();
|
|
2501
|
+
for (const [sessionId, session] of this._sessions){
|
|
2502
|
+
if (session.acceptedPostCount === 0 && now - session.lastActivityAt >= this._sessionRetention.sessionIdleTimeoutMs) {
|
|
2503
|
+
this._disposeSession(sessionId);
|
|
2504
|
+
}
|
|
2505
|
+
}
|
|
2506
|
+
}
|
|
2507
|
+
_disposeSession(sessionId) {
|
|
2508
|
+
const session = this._sessions.get(sessionId);
|
|
2509
|
+
if (!session) return;
|
|
2510
|
+
this._sessions.delete(sessionId);
|
|
2511
|
+
for (const stream of session.notificationStreams){
|
|
2512
|
+
try {
|
|
2513
|
+
stream.end();
|
|
2514
|
+
} catch (error) {
|
|
2515
|
+
this._lifecycleFailureReporter.report(error);
|
|
2516
|
+
}
|
|
2517
|
+
}
|
|
2518
|
+
session.notificationStreams.clear();
|
|
2519
|
+
this._updateSessionMetrics();
|
|
2520
|
+
}
|
|
2521
|
+
_stopSessionSweep() {
|
|
2522
|
+
const interval = this._sessionSweepIntervalId;
|
|
2523
|
+
if (!interval) return;
|
|
2524
|
+
interval.unref();
|
|
2525
|
+
clearInterval(interval);
|
|
2526
|
+
this._sessionSweepIntervalId = null;
|
|
2443
2527
|
}
|
|
2444
2528
|
/**
|
|
2445
2529
|
* Extract Mcp-Session-Id from request headers.
|
|
@@ -2547,19 +2631,11 @@ class AcceptedWorkTracker {
|
|
|
2547
2631
|
if (this._stopPromise) return this._stopPromise;
|
|
2548
2632
|
this._isShuttingDown = true;
|
|
2549
2633
|
this._stopRateLimitCleanup();
|
|
2634
|
+
this._stopSessionSweep();
|
|
2550
2635
|
const shutdownTimeout = timeout ?? 30000;
|
|
2551
|
-
|
|
2552
|
-
|
|
2553
|
-
for (const stream of session.notificationStreams){
|
|
2554
|
-
try {
|
|
2555
|
-
stream.end();
|
|
2556
|
-
} catch {
|
|
2557
|
-
// Ignore errors
|
|
2558
|
-
}
|
|
2559
|
-
}
|
|
2560
|
-
session.notificationStreams.clear();
|
|
2636
|
+
for (const sessionId of this._sessions.keys()){
|
|
2637
|
+
this._disposeSession(sessionId);
|
|
2561
2638
|
}
|
|
2562
|
-
this._sessions.clear();
|
|
2563
2639
|
const server = this._server;
|
|
2564
2640
|
const serverClosed = new Promise((resolve, reject)=>{
|
|
2565
2641
|
if (!server?.listening) {
|
|
@@ -51,10 +51,11 @@ export declare class CompressionService {
|
|
|
51
51
|
/** Collect the root and all of its descendants (chronological BFS). */
|
|
52
52
|
private _collectCovered;
|
|
53
53
|
/**
|
|
54
|
-
* Resolve
|
|
55
|
-
*
|
|
54
|
+
* Resolve candidate ids against one stable session snapshot. Main-history
|
|
55
|
+
* records take precedence over branch copies; branch-only records are added
|
|
56
|
+
* in declared branch order. Graph ids absent from the snapshot are omitted.
|
|
56
57
|
*/
|
|
57
|
-
private
|
|
58
|
+
private _resolveThoughts;
|
|
58
59
|
/**
|
|
59
60
|
* Mean of (`calibrated_confidence` ?? `confidence` ?? 0) across covered.
|
|
60
61
|
* Returns 0 when no thoughts are covered.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CompressionService.d.ts","sourceRoot":"","sources":["../../../src/core/compression/CompressionService.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,OAAO,EAAE,MAAM,4BAA4B,CAAC;AACzE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAChE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,kCAAkC,CAAC;AAC/D,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"CompressionService.d.ts","sourceRoot":"","sources":["../../../src/core/compression/CompressionService.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,OAAO,EAAE,MAAM,4BAA4B,CAAC;AACzE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAChE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,kCAAkC,CAAC;AAC/D,OAAO,KAAK,EAA0B,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAKrF,OAAO,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAiB7E,2DAA2D;AAC3D,MAAM,WAAW,eAAe;IAC/B,QAAQ,CAAC,cAAc,EAAE,eAAe,CAAC;IACzC,QAAQ,CAAC,SAAS,EAAE,UAAU,CAAC;IAC/B,QAAQ,CAAC,YAAY,EAAE,aAAa,CAAC;IACrC,QAAQ,CAAC,gBAAgB,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;IACvD,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;CACzB;AAED;;;;;;;;GAQG;AACH,qBAAa,kBAAkB;IAC9B,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAkB;IACxC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAY;gBAEvB,IAAI,EAAE,eAAe;IAKjC;;;;;;OAMG;IACH,cAAc,CAAC,SAAS,EAAE,SAAS,EAAE,QAAQ,EAAE,QAAQ,EAAE,aAAa,EAAE,SAAS,GAAG,OAAO;IAkC3F,uEAAuE;IACvE,OAAO,CAAC,oBAAoB;IAW5B,uEAAuE;IACvE,OAAO,CAAC,eAAe;IAKvB;;;;OAIG;IACH,OAAO,CAAC,gBAAgB;IA0BxB;;;OAGG;IACH,OAAO,CAAC,eAAe;IAWvB;;;OAGG;IACH,OAAO,CAAC,aAAa;IAYrB;;;OAGG;IACH,OAAO,CAAC,cAAc;IAsBtB,8EAA8E;IAC9E,OAAO,CAAC,eAAe;CAMvB"}
|
|
@@ -56,8 +56,12 @@ class CompressionService {
|
|
|
56
56
|
compressBranch(sessionId, branchId, rootThoughtId) {
|
|
57
57
|
const existing = this._findExistingForRoot(sessionId, branchId, rootThoughtId);
|
|
58
58
|
if (existing) return existing;
|
|
59
|
-
const
|
|
60
|
-
const
|
|
59
|
+
const snapshot = this._deps.historyManager.inspectSession(sessionId);
|
|
60
|
+
const candidateIds = this._collectCovered(sessionId, rootThoughtId);
|
|
61
|
+
const thoughts = this._resolveThoughts(snapshot, candidateIds);
|
|
62
|
+
const coveredIds = thoughts.flatMap((thought)=>void 0 === thought.id ? [] : [
|
|
63
|
+
thought.id
|
|
64
|
+
]);
|
|
61
65
|
const summary = {
|
|
62
66
|
id: generateUlid(),
|
|
63
67
|
sessionId,
|
|
@@ -90,16 +94,21 @@ class CompressionService {
|
|
|
90
94
|
...descendants
|
|
91
95
|
];
|
|
92
96
|
}
|
|
93
|
-
|
|
94
|
-
const history = this._deps.historyManager.getHistory(sessionId);
|
|
97
|
+
_resolveThoughts(snapshot, candidateIds) {
|
|
95
98
|
const byId = new Map();
|
|
96
|
-
for (const
|
|
97
|
-
const
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
99
|
+
for (const thought of snapshot.history)if (void 0 !== thought.id && !byId.has(thought.id)) byId.set(thought.id, thought);
|
|
100
|
+
for (const branchId of snapshot.branchIds)for (const thought of snapshot.branches[branchId] ?? [])if (void 0 !== thought.id && !byId.has(thought.id)) byId.set(thought.id, thought);
|
|
101
|
+
const resolved = [];
|
|
102
|
+
const seen = new Set();
|
|
103
|
+
for (const id of candidateIds){
|
|
104
|
+
if (seen.has(id)) continue;
|
|
105
|
+
const thought = byId.get(id);
|
|
106
|
+
if (void 0 !== thought) {
|
|
107
|
+
seen.add(id);
|
|
108
|
+
resolved.push(thought);
|
|
109
|
+
}
|
|
101
110
|
}
|
|
102
|
-
return
|
|
111
|
+
return resolved;
|
|
103
112
|
}
|
|
104
113
|
_meanConfidence(thoughts) {
|
|
105
114
|
if (0 === thoughts.length) return 0;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"core/compression/CompressionService.js","sources":["../../../src/core/compression/CompressionService.ts"],"sourcesContent":["/**\n * CompressionService — deterministic branch summarization.\n *\n * Compresses a terminated branch (or any subtree rooted at a thought) into a\n * single {@link Summary} record. Pure offline computation: no LLM, no I/O.\n *\n * Topic extraction is unigram frequency with stopword filtering; aggregate\n * confidence is the arithmetic mean of per-thought calibrated (or raw)\n * confidence values. The covered set is identified via\n * {@link GraphView.descendants}. Compression is **additive**: original\n * thoughts are never mutated or deleted.\n *\n * @module core/compression/CompressionService\n */\n\nimport type { ISummaryStore, Summary } from '../../contracts/summary.js';\nimport type { IEdgeStore } from '../../contracts/interfaces.js';\nimport type { Logger } from '../../logger/StructuredLogger.js';\nimport type { IHistoryManager } from '../IHistoryManager.js';\nimport type { ThoughtData } from '../thought.js';\nimport type { ConfidenceSignals } from '../reasoning.js';\nimport { GraphView } from '../graph/GraphView.js';\nimport { generateUlid } from '../ids.js';\nimport type { BranchId, SessionId, ThoughtId } from '../../contracts/ids.js';\n\n/** Stopwords excluded from topic extraction (lowercase). */\nconst STOPWORDS: ReadonlySet<string> = new Set([\n\t'the', 'this', 'that', 'then', 'than', 'with', 'from', 'have', 'will', 'been',\n\t'they', 'them', 'their', 'there', 'about', 'would', 'could', 'should', 'which',\n\t'where', 'when', 'what', 'some', 'into', 'also', 'just', 'like', 'over', 'such',\n\t'after', 'only', 'most', 'very', 'much', 'well', 'even', 'still', 'since',\n\t'being', 'doing', 'going', 'using',\n]);\n\nconst MIN_TOKEN_LENGTH = 4;\nconst TOP_TOPICS = 3;\n\n/** Local view of {@link ThoughtData} that exposes optional confidence signals. */\ntype ThoughtWithSignals = ThoughtData & { readonly confidence_signals?: ConfidenceSignals };\n\n/** Dependencies required by {@link CompressionService}. */\nexport interface CompressionDeps {\n\treadonly historyManager: IHistoryManager;\n\treadonly edgeStore: IEdgeStore;\n\treadonly summaryStore: ISummaryStore;\n\treadonly onSummaryCreated?: (summary: Summary) => void;\n\treadonly logger?: Logger;\n}\n\n/**\n * Deterministic, offline compression of branch subtrees into {@link Summary}.\n *\n * @example\n * ```typescript\n * const svc = new CompressionService({ historyManager, edgeStore, summaryStore });\n * const summary = svc.compressBranch('s1', 'alt-1', 'thought-root');\n * ```\n */\nexport class CompressionService {\n\tprivate readonly _deps: CompressionDeps;\n\tprivate readonly _graph: GraphView;\n\n\tconstructor(deps: CompressionDeps) {\n\t\tthis._deps = deps;\n\t\tthis._graph = new GraphView(deps.edgeStore);\n\t}\n\n\t/**\n\t * Compress the subtree rooted at `rootThoughtId` into a {@link Summary}.\n\t *\n\t * Idempotency: if a summary for the same `(branchId, rootThoughtId)` already\n\t * exists in the store, the existing summary is returned unchanged — same\n\t * inputs always yield the same Summary identity.\n\t */\n\tcompressBranch(sessionId: SessionId, branchId: BranchId, rootThoughtId: ThoughtId): Summary {\n\t\tconst existing = this._findExistingForRoot(sessionId, branchId, rootThoughtId);\n\t\tif (existing) return existing;\n\n\t\tconst coveredIds = this._collectCovered(sessionId, rootThoughtId);\n\t\tconst thoughts = this._lookupThoughts(sessionId, coveredIds);\n\t\tconst summary: Summary = {\n\t\t\tid: generateUlid(),\n\t\t\tsessionId,\n\t\t\tbranchId,\n\t\t\trootThoughtId,\n\t\t\tcoveredIds,\n\t\t\tcoveredRange: this._coveredRange(thoughts),\n\t\t\ttopics: this._extractTopics(thoughts),\n\t\t\taggregateConfidence: this._meanConfidence(thoughts),\n\t\t\tcreatedAt: Date.now(),\n\t\t};\n\n\t\tthis._deps.summaryStore.add(summary);\n\t\tthis._deps.onSummaryCreated?.(summary);\n\t\tthis._deps.logger?.debug('compression.branch.compressed', {\n\t\t\tsessionId,\n\t\t\tbranchId,\n\t\t\trootThoughtId,\n\t\t\tcovered: coveredIds.length,\n\t\t\ttopics: summary.topics,\n\t\t});\n\t\treturn summary;\n\t}\n\n\t/** Look up an existing summary on this branch with a matching root. */\n\tprivate _findExistingForRoot(\n\t\tsessionId: SessionId,\n\t\tbranchId: BranchId,\n\t\trootThoughtId: ThoughtId\n\t): Summary | undefined {\n\t\tfor (const s of this._deps.summaryStore.forBranch(sessionId, branchId)) {\n\t\t\tif (s.rootThoughtId === rootThoughtId) return s;\n\t\t}\n\t\treturn undefined;\n\t}\n\n\t/** Collect the root and all of its descendants (chronological BFS). */\n\tprivate _collectCovered(sessionId: SessionId, rootThoughtId: ThoughtId): readonly ThoughtId[] {\n\t\tconst descendants = this._graph.descendants(sessionId, rootThoughtId);\n\t\treturn [rootThoughtId, ...descendants];\n\t}\n\n\t/**\n\t * Resolve covered ids to {@link ThoughtData}, dropping any not found in\n\t * the history (defensive — graph may reference evicted thoughts).\n\t */\n\tprivate _lookupThoughts(sessionId: SessionId, coveredIds: readonly ThoughtId[]): ThoughtData[] {\n\t\tconst history = this._deps.historyManager.getHistory(sessionId);\n\t\tconst byId = new Map<string, ThoughtData>();\n\t\tfor (const t of history) {\n\t\t\tif (t.id !== undefined) byId.set(t.id, t);\n\t\t}\n\t\tconst out: ThoughtData[] = [];\n\t\tfor (const id of coveredIds) {\n\t\t\tconst t = byId.get(id);\n\t\t\tif (t) out.push(t);\n\t\t}\n\t\treturn out;\n\t}\n\n\t/**\n\t * Mean of (`calibrated_confidence` ?? `confidence` ?? 0) across covered.\n\t * Returns 0 when no thoughts are covered.\n\t */\n\tprivate _meanConfidence(thoughts: readonly ThoughtData[]): number {\n\t\tif (thoughts.length === 0) return 0;\n\t\tlet sum = 0;\n\t\tfor (const t of thoughts) {\n\t\t\tconst withSignals = t as ThoughtWithSignals;\n\t\t\tconst calibrated = withSignals.confidence_signals?.calibrated_confidence;\n\t\t\tsum += calibrated ?? t.confidence ?? 0;\n\t\t}\n\t\treturn sum / thoughts.length;\n\t}\n\n\t/**\n\t * Inclusive `[min, max]` of `thought_number` across covered thoughts.\n\t * Returns `[0, 0]` when no thoughts are covered.\n\t */\n\tprivate _coveredRange(thoughts: readonly ThoughtData[]): readonly [number, number] {\n\t\tif (thoughts.length === 0) return [0, 0];\n\t\tlet min = Number.POSITIVE_INFINITY;\n\t\tlet max = Number.NEGATIVE_INFINITY;\n\t\tfor (const t of thoughts) {\n\t\t\tconst n = t.thought_number;\n\t\t\tif (n < min) min = n;\n\t\t\tif (n > max) max = n;\n\t\t}\n\t\treturn [min, max];\n\t}\n\n\t/**\n\t * Extract top-3 unigrams by frequency from concatenated thought text.\n\t * Ties broken by first-occurrence order (stable).\n\t */\n\tprivate _extractTopics(thoughts: readonly ThoughtData[]): readonly string[] {\n\t\tif (thoughts.length === 0) return [];\n\t\tconst counts = new Map<string, number>();\n\t\tconst order = new Map<string, number>();\n\t\tlet position = 0;\n\t\tfor (const t of thoughts) {\n\t\t\tfor (const raw of (t.thought ?? '').split(/\\s+/)) {\n\t\t\t\tconst token = this._normalizeToken(raw);\n\t\t\t\tif (token === null) continue;\n\t\t\t\tif (!counts.has(token)) order.set(token, position++);\n\t\t\t\tcounts.set(token, (counts.get(token) ?? 0) + 1);\n\t\t\t}\n\t\t}\n\t\tif (counts.size === 0) return [];\n\t\tconst entries = Array.from(counts.entries());\n\t\tentries.sort((a, b) => {\n\t\t\tif (b[1] !== a[1]) return b[1] - a[1];\n\t\t\treturn (order.get(a[0]) ?? 0) - (order.get(b[0]) ?? 0);\n\t\t});\n\t\treturn entries.slice(0, TOP_TOPICS).map(([word]) => word);\n\t}\n\n\t/** Lowercase + strip non-alphanumerics; reject if too short or a stopword. */\n\tprivate _normalizeToken(raw: string): string | null {\n\t\tconst cleaned = raw.toLowerCase().replace(/[^a-z0-9]+/g, '');\n\t\tif (cleaned.length < MIN_TOKEN_LENGTH) return null;\n\t\tif (STOPWORDS.has(cleaned)) return null;\n\t\treturn cleaned;\n\t}\n}\n"],"names":["STOPWORDS","Set","MIN_TOKEN_LENGTH","TOP_TOPICS","CompressionService","deps","GraphView","sessionId","branchId","rootThoughtId","existing","coveredIds","thoughts","summary","generateUlid","Date","s","descendants","history","byId","Map","t","undefined","out","id","sum","withSignals","calibrated","min","Number","max","n","counts","order","position","raw","token","entries","Array","a","b","word","cleaned"],"mappings":";;AA0BA,MAAMA,YAAiC,IAAIC,IAAI;IAC9C;IAAO;IAAQ;IAAQ;IAAQ;IAAQ;IAAQ;IAAQ;IAAQ;IAAQ;IACvE;IAAQ;IAAQ;IAAS;IAAS;IAAS;IAAS;IAAS;IAAU;IACvE;IAAS;IAAQ;IAAQ;IAAQ;IAAQ;IAAQ;IAAQ;IAAQ;IAAQ;IACzE;IAAS;IAAQ;IAAQ;IAAQ;IAAQ;IAAQ;IAAQ;IAAS;IAClE;IAAS;IAAS;IAAS;CAC3B;AAED,MAAMC,mBAAmB;AACzB,MAAMC,aAAa;AAuBZ,MAAMC;IACK,MAAuB;IACvB,OAAkB;IAEnC,YAAYC,IAAqB,CAAE;QAClC,IAAI,CAAC,KAAK,GAAGA;QACb,IAAI,CAAC,MAAM,GAAG,IAAIC,UAAUD,KAAK,SAAS;IAC3C;IASA,eAAeE,SAAoB,EAAEC,QAAkB,EAAEC,aAAwB,EAAW;QAC3F,MAAMC,WAAW,IAAI,CAAC,oBAAoB,CAACH,WAAWC,UAAUC;QAChE,IAAIC,UAAU,OAAOA;QAErB,MAAMC,aAAa,IAAI,CAAC,eAAe,CAACJ,WAAWE;QACnD,MAAMG,WAAW,IAAI,CAAC,eAAe,CAACL,WAAWI;QACjD,MAAME,UAAmB;YACxB,IAAIC;YACJP;YACAC;YACAC;YACAE;YACA,cAAc,IAAI,CAAC,aAAa,CAACC;YACjC,QAAQ,IAAI,CAAC,cAAc,CAACA;YAC5B,qBAAqB,IAAI,CAAC,eAAe,CAACA;YAC1C,WAAWG,KAAK,GAAG;QACpB;QAEA,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,GAAG,CAACF;QAC5B,IAAI,CAAC,KAAK,CAAC,gBAAgB,GAAGA;QAC9B,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,MAAM,iCAAiC;YACzDN;YACAC;YACAC;YACA,SAASE,WAAW,MAAM;YAC1B,QAAQE,QAAQ,MAAM;QACvB;QACA,OAAOA;IACR;IAGQ,qBACPN,SAAoB,EACpBC,QAAkB,EAClBC,aAAwB,EACF;QACtB,KAAK,MAAMO,KAAK,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,SAAS,CAACT,WAAWC,UAC5D,IAAIQ,EAAE,aAAa,KAAKP,eAAe,OAAOO;IAGhD;IAGQ,gBAAgBT,SAAoB,EAAEE,aAAwB,EAAwB;QAC7F,MAAMQ,cAAc,IAAI,CAAC,MAAM,CAAC,WAAW,CAACV,WAAWE;QACvD,OAAO;YAACA;eAAkBQ;SAAY;IACvC;IAMQ,gBAAgBV,SAAoB,EAAEI,UAAgC,EAAiB;QAC9F,MAAMO,UAAU,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,UAAU,CAACX;QACrD,MAAMY,OAAO,IAAIC;QACjB,KAAK,MAAMC,KAAKH,QACf,IAAIG,AAASC,WAATD,EAAE,EAAE,EAAgBF,KAAK,GAAG,CAACE,EAAE,EAAE,EAAEA;QAExC,MAAME,MAAqB,EAAE;QAC7B,KAAK,MAAMC,MAAMb,WAAY;YAC5B,MAAMU,IAAIF,KAAK,GAAG,CAACK;YACnB,IAAIH,GAAGE,IAAI,IAAI,CAACF;QACjB;QACA,OAAOE;IACR;IAMQ,gBAAgBX,QAAgC,EAAU;QACjE,IAAIA,AAAoB,MAApBA,SAAS,MAAM,EAAQ,OAAO;QAClC,IAAIa,MAAM;QACV,KAAK,MAAMJ,KAAKT,SAAU;YACzB,MAAMc,cAAcL;YACpB,MAAMM,aAAaD,YAAY,kBAAkB,EAAE;YACnDD,OAAOE,cAAcN,EAAE,UAAU,IAAI;QACtC;QACA,OAAOI,MAAMb,SAAS,MAAM;IAC7B;IAMQ,cAAcA,QAAgC,EAA6B;QAClF,IAAIA,AAAoB,MAApBA,SAAS,MAAM,EAAQ,OAAO;YAAC;YAAG;SAAE;QACxC,IAAIgB,MAAMC,KAAwB;QAClC,IAAIC,MAAMD,MAAwB;QAClC,KAAK,MAAMR,KAAKT,SAAU;YACzB,MAAMmB,IAAIV,EAAE,cAAc;YAC1B,IAAIU,IAAIH,KAAKA,MAAMG;YACnB,IAAIA,IAAID,KAAKA,MAAMC;QACpB;QACA,OAAO;YAACH;YAAKE;SAAI;IAClB;IAMQ,eAAelB,QAAgC,EAAqB;QAC3E,IAAIA,AAAoB,MAApBA,SAAS,MAAM,EAAQ,OAAO,EAAE;QACpC,MAAMoB,SAAS,IAAIZ;QACnB,MAAMa,QAAQ,IAAIb;QAClB,IAAIc,WAAW;QACf,KAAK,MAAMb,KAAKT,SACf,KAAK,MAAMuB,OAAQd,AAAAA,CAAAA,EAAE,OAAO,IAAI,EAAC,EAAG,KAAK,CAAC,OAAQ;YACjD,MAAMe,QAAQ,IAAI,CAAC,eAAe,CAACD;YACnC,IAAIC,AAAU,SAAVA;gBACJ,IAAI,CAACJ,OAAO,GAAG,CAACI,QAAQH,MAAM,GAAG,CAACG,OAAOF;gBACzCF,OAAO,GAAG,CAACI,OAAQJ,AAAAA,CAAAA,OAAO,GAAG,CAACI,UAAU,KAAK;;QAC9C;QAED,IAAIJ,AAAgB,MAAhBA,OAAO,IAAI,EAAQ,OAAO,EAAE;QAChC,MAAMK,UAAUC,MAAM,IAAI,CAACN,OAAO,OAAO;QACzCK,QAAQ,IAAI,CAAC,CAACE,GAAGC;YAChB,IAAIA,CAAC,CAAC,EAAE,KAAKD,CAAC,CAAC,EAAE,EAAE,OAAOC,CAAC,CAAC,EAAE,GAAGD,CAAC,CAAC,EAAE;YACrC,OAAQN,AAAAA,CAAAA,MAAM,GAAG,CAACM,CAAC,CAAC,EAAE,KAAK,KAAMN,CAAAA,MAAM,GAAG,CAACO,CAAC,CAAC,EAAE,KAAK;QACrD;QACA,OAAOH,QAAQ,KAAK,CAAC,GAAGlC,YAAY,GAAG,CAAC,CAAC,CAACsC,KAAK,GAAKA;IACrD;IAGQ,gBAAgBN,GAAW,EAAiB;QACnD,MAAMO,UAAUP,IAAI,WAAW,GAAG,OAAO,CAAC,eAAe;QACzD,IAAIO,QAAQ,MAAM,GAAGxC,kBAAkB,OAAO;QAC9C,IAAIF,UAAU,GAAG,CAAC0C,UAAU,OAAO;QACnC,OAAOA;IACR;AACD"}
|
|
1
|
+
{"version":3,"file":"core/compression/CompressionService.js","sources":["../../../src/core/compression/CompressionService.ts"],"sourcesContent":["/**\n * CompressionService — deterministic branch summarization.\n *\n * Compresses a terminated branch (or any subtree rooted at a thought) into a\n * single {@link Summary} record. Pure offline computation: no LLM, no I/O.\n *\n * Topic extraction is unigram frequency with stopword filtering; aggregate\n * confidence is the arithmetic mean of per-thought calibrated (or raw)\n * confidence values. The covered set is identified via\n * {@link GraphView.descendants}. Compression is **additive**: original\n * thoughts are never mutated or deleted.\n *\n * @module core/compression/CompressionService\n */\n\nimport type { ISummaryStore, Summary } from '../../contracts/summary.js';\nimport type { IEdgeStore } from '../../contracts/interfaces.js';\nimport type { Logger } from '../../logger/StructuredLogger.js';\nimport type { HistorySessionSnapshot, IHistoryManager } from '../IHistoryManager.js';\nimport type { ThoughtData } from '../thought.js';\nimport type { ConfidenceSignals } from '../reasoning.js';\nimport { GraphView } from '../graph/GraphView.js';\nimport { generateUlid } from '../ids.js';\nimport type { BranchId, SessionId, ThoughtId } from '../../contracts/ids.js';\n\n/** Stopwords excluded from topic extraction (lowercase). */\nconst STOPWORDS: ReadonlySet<string> = new Set([\n\t'the', 'this', 'that', 'then', 'than', 'with', 'from', 'have', 'will', 'been',\n\t'they', 'them', 'their', 'there', 'about', 'would', 'could', 'should', 'which',\n\t'where', 'when', 'what', 'some', 'into', 'also', 'just', 'like', 'over', 'such',\n\t'after', 'only', 'most', 'very', 'much', 'well', 'even', 'still', 'since',\n\t'being', 'doing', 'going', 'using',\n]);\n\nconst MIN_TOKEN_LENGTH = 4;\nconst TOP_TOPICS = 3;\n\n/** Local view of {@link ThoughtData} that exposes optional confidence signals. */\ntype ThoughtWithSignals = ThoughtData & { readonly confidence_signals?: ConfidenceSignals };\n\n/** Dependencies required by {@link CompressionService}. */\nexport interface CompressionDeps {\n\treadonly historyManager: IHistoryManager;\n\treadonly edgeStore: IEdgeStore;\n\treadonly summaryStore: ISummaryStore;\n\treadonly onSummaryCreated?: (summary: Summary) => void;\n\treadonly logger?: Logger;\n}\n\n/**\n * Deterministic, offline compression of branch subtrees into {@link Summary}.\n *\n * @example\n * ```typescript\n * const svc = new CompressionService({ historyManager, edgeStore, summaryStore });\n * const summary = svc.compressBranch('s1', 'alt-1', 'thought-root');\n * ```\n */\nexport class CompressionService {\n\tprivate readonly _deps: CompressionDeps;\n\tprivate readonly _graph: GraphView;\n\n\tconstructor(deps: CompressionDeps) {\n\t\tthis._deps = deps;\n\t\tthis._graph = new GraphView(deps.edgeStore);\n\t}\n\n\t/**\n\t * Compress the subtree rooted at `rootThoughtId` into a {@link Summary}.\n\t *\n\t * Idempotency: if a summary for the same `(branchId, rootThoughtId)` already\n\t * exists in the store, the existing summary is returned unchanged — same\n\t * inputs always yield the same Summary identity.\n\t */\n\tcompressBranch(sessionId: SessionId, branchId: BranchId, rootThoughtId: ThoughtId): Summary {\n\t\tconst existing = this._findExistingForRoot(sessionId, branchId, rootThoughtId);\n\t\tif (existing) return existing;\n\n\t\tconst snapshot = this._deps.historyManager.inspectSession(sessionId);\n\t\tconst candidateIds = this._collectCovered(sessionId, rootThoughtId);\n\t\tconst thoughts = this._resolveThoughts(snapshot, candidateIds);\n\t\tconst coveredIds = thoughts.flatMap((thought) =>\n\t\t\tthought.id === undefined ? [] : [thought.id]\n\t\t);\n\t\tconst summary: Summary = {\n\t\t\tid: generateUlid(),\n\t\t\tsessionId,\n\t\t\tbranchId,\n\t\t\trootThoughtId,\n\t\t\tcoveredIds,\n\t\t\tcoveredRange: this._coveredRange(thoughts),\n\t\t\ttopics: this._extractTopics(thoughts),\n\t\t\taggregateConfidence: this._meanConfidence(thoughts),\n\t\t\tcreatedAt: Date.now(),\n\t\t};\n\n\t\tthis._deps.summaryStore.add(summary);\n\t\tthis._deps.onSummaryCreated?.(summary);\n\t\tthis._deps.logger?.debug('compression.branch.compressed', {\n\t\t\tsessionId,\n\t\t\tbranchId,\n\t\t\trootThoughtId,\n\t\t\tcovered: coveredIds.length,\n\t\t\ttopics: summary.topics,\n\t\t});\n\t\treturn summary;\n\t}\n\n\t/** Look up an existing summary on this branch with a matching root. */\n\tprivate _findExistingForRoot(\n\t\tsessionId: SessionId,\n\t\tbranchId: BranchId,\n\t\trootThoughtId: ThoughtId\n\t): Summary | undefined {\n\t\tfor (const s of this._deps.summaryStore.forBranch(sessionId, branchId)) {\n\t\t\tif (s.rootThoughtId === rootThoughtId) return s;\n\t\t}\n\t\treturn undefined;\n\t}\n\n\t/** Collect the root and all of its descendants (chronological BFS). */\n\tprivate _collectCovered(sessionId: SessionId, rootThoughtId: ThoughtId): readonly ThoughtId[] {\n\t\tconst descendants = this._graph.descendants(sessionId, rootThoughtId);\n\t\treturn [rootThoughtId, ...descendants];\n\t}\n\n\t/**\n\t * Resolve candidate ids against one stable session snapshot. Main-history\n\t * records take precedence over branch copies; branch-only records are added\n\t * in declared branch order. Graph ids absent from the snapshot are omitted.\n\t */\n\tprivate _resolveThoughts(\n\t\tsnapshot: HistorySessionSnapshot,\n\t\tcandidateIds: readonly ThoughtId[]\n\t): ThoughtData[] {\n\t\tconst byId = new Map<ThoughtId, ThoughtData>();\n\t\tfor (const thought of snapshot.history) {\n\t\t\tif (thought.id !== undefined && !byId.has(thought.id)) byId.set(thought.id, thought);\n\t\t}\n\t\tfor (const branchId of snapshot.branchIds) {\n\t\t\tfor (const thought of snapshot.branches[branchId] ?? []) {\n\t\t\t\tif (thought.id !== undefined && !byId.has(thought.id)) byId.set(thought.id, thought);\n\t\t\t}\n\t\t}\n\n\t\tconst resolved: ThoughtData[] = [];\n\t\tconst seen = new Set<ThoughtId>();\n\t\tfor (const id of candidateIds) {\n\t\t\tif (seen.has(id)) continue;\n\t\t\tconst thought = byId.get(id);\n\t\t\tif (thought === undefined) continue;\n\t\t\tseen.add(id);\n\t\t\tresolved.push(thought);\n\t\t}\n\t\treturn resolved;\n\t}\n\n\t/**\n\t * Mean of (`calibrated_confidence` ?? `confidence` ?? 0) across covered.\n\t * Returns 0 when no thoughts are covered.\n\t */\n\tprivate _meanConfidence(thoughts: readonly ThoughtData[]): number {\n\t\tif (thoughts.length === 0) return 0;\n\t\tlet sum = 0;\n\t\tfor (const t of thoughts) {\n\t\t\tconst withSignals = t as ThoughtWithSignals;\n\t\t\tconst calibrated = withSignals.confidence_signals?.calibrated_confidence;\n\t\t\tsum += calibrated ?? t.confidence ?? 0;\n\t\t}\n\t\treturn sum / thoughts.length;\n\t}\n\n\t/**\n\t * Inclusive `[min, max]` of `thought_number` across covered thoughts.\n\t * Returns `[0, 0]` when no thoughts are covered.\n\t */\n\tprivate _coveredRange(thoughts: readonly ThoughtData[]): readonly [number, number] {\n\t\tif (thoughts.length === 0) return [0, 0];\n\t\tlet min = Number.POSITIVE_INFINITY;\n\t\tlet max = Number.NEGATIVE_INFINITY;\n\t\tfor (const t of thoughts) {\n\t\t\tconst n = t.thought_number;\n\t\t\tif (n < min) min = n;\n\t\t\tif (n > max) max = n;\n\t\t}\n\t\treturn [min, max];\n\t}\n\n\t/**\n\t * Extract top-3 unigrams by frequency from concatenated thought text.\n\t * Ties broken by first-occurrence order (stable).\n\t */\n\tprivate _extractTopics(thoughts: readonly ThoughtData[]): readonly string[] {\n\t\tif (thoughts.length === 0) return [];\n\t\tconst counts = new Map<string, number>();\n\t\tconst order = new Map<string, number>();\n\t\tlet position = 0;\n\t\tfor (const t of thoughts) {\n\t\t\tfor (const raw of (t.thought ?? '').split(/\\s+/)) {\n\t\t\t\tconst token = this._normalizeToken(raw);\n\t\t\t\tif (token === null) continue;\n\t\t\t\tif (!counts.has(token)) order.set(token, position++);\n\t\t\t\tcounts.set(token, (counts.get(token) ?? 0) + 1);\n\t\t\t}\n\t\t}\n\t\tif (counts.size === 0) return [];\n\t\tconst entries = Array.from(counts.entries());\n\t\tentries.sort((a, b) => {\n\t\t\tif (b[1] !== a[1]) return b[1] - a[1];\n\t\t\treturn (order.get(a[0]) ?? 0) - (order.get(b[0]) ?? 0);\n\t\t});\n\t\treturn entries.slice(0, TOP_TOPICS).map(([word]) => word);\n\t}\n\n\t/** Lowercase + strip non-alphanumerics; reject if too short or a stopword. */\n\tprivate _normalizeToken(raw: string): string | null {\n\t\tconst cleaned = raw.toLowerCase().replace(/[^a-z0-9]+/g, '');\n\t\tif (cleaned.length < MIN_TOKEN_LENGTH) return null;\n\t\tif (STOPWORDS.has(cleaned)) return null;\n\t\treturn cleaned;\n\t}\n}\n"],"names":["STOPWORDS","Set","MIN_TOKEN_LENGTH","TOP_TOPICS","CompressionService","deps","GraphView","sessionId","branchId","rootThoughtId","existing","snapshot","candidateIds","thoughts","coveredIds","thought","undefined","summary","generateUlid","Date","s","descendants","byId","Map","resolved","seen","id","sum","t","withSignals","calibrated","min","Number","max","n","counts","order","position","raw","token","entries","Array","a","b","word","cleaned"],"mappings":"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"}
|
|
@@ -9,8 +9,8 @@
|
|
|
9
9
|
* Pure and **non-mutating**: the input history array is never modified, and
|
|
10
10
|
* neither the summary store nor any thought record is altered. When a cold
|
|
11
11
|
* thought has no matching summary, the original {@link ThoughtData} is emitted
|
|
12
|
-
* unchanged. Consecutive cold thoughts
|
|
13
|
-
* `
|
|
12
|
+
* unchanged. Consecutive cold thoughts listed in the same summary's stable
|
|
13
|
+
* `coveredIds` are deduplicated to a single `SummaryRef`.
|
|
14
14
|
*
|
|
15
15
|
* @module core/compression/DehydrationPolicy
|
|
16
16
|
*/
|
|
@@ -56,8 +56,8 @@ export declare class DehydrationPolicy {
|
|
|
56
56
|
*
|
|
57
57
|
* Returns a new array of `(ThoughtData | SummaryRef)` where:
|
|
58
58
|
* - The last `keepLastK` thoughts are preserved verbatim.
|
|
59
|
-
* - Older thoughts whose `
|
|
60
|
-
*
|
|
59
|
+
* - Older thoughts whose stable `id` appears in an existing summary's
|
|
60
|
+
* `coveredIds` are replaced by a single {@link SummaryRef}.
|
|
61
61
|
* - Consecutive cold thoughts covered by the same summary collapse to one
|
|
62
62
|
* `SummaryRef`.
|
|
63
63
|
* - Cold thoughts with no matching summary are emitted verbatim.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DehydrationPolicy.d.ts","sourceRoot":"","sources":["../../../src/core/compression/DehydrationPolicy.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAW,MAAM,4BAA4B,CAAC;AACzE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,KAAK,EAAE,SAAS,
|
|
1
|
+
{"version":3,"file":"DehydrationPolicy.d.ts","sourceRoot":"","sources":["../../../src/core/compression/DehydrationPolicy.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAW,MAAM,4BAA4B,CAAC;AACzE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,KAAK,EAAE,SAAS,EAAa,MAAM,wBAAwB,CAAC;AAKnE,sDAAsD;AACtD,MAAM,WAAW,kBAAkB;IAClC;;;;;OAKG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED;;;;GAIG;AACH,MAAM,WAAW,UAAU;IAC1B,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IACzB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,YAAY,EAAE,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACjD;AAED,gFAAgF;AAChF,MAAM,MAAM,aAAa,GAAG,WAAW,GAAG,UAAU,CAAC;AAErD;;;;;;;;GAQG;AACH,qBAAa,iBAAiB;IACjB,OAAO,CAAC,QAAQ,CAAC,aAAa;gBAAb,aAAa,EAAE,aAAa;IAEzD;;;;;;;;;;;;;;;;;;OAkBG;IACH,KAAK,CACJ,OAAO,EAAE,SAAS,WAAW,EAAE,EAC/B,SAAS,EAAE,SAAS,EACpB,IAAI,CAAC,EAAE,kBAAkB,GACvB,aAAa,EAAE;CAiClB"}
|
|
@@ -15,7 +15,7 @@ class DehydrationPolicy {
|
|
|
15
15
|
const out = [];
|
|
16
16
|
let lastEmittedSummaryId;
|
|
17
17
|
for (const thought of cold){
|
|
18
|
-
const match = findCoveringSummary(summaries, thought.
|
|
18
|
+
const match = void 0 === thought.id ? void 0 : findCoveringSummary(summaries, thought.id);
|
|
19
19
|
if (void 0 === match) {
|
|
20
20
|
out.push(thought);
|
|
21
21
|
lastEmittedSummaryId = void 0;
|
|
@@ -34,11 +34,8 @@ class DehydrationPolicy {
|
|
|
34
34
|
return out;
|
|
35
35
|
}
|
|
36
36
|
}
|
|
37
|
-
function findCoveringSummary(summaries,
|
|
38
|
-
for (const s of summaries)
|
|
39
|
-
const [lo, hi] = s.coveredRange;
|
|
40
|
-
if (thoughtNumber >= lo && thoughtNumber <= hi) return s;
|
|
41
|
-
}
|
|
37
|
+
function findCoveringSummary(summaries, thoughtId) {
|
|
38
|
+
for (const s of summaries)if (s.coveredIds.includes(thoughtId)) return s;
|
|
42
39
|
}
|
|
43
40
|
export { DehydrationPolicy };
|
|
44
41
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"core/compression/DehydrationPolicy.js","sources":["../../../src/core/compression/DehydrationPolicy.ts"],"sourcesContent":["/**\n * DehydrationPolicy — sliding-window history compaction.\n *\n * Replaces older thoughts (the \"cold\" prefix beyond the most recent K) with\n * lightweight {@link SummaryRef} placeholders that point to existing\n * {@link Summary} records in an {@link ISummaryStore}. Recent thoughts (the\n * \"hot\" suffix of length K) are preserved verbatim.\n *\n * Pure and **non-mutating**: the input history array is never modified, and\n * neither the summary store nor any thought record is altered. When a cold\n * thought has no matching summary, the original {@link ThoughtData} is emitted\n * unchanged. Consecutive cold thoughts
|
|
1
|
+
{"version":3,"file":"core/compression/DehydrationPolicy.js","sources":["../../../src/core/compression/DehydrationPolicy.ts"],"sourcesContent":["/**\n * DehydrationPolicy — sliding-window history compaction.\n *\n * Replaces older thoughts (the \"cold\" prefix beyond the most recent K) with\n * lightweight {@link SummaryRef} placeholders that point to existing\n * {@link Summary} records in an {@link ISummaryStore}. Recent thoughts (the\n * \"hot\" suffix of length K) are preserved verbatim.\n *\n * Pure and **non-mutating**: the input history array is never modified, and\n * neither the summary store nor any thought record is altered. When a cold\n * thought has no matching summary, the original {@link ThoughtData} is emitted\n * unchanged. Consecutive cold thoughts listed in the same summary's stable\n * `coveredIds` are deduplicated to a single `SummaryRef`.\n *\n * @module core/compression/DehydrationPolicy\n */\n\nimport type { ISummaryStore, Summary } from '../../contracts/summary.js';\nimport type { ThoughtData } from '../thought.js';\nimport type { SessionId, ThoughtId } from '../../contracts/ids.js';\n\n/** Default value for {@link DehydrationOptions.keepLastK}. */\nconst DEFAULT_KEEP_LAST_K = 50;\n\n/** Options controlling sliding-window dehydration. */\nexport interface DehydrationOptions {\n\t/**\n\t * Number of most-recent thoughts to keep verbatim (\"hot\" window).\n\t * Older thoughts (the \"cold\" prefix) are eligible for replacement by\n\t * summary references.\n\t * @default 50\n\t */\n\treadonly keepLastK?: number;\n}\n\n/**\n * Lightweight reference replacing one or more cold thoughts covered by a\n * {@link Summary}. Carries only the summary id and the inclusive\n * `thought_number` range it covers.\n */\nexport interface SummaryRef {\n\treadonly kind: 'summary';\n\treadonly summaryId: string;\n\treadonly coveredRange: readonly [number, number];\n}\n\n/** Output entry in a dehydrated history: either a verbatim thought or a ref. */\nexport type HydratedEntry = ThoughtData | SummaryRef;\n\n/**\n * Sliding-window dehydration policy.\n *\n * @example\n * ```typescript\n * const policy = new DehydrationPolicy(summaryStore);\n * const hydrated = policy.apply(history, sessionId, { keepLastK: 50 });\n * ```\n */\nexport class DehydrationPolicy {\n\tconstructor(private readonly _summaryStore: ISummaryStore) {}\n\n\t/**\n\t * Apply sliding-window dehydration to a history array.\n\t *\n\t * Returns a new array of `(ThoughtData | SummaryRef)` where:\n\t * - The last `keepLastK` thoughts are preserved verbatim.\n\t * - Older thoughts whose stable `id` appears in an existing summary's\n\t * `coveredIds` are replaced by a single {@link SummaryRef}.\n\t * - Consecutive cold thoughts covered by the same summary collapse to one\n\t * `SummaryRef`.\n\t * - Cold thoughts with no matching summary are emitted verbatim.\n\t *\n\t * Non-mutating: the input array is not modified and original thoughts are\n\t * never altered.\n\t *\n\t * @param history - Input history (chronological)\n\t * @param sessionId - Session whose summaries should be considered\n\t * @param opts - Optional dehydration options\n\t * @returns A new array of hydrated entries\n\t */\n\tapply(\n\t\thistory: readonly ThoughtData[],\n\t\tsessionId: SessionId,\n\t\topts?: DehydrationOptions\n\t): HydratedEntry[] {\n\t\tconst k = opts?.keepLastK ?? DEFAULT_KEEP_LAST_K;\n\t\tif (history.length === 0) return [];\n\t\tif (history.length <= k) return history.slice();\n\n\t\tconst splitAt = history.length - k;\n\t\tconst cold = history.slice(0, splitAt);\n\t\tconst hot = history.slice(splitAt);\n\n\t\tconst summaries = this._summaryStore.forSession(sessionId);\n\t\tconst out: HydratedEntry[] = [];\n\t\tlet lastEmittedSummaryId: string | undefined;\n\n\t\tfor (const thought of cold) {\n\t\t\tconst match =\n\t\t\t\tthought.id === undefined ? undefined : findCoveringSummary(summaries, thought.id);\n\t\t\tif (match === undefined) {\n\t\t\t\tout.push(thought);\n\t\t\t\tlastEmittedSummaryId = undefined;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (match.id === lastEmittedSummaryId) continue;\n\t\t\tout.push({\n\t\t\t\tkind: 'summary',\n\t\t\t\tsummaryId: match.id,\n\t\t\t\tcoveredRange: match.coveredRange,\n\t\t\t});\n\t\t\tlastEmittedSummaryId = match.id;\n\t\t}\n\n\t\tfor (const t of hot) out.push(t);\n\t\treturn out;\n\t}\n}\n\n/**\n * Find the first summary whose stable `coveredIds` includes the thought.\n * Returns `undefined` when none match.\n */\nfunction findCoveringSummary(\n\tsummaries: readonly Summary[],\n\tthoughtId: ThoughtId\n): Summary | undefined {\n\tfor (const s of summaries) {\n\t\tif (s.coveredIds.includes(thoughtId)) return s;\n\t}\n\treturn undefined;\n}\n"],"names":["DEFAULT_KEEP_LAST_K","DehydrationPolicy","_summaryStore","history","sessionId","opts","k","splitAt","cold","hot","summaries","out","lastEmittedSummaryId","thought","match","undefined","findCoveringSummary","t","thoughtId","s"],"mappings":"AAsBA,MAAMA,sBAAsB;AAoCrB,MAAMC;;IACZ,YAA6BC,aAA4B,CAAE;aAA9BA,aAAa,GAAbA;IAA+B;IAqB5D,MACCC,OAA+B,EAC/BC,SAAoB,EACpBC,IAAyB,EACP;QAClB,MAAMC,IAAID,MAAM,aAAaL;QAC7B,IAAIG,AAAmB,MAAnBA,QAAQ,MAAM,EAAQ,OAAO,EAAE;QACnC,IAAIA,QAAQ,MAAM,IAAIG,GAAG,OAAOH,QAAQ,KAAK;QAE7C,MAAMI,UAAUJ,QAAQ,MAAM,GAAGG;QACjC,MAAME,OAAOL,QAAQ,KAAK,CAAC,GAAGI;QAC9B,MAAME,MAAMN,QAAQ,KAAK,CAACI;QAE1B,MAAMG,YAAY,IAAI,CAAC,aAAa,CAAC,UAAU,CAACN;QAChD,MAAMO,MAAuB,EAAE;QAC/B,IAAIC;QAEJ,KAAK,MAAMC,WAAWL,KAAM;YAC3B,MAAMM,QACLD,AAAeE,WAAfF,QAAQ,EAAE,GAAiBE,SAAYC,oBAAoBN,WAAWG,QAAQ,EAAE;YACjF,IAAIC,AAAUC,WAAVD,OAAqB;gBACxBH,IAAI,IAAI,CAACE;gBACTD,uBAAuBG;gBACvB;YACD;YACA,IAAID,MAAM,EAAE,KAAKF;gBACjBD,IAAI,IAAI,CAAC;oBACR,MAAM;oBACN,WAAWG,MAAM,EAAE;oBACnB,cAAcA,MAAM,YAAY;gBACjC;gBACAF,uBAAuBE,MAAM,EAAE;;QAChC;QAEA,KAAK,MAAMG,KAAKR,IAAKE,IAAI,IAAI,CAACM;QAC9B,OAAON;IACR;AACD;AAMA,SAASK,oBACRN,SAA6B,EAC7BQ,SAAoB;IAEpB,KAAK,MAAMC,KAAKT,UACf,IAAIS,EAAE,UAAU,CAAC,QAAQ,CAACD,YAAY,OAAOC;AAG/C"}
|
package/dist/lib.d.ts
CHANGED
|
@@ -12,6 +12,10 @@ import { StructuredLogger } from './logger/StructuredLogger.js';
|
|
|
12
12
|
import { SkillRegistry } from './registry/SkillRegistry.js';
|
|
13
13
|
import { ToolRegistry } from './registry/ToolRegistry.js';
|
|
14
14
|
import { ServerConfig } from './ServerConfig.js';
|
|
15
|
+
export { HttpTransport, createHttpTransport } from './transport/HttpTransport.js';
|
|
16
|
+
export type { HttpTransportOptions } from './transport/HttpTransport.js';
|
|
17
|
+
export type { TransportOptions } from './transport/BaseTransport.js';
|
|
18
|
+
export type { ITransport, TransportKind } from './contracts/transport.js';
|
|
15
19
|
export interface ServerOptions {
|
|
16
20
|
maxHistorySize?: number;
|
|
17
21
|
maxBranches?: number;
|
|
@@ -240,6 +244,8 @@ export declare class ToolAwareSequentialThinkingServer extends EventEmitter impl
|
|
|
240
244
|
*
|
|
241
245
|
* @example
|
|
242
246
|
* ```typescript
|
|
247
|
+
* import { createServer } from '@iworkforces/tracelattice';
|
|
248
|
+
*
|
|
243
249
|
* // Basic usage (with async discovery and persistence)
|
|
244
250
|
* const server = await createServer();
|
|
245
251
|
*
|
|
@@ -250,14 +256,8 @@ export declare class ToolAwareSequentialThinkingServer extends EventEmitter impl
|
|
|
250
256
|
* maxHistorySize: 500,
|
|
251
257
|
* loadFromPersistence: true
|
|
252
258
|
* });
|
|
253
|
-
*
|
|
254
|
-
* // With custom container for testing
|
|
255
|
-
* const mockContainer = new Container();
|
|
256
|
-
* mockContainer.registerInstance('Logger', mockLogger);
|
|
257
|
-
* const server = await createServer({ container: mockContainer });
|
|
258
259
|
* ```
|
|
259
260
|
*/
|
|
260
261
|
export declare function createServer(options?: ServerOptions): Promise<ToolAwareSequentialThinkingServer>;
|
|
261
262
|
export declare function initializeServer(): Promise<ToolAwareSequentialThinkingServer>;
|
|
262
|
-
export {};
|
|
263
263
|
//# sourceMappingURL=lib.d.ts.map
|
package/dist/lib.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lib.d.ts","sourceRoot":"","sources":["../src/lib.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"lib.d.ts","sourceRoot":"","sources":["../src/lib.ts"],"names":[],"mappings":"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"}
|
package/dist/lib.js
CHANGED
|
@@ -404,6 +404,7 @@ async function initializeServer() {
|
|
|
404
404
|
logger.info('Server initialized successfully');
|
|
405
405
|
return thinkingServer;
|
|
406
406
|
}
|
|
407
|
+
export { HttpTransport, createHttpTransport } from "./transport/HttpTransport.js";
|
|
407
408
|
export { ToolAwareSequentialThinkingServer, createServer, initializeServer };
|
|
408
409
|
|
|
409
410
|
//# sourceMappingURL=lib.js.map
|