@iworkforces/tracelattice 2.0.7 → 2.0.8
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 +1 -1
- package/dist/cli.js +205 -181
- package/dist/contracts/summary.d.ts +0 -1
- package/dist/contracts/summary.d.ts.map +1 -1
- package/dist/core/PersistenceRestore.d.ts +1 -1
- package/dist/core/PersistenceRestore.d.ts.map +1 -1
- package/dist/core/PersistenceRestore.js.map +1 -1
- package/dist/core/ThoughtEvaluator.d.ts.map +1 -1
- package/dist/core/ThoughtEvaluator.js.map +1 -1
- package/dist/core/ThoughtFormatter.js.map +1 -1
- package/dist/core/ThoughtProcessor.d.ts.map +1 -1
- package/dist/core/ThoughtProcessor.js.map +1 -1
- package/dist/core/compression/CompressionService.d.ts +2 -1
- package/dist/core/compression/CompressionService.d.ts.map +1 -1
- package/dist/core/compression/CompressionService.js.map +1 -1
- package/dist/core/compression/DehydrationPolicy.d.ts.map +1 -1
- package/dist/core/compression/DehydrationPolicy.js.map +1 -1
- package/dist/core/compression/InMemorySummaryStore.d.ts +2 -1
- package/dist/core/compression/InMemorySummaryStore.d.ts.map +1 -1
- package/dist/core/compression/InMemorySummaryStore.js.map +1 -1
- package/dist/core/evaluator/Calibrator.d.ts +1 -1
- package/dist/core/evaluator/Calibrator.d.ts.map +1 -1
- package/dist/core/evaluator/Calibrator.js.map +1 -1
- package/dist/core/evaluator/SignalComputer.d.ts +2 -1
- package/dist/core/evaluator/SignalComputer.d.ts.map +1 -1
- package/dist/core/evaluator/SignalComputer.js.map +1 -1
- package/dist/core/evaluator/internals.d.ts +1 -1
- package/dist/core/evaluator/internals.d.ts.map +1 -1
- package/dist/core/evaluator/internals.js.map +1 -1
- package/dist/core/graph/GraphView.d.ts +13 -1
- package/dist/core/graph/GraphView.d.ts.map +1 -1
- package/dist/core/graph/GraphView.js +34 -0
- package/dist/core/graph/GraphView.js.map +1 -1
- package/dist/core/reasoning/strategies/TreeOfThoughtStrategy.d.ts +6 -6
- package/dist/core/reasoning/strategies/TreeOfThoughtStrategy.d.ts.map +1 -1
- package/dist/core/reasoning/strategies/TreeOfThoughtStrategy.js +16 -2
- package/dist/core/reasoning/strategies/TreeOfThoughtStrategy.js.map +1 -1
- package/dist/core/reasoning/strategies/totScoring.d.ts.map +1 -1
- package/dist/core/reasoning/strategies/totScoring.js.map +1 -1
- package/dist/core/reasoning.d.ts +1 -3
- package/dist/core/reasoning.d.ts.map +1 -1
- package/dist/core/thought.d.ts +1 -1
- package/dist/core/thought.d.ts.map +1 -1
- package/dist/lib.d.ts +18 -4
- package/dist/lib.d.ts.map +1 -1
- package/dist/lib.js +51 -3
- package/dist/lib.js.map +1 -1
- package/dist/transport/HttpHelpers.d.ts +4 -1
- package/dist/transport/HttpHelpers.d.ts.map +1 -1
- package/dist/transport/HttpHelpers.js +61 -11
- package/dist/transport/HttpHelpers.js.map +1 -1
- package/dist/transport/HttpRequestLifecycle.d.ts +15 -1
- package/dist/transport/HttpRequestLifecycle.d.ts.map +1 -1
- package/dist/transport/HttpRequestLifecycle.js +66 -4
- package/dist/transport/HttpRequestLifecycle.js.map +1 -1
- package/dist/transport/HttpTransport.d.ts +2 -0
- package/dist/transport/HttpTransport.d.ts.map +1 -1
- package/dist/transport/HttpTransport.js +75 -38
- package/dist/transport/HttpTransport.js.map +1 -1
- package/dist/transport/StreamableHttpTransport.d.ts +5 -29
- package/dist/transport/StreamableHttpTransport.d.ts.map +1 -1
- package/dist/transport/StreamableHttpTransport.js +74 -116
- package/dist/transport/StreamableHttpTransport.js.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -202,7 +202,7 @@ Set `TRANSPORT_TYPE` to pick one:
|
|
|
202
202
|
| `stdio` (default) | Local MCP clients | `tracelattice` |
|
|
203
203
|
| `streamable-http` | Production deployments | `TRANSPORT_TYPE=streamable-http tracelattice` |
|
|
204
204
|
|
|
205
|
-
The Streamable HTTP endpoint defaults to `POST /mcp` for JSON-RPC requests and supports stateful sessions via the `Mcp-Session-Id` header.
|
|
205
|
+
The Streamable HTTP endpoint defaults to `POST /mcp` for JSON-RPC requests and supports stateful sessions via the `Mcp-Session-Id` header. `GET /mcp` is not allowed. The library also exposes `HttpTransport` for stateless JSON-RPC over HTTP, but the CLI does not select it with `TRANSPORT_TYPE`.
|
|
206
206
|
|
|
207
207
|
### Stateless HTTP library API
|
|
208
208
|
|
package/dist/cli.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import * as __rspack_external_valibot from "valibot";
|
|
3
3
|
import * as __rspack_external_node_crypto_2e7c4b46 from "node:crypto";
|
|
4
4
|
import * as __rspack_external_node_http_e245b239 from "node:http";
|
|
5
|
+
import * as __rspack_external_node_string_decoder_69b9bd04 from "node:string_decoder";
|
|
5
6
|
import * as __rspack_external_node_async_hooks_4d8b1b4a from "node:async_hooks";
|
|
6
7
|
import * as __rspack_external__tmcp_adapter_valibot_0faddfa6 from "@tmcp/adapter-valibot";
|
|
7
8
|
import * as __rspack_external__tmcp_transport_stdio_98e5584f from "@tmcp/transport-stdio";
|
|
@@ -1326,7 +1327,7 @@ __webpack_require__.d(__webpack_exports__, {
|
|
|
1326
1327
|
|
|
1327
1328
|
|
|
1328
1329
|
},
|
|
1329
|
-
"
|
|
1330
|
+
"q"(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
|
|
1330
1331
|
|
|
1331
1332
|
// EXPORTS
|
|
1332
1333
|
__webpack_require__.d(__webpack_exports__, {
|
|
@@ -1779,6 +1780,8 @@ class BaseTransport {
|
|
|
1779
1780
|
* instead of casting `'__global__'` ad-hoc.
|
|
1780
1781
|
*/ const GLOBAL_SESSION_ID = asSessionId('__global__');
|
|
1781
1782
|
|
|
1783
|
+
;// CONCATENATED MODULE: external "node:string_decoder"
|
|
1784
|
+
|
|
1782
1785
|
;// CONCATENATED MODULE: ./src/transport/HttpHelpers.ts
|
|
1783
1786
|
/**
|
|
1784
1787
|
* Shared HTTP helper utilities for MCP transport implementations.
|
|
@@ -1788,7 +1791,11 @@ class BaseTransport {
|
|
|
1788
1791
|
* HttpTransport and StreamableHttpTransport.
|
|
1789
1792
|
*
|
|
1790
1793
|
* @module transport/HttpHelpers
|
|
1791
|
-
*/
|
|
1794
|
+
*/
|
|
1795
|
+
class RequestBodyAbortedError extends Error {
|
|
1796
|
+
name = 'RequestBodyAbortedError';
|
|
1797
|
+
}
|
|
1798
|
+
/**
|
|
1792
1799
|
* Send a JSON-RPC 2.0 error response.
|
|
1793
1800
|
*
|
|
1794
1801
|
* Standardizes error response formatting across all transport implementations.
|
|
@@ -1856,23 +1863,118 @@ class BaseTransport {
|
|
|
1856
1863
|
* @param req - The incoming HTTP request
|
|
1857
1864
|
* @param maxBodySize - Maximum allowed body size in bytes (0 = unlimited)
|
|
1858
1865
|
* @returns The body string, or `null` if the body exceeded the size limit
|
|
1859
|
-
*/ async function readRequestBody(req, maxBodySize) {
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1866
|
+
*/ async function readRequestBody(req, maxBodySize, signal) {
|
|
1867
|
+
return new Promise((resolve, reject)=>{
|
|
1868
|
+
let body = '';
|
|
1869
|
+
let bodySize = 0;
|
|
1870
|
+
let settled = false;
|
|
1871
|
+
const decoder = new __rspack_external_node_string_decoder_69b9bd04.StringDecoder('utf8');
|
|
1872
|
+
const cleanup = ()=>{
|
|
1873
|
+
req.off('data', onData);
|
|
1874
|
+
req.off('end', onEnd);
|
|
1875
|
+
req.off('aborted', onAborted);
|
|
1876
|
+
req.off('close', onAborted);
|
|
1877
|
+
req.off('error', onError);
|
|
1878
|
+
signal?.removeEventListener('abort', onAborted);
|
|
1879
|
+
};
|
|
1880
|
+
const onData = (chunk)=>{
|
|
1881
|
+
if (settled) return;
|
|
1882
|
+
const chunkSize = typeof chunk === 'string' ? Buffer.byteLength(chunk) : chunk.byteLength;
|
|
1883
|
+
bodySize += chunkSize;
|
|
1884
|
+
if (maxBodySize > 0 && bodySize > maxBodySize) {
|
|
1885
|
+
settled = true;
|
|
1886
|
+
cleanup();
|
|
1887
|
+
req.resume();
|
|
1888
|
+
resolve(null);
|
|
1889
|
+
return;
|
|
1890
|
+
}
|
|
1891
|
+
body += typeof chunk === 'string' ? chunk : decoder.write(chunk);
|
|
1892
|
+
};
|
|
1893
|
+
const onEnd = ()=>{
|
|
1894
|
+
if (settled) return;
|
|
1895
|
+
settled = true;
|
|
1896
|
+
cleanup();
|
|
1897
|
+
resolve(body + decoder.end());
|
|
1898
|
+
};
|
|
1899
|
+
const onAborted = ()=>{
|
|
1900
|
+
if (settled) return;
|
|
1901
|
+
settled = true;
|
|
1902
|
+
cleanup();
|
|
1903
|
+
req.resume();
|
|
1904
|
+
reject(new RequestBodyAbortedError());
|
|
1905
|
+
};
|
|
1906
|
+
const onError = (error)=>{
|
|
1907
|
+
if (settled) return;
|
|
1908
|
+
settled = true;
|
|
1909
|
+
cleanup();
|
|
1910
|
+
reject(error);
|
|
1911
|
+
};
|
|
1912
|
+
req.on('data', onData);
|
|
1913
|
+
req.once('end', onEnd);
|
|
1914
|
+
req.once('aborted', onAborted);
|
|
1915
|
+
req.once('close', onAborted);
|
|
1916
|
+
req.once('error', onError);
|
|
1917
|
+
signal?.addEventListener('abort', onAborted, {
|
|
1918
|
+
once: true
|
|
1919
|
+
});
|
|
1920
|
+
if (signal?.aborted) onAborted();
|
|
1921
|
+
});
|
|
1871
1922
|
}
|
|
1872
1923
|
|
|
1873
1924
|
// EXTERNAL MODULE: ./src/context/RequestContext.ts + 1 modules
|
|
1874
1925
|
var RequestContext = __webpack_require__("i");
|
|
1875
1926
|
;// CONCATENATED MODULE: ./src/transport/HttpRequestLifecycle.ts
|
|
1927
|
+
class TrackedPreDispatchLease {
|
|
1928
|
+
_onRelease;
|
|
1929
|
+
_controller = new AbortController();
|
|
1930
|
+
_settled = Promise.withResolvers();
|
|
1931
|
+
_active = true;
|
|
1932
|
+
_cancellationReason = null;
|
|
1933
|
+
constructor(_onRelease){
|
|
1934
|
+
this._onRelease = _onRelease;
|
|
1935
|
+
}
|
|
1936
|
+
get signal() {
|
|
1937
|
+
return this._controller.signal;
|
|
1938
|
+
}
|
|
1939
|
+
get cancellationReason() {
|
|
1940
|
+
return this._cancellationReason;
|
|
1941
|
+
}
|
|
1942
|
+
get settled() {
|
|
1943
|
+
return this._settled.promise;
|
|
1944
|
+
}
|
|
1945
|
+
cancel(reason) {
|
|
1946
|
+
if (!this._active || this._controller.signal.aborted) return;
|
|
1947
|
+
this._cancellationReason = reason;
|
|
1948
|
+
this._controller.abort();
|
|
1949
|
+
}
|
|
1950
|
+
release() {
|
|
1951
|
+
if (!this._active) return;
|
|
1952
|
+
this._active = false;
|
|
1953
|
+
this._onRelease(this);
|
|
1954
|
+
this._settled.resolve();
|
|
1955
|
+
}
|
|
1956
|
+
}
|
|
1957
|
+
class PreDispatchTracker {
|
|
1958
|
+
_leases = new Set();
|
|
1959
|
+
_accepting = true;
|
|
1960
|
+
acquire() {
|
|
1961
|
+
if (!this._accepting) return null;
|
|
1962
|
+
const lease = new TrackedPreDispatchLease((released)=>this._leases.delete(released));
|
|
1963
|
+
this._leases.add(lease);
|
|
1964
|
+
return lease;
|
|
1965
|
+
}
|
|
1966
|
+
closeAdmission(reason) {
|
|
1967
|
+
this._accepting = false;
|
|
1968
|
+
for (const lease of this._leases)lease.cancel(reason);
|
|
1969
|
+
}
|
|
1970
|
+
async join() {
|
|
1971
|
+
while(this._leases.size > 0){
|
|
1972
|
+
await Promise.all([
|
|
1973
|
+
...this._leases
|
|
1974
|
+
].map((lease)=>lease.settled));
|
|
1975
|
+
}
|
|
1976
|
+
}
|
|
1977
|
+
}
|
|
1876
1978
|
/** Maximum number of reporting failures retained for diagnostics. */ const LIFECYCLE_REPORTING_FAILURE_CAPACITY = 32;
|
|
1877
1979
|
class LifecycleFailureReporter {
|
|
1878
1980
|
_onFailure;
|
|
@@ -1944,14 +2046,27 @@ class AcceptedWorkTracker {
|
|
|
1944
2046
|
get size() {
|
|
1945
2047
|
return this._work.size;
|
|
1946
2048
|
}
|
|
1947
|
-
|
|
2049
|
+
transfer(lease, start) {
|
|
2050
|
+
lease.signal.throwIfAborted();
|
|
2051
|
+
const reservation = Promise.withResolvers();
|
|
2052
|
+
this._work.add(reservation.promise);
|
|
2053
|
+
lease.release();
|
|
2054
|
+
let work;
|
|
2055
|
+
try {
|
|
2056
|
+
work = start();
|
|
2057
|
+
} catch (error) {
|
|
2058
|
+
this._work.delete(reservation.promise);
|
|
2059
|
+
reservation.resolve();
|
|
2060
|
+
throw error;
|
|
2061
|
+
}
|
|
1948
2062
|
const observed = work.catch((error)=>{
|
|
1949
2063
|
this._failureReporter.report(error);
|
|
1950
2064
|
});
|
|
1951
|
-
this._work.add(observed);
|
|
1952
2065
|
void observed.then(()=>{
|
|
1953
|
-
this._work.delete(
|
|
2066
|
+
this._work.delete(reservation.promise);
|
|
2067
|
+
reservation.resolve();
|
|
1954
2068
|
});
|
|
2069
|
+
return work;
|
|
1955
2070
|
}
|
|
1956
2071
|
async join() {
|
|
1957
2072
|
while(this._work.size > 0){
|
|
@@ -1964,12 +2079,8 @@ class AcceptedWorkTracker {
|
|
|
1964
2079
|
/**
|
|
1965
2080
|
* Streamable HTTP Transport implementation (MCP spec recommended transport).
|
|
1966
2081
|
*
|
|
1967
|
-
* This transport implements the MCP Streamable HTTP specification, which replaces
|
|
1968
|
-
* the deprecated SSE transport as the recommended HTTP-based transport since March 2025.
|
|
1969
|
-
*
|
|
1970
2082
|
* Key features:
|
|
1971
2083
|
* - POST /mcp for JSON-RPC requests (main MCP endpoint)
|
|
1972
|
-
* - GET /mcp for optional SSE server-to-client notifications
|
|
1973
2084
|
* - Session management via Mcp-Session-Id header
|
|
1974
2085
|
* - Supports both stateful (session-based) and stateless (per-request) modes
|
|
1975
2086
|
* - Health endpoints (/health, /ready)
|
|
@@ -2011,8 +2122,7 @@ function parseSessionRetentionOptions(options) {
|
|
|
2011
2122
|
* Streamable HTTP Transport for MCP server.
|
|
2012
2123
|
*
|
|
2013
2124
|
* This transport implements the MCP Streamable HTTP specification,
|
|
2014
|
-
* providing JSON-RPC over HTTP with optional session management
|
|
2015
|
-
* and server-to-client SSE notification streams.
|
|
2125
|
+
* providing JSON-RPC over HTTP with optional session management.
|
|
2016
2126
|
*
|
|
2017
2127
|
* @remarks
|
|
2018
2128
|
* **Security Features (inherited from BaseTransport):**
|
|
@@ -2024,13 +2134,11 @@ function parseSessionRetentionOptions(options) {
|
|
|
2024
2134
|
*
|
|
2025
2135
|
* **MCP Streamable HTTP Spec Compliance:**
|
|
2026
2136
|
* - POST /mcp — JSON-RPC method calls
|
|
2027
|
-
* - GET /mcp — SSE notification stream (server-to-client)
|
|
2028
2137
|
* - Mcp-Session-Id header for session management
|
|
2029
2138
|
* - Content-Type: application/json for JSON-RPC responses
|
|
2030
|
-
* - Content-Type: text/event-stream for SSE notification streams
|
|
2031
2139
|
*
|
|
2032
2140
|
* **HTTP Status Code Mapping:**
|
|
2033
|
-
* - 200: Success (JSON-RPC response
|
|
2141
|
+
* - 200: Success (JSON-RPC response)
|
|
2034
2142
|
* - 202: Accepted (JSON-RPC notification, no response body)
|
|
2035
2143
|
* - 204: CORS Preflight (empty body)
|
|
2036
2144
|
* - 400: Bad Request (invalid JSON, invalid session ID)
|
|
@@ -2060,6 +2168,7 @@ function parseSessionRetentionOptions(options) {
|
|
|
2060
2168
|
_metricsProvider;
|
|
2061
2169
|
_lifecycleFailureReporter;
|
|
2062
2170
|
_acceptedWork;
|
|
2171
|
+
_preDispatch = new PreDispatchTracker();
|
|
2063
2172
|
_sessionRetention;
|
|
2064
2173
|
_sessionSweepIntervalId = null;
|
|
2065
2174
|
_stopPromise = null;
|
|
@@ -2142,15 +2251,18 @@ function parseSessionRetentionOptions(options) {
|
|
|
2142
2251
|
}
|
|
2143
2252
|
});
|
|
2144
2253
|
}
|
|
2145
|
-
|
|
2146
|
-
* Route and handle incoming HTTP requests.
|
|
2147
|
-
*/ async _handleRequest(req, res) {
|
|
2254
|
+
_recordRequestMetrics(res) {
|
|
2148
2255
|
const startTime = Date.now();
|
|
2149
2256
|
this._metrics?.counter('streamable_http_requests_total', 1, {}, 'Total Streamable HTTP transport requests');
|
|
2150
2257
|
res.once('finish', ()=>{
|
|
2151
2258
|
const durationSeconds = (Date.now() - startTime) / 1000;
|
|
2152
2259
|
this._metrics?.histogram('streamable_http_request_duration_seconds', durationSeconds, {});
|
|
2153
2260
|
});
|
|
2261
|
+
}
|
|
2262
|
+
/**
|
|
2263
|
+
* Route and handle incoming HTTP requests.
|
|
2264
|
+
*/ async _handleRequest(req, res) {
|
|
2265
|
+
this._recordRequestMetrics(res);
|
|
2154
2266
|
// Host validation
|
|
2155
2267
|
if (!this.validateHostHeader(req)) {
|
|
2156
2268
|
this._sendJsonRpcError(res, 403, -32000, 'Forbidden - invalid host header');
|
|
@@ -2201,16 +2313,20 @@ function parseSessionRetentionOptions(options) {
|
|
|
2201
2313
|
// MCP endpoint routing
|
|
2202
2314
|
if (urlPath === this._path) {
|
|
2203
2315
|
if (req.method === 'POST') {
|
|
2204
|
-
this.
|
|
2205
|
-
|
|
2206
|
-
|
|
2207
|
-
|
|
2208
|
-
|
|
2316
|
+
const lease = this._preDispatch.acquire();
|
|
2317
|
+
if (!lease) {
|
|
2318
|
+
const responseFinalizer = new ResponseFinalizer(res, this._lifecycleFailureReporter);
|
|
2319
|
+
responseFinalizer.finalize((response)=>{
|
|
2320
|
+
this._sendJsonRpcError(response, 503, -32603, 'Server is shutting down');
|
|
2321
|
+
});
|
|
2322
|
+
return;
|
|
2323
|
+
}
|
|
2324
|
+
await this._handleMcpPost(req, res, lease);
|
|
2209
2325
|
return;
|
|
2210
2326
|
}
|
|
2211
2327
|
res.writeHead(405, {
|
|
2212
2328
|
'Content-Type': 'application/json',
|
|
2213
|
-
Allow: '
|
|
2329
|
+
Allow: 'POST'
|
|
2214
2330
|
});
|
|
2215
2331
|
res.end(JSON.stringify({
|
|
2216
2332
|
jsonrpc: '2.0',
|
|
@@ -2244,6 +2360,28 @@ function parseSessionRetentionOptions(options) {
|
|
|
2244
2360
|
error
|
|
2245
2361
|
}));
|
|
2246
2362
|
}
|
|
2363
|
+
_parseJsonRpcRequest(body, responseFinalizer) {
|
|
2364
|
+
let rawBody;
|
|
2365
|
+
try {
|
|
2366
|
+
rawBody = JSON.parse(body);
|
|
2367
|
+
} catch {
|
|
2368
|
+
responseFinalizer.finalize((response)=>{
|
|
2369
|
+
this._sendJsonRpcError(response, 200, -32700, 'Parse error');
|
|
2370
|
+
});
|
|
2371
|
+
return null;
|
|
2372
|
+
}
|
|
2373
|
+
const parseResult = (0,external_valibot_.safeParse)(schema/* .JsonRpcRequestSchema */.Uv, rawBody);
|
|
2374
|
+
const rawId = rawBody && typeof rawBody === 'object' && 'id' in rawBody ? rawBody.id ?? null : null;
|
|
2375
|
+
if (!parseResult.success) {
|
|
2376
|
+
responseFinalizer.finalize((response)=>{
|
|
2377
|
+
this._sendJsonRpcError(response, 200, -32600, 'Invalid Request', rawId, {
|
|
2378
|
+
data: parseResult.issues
|
|
2379
|
+
});
|
|
2380
|
+
});
|
|
2381
|
+
return null;
|
|
2382
|
+
}
|
|
2383
|
+
return parseResult.output;
|
|
2384
|
+
}
|
|
2247
2385
|
/**
|
|
2248
2386
|
* Handle POST /mcp — JSON-RPC method calls.
|
|
2249
2387
|
*
|
|
@@ -2252,65 +2390,67 @@ function parseSessionRetentionOptions(options) {
|
|
|
2252
2390
|
* - Returns Mcp-Session-Id header for new sessions (stateful mode)
|
|
2253
2391
|
* - Validates Mcp-Session-Id for existing sessions (stateful mode)
|
|
2254
2392
|
* - Content-Type: application/json for responses
|
|
2255
|
-
*/ async _handleMcpPost(req, res) {
|
|
2393
|
+
*/ async _handleMcpPost(req, res, lease) {
|
|
2256
2394
|
this._requestCount++;
|
|
2257
2395
|
this._activeRequests++;
|
|
2258
2396
|
const responseFinalizer = new ResponseFinalizer(res, this._lifecycleFailureReporter);
|
|
2259
2397
|
let acceptedSession = null;
|
|
2398
|
+
const onAborted = ()=>lease.cancel('peer');
|
|
2399
|
+
req.once('aborted', onAborted);
|
|
2260
2400
|
const timeout = setTimeout(()=>{
|
|
2261
2401
|
responseFinalizer.finalize((response)=>{
|
|
2262
2402
|
this._sendJsonRpcError(response, 500, -32603, 'Request timeout');
|
|
2263
2403
|
});
|
|
2404
|
+
lease.cancel('timeout');
|
|
2264
2405
|
}, this._requestTimeout);
|
|
2265
2406
|
try {
|
|
2266
2407
|
// Read request body with size limit
|
|
2267
|
-
const body = await readRequestBody(req, this._bodySizeLimitEnabled ? this._maxBodySize : 0);
|
|
2408
|
+
const body = await readRequestBody(req, this._bodySizeLimitEnabled ? this._maxBodySize : 0, lease.signal);
|
|
2268
2409
|
if (body === null) {
|
|
2269
2410
|
responseFinalizer.finalize((response)=>{
|
|
2270
2411
|
this._sendJsonRpcError(response, 413, -32000, 'Request body too large');
|
|
2271
2412
|
});
|
|
2272
2413
|
return;
|
|
2273
2414
|
}
|
|
2274
|
-
|
|
2275
|
-
|
|
2276
|
-
try {
|
|
2277
|
-
rawBody = JSON.parse(body);
|
|
2278
|
-
} catch {
|
|
2279
|
-
responseFinalizer.finalize((response)=>{
|
|
2280
|
-
this._sendJsonRpcError(response, 200, -32700, 'Parse error');
|
|
2281
|
-
});
|
|
2282
|
-
return;
|
|
2283
|
-
}
|
|
2284
|
-
// Validate JSON-RPC schema
|
|
2285
|
-
const parseResult = (0,external_valibot_.safeParse)(schema/* .JsonRpcRequestSchema */.Uv, rawBody);
|
|
2286
|
-
const rawId = rawBody && typeof rawBody === 'object' && 'id' in rawBody ? rawBody.id ?? null : null;
|
|
2287
|
-
if (!parseResult.success) {
|
|
2288
|
-
responseFinalizer.finalize((response)=>{
|
|
2289
|
-
this._sendJsonRpcError(response, 200, -32600, 'Invalid Request', rawId, {
|
|
2290
|
-
data: parseResult.issues
|
|
2291
|
-
});
|
|
2292
|
-
});
|
|
2293
|
-
return;
|
|
2294
|
-
}
|
|
2295
|
-
const jsonRpcRequest = parseResult.output;
|
|
2415
|
+
const jsonRpcRequest = this._parseJsonRpcRequest(body, responseFinalizer);
|
|
2416
|
+
if (jsonRpcRequest === null) return;
|
|
2296
2417
|
const session = this._acceptPostSession(req, responseFinalizer);
|
|
2297
2418
|
if (!session) return;
|
|
2298
2419
|
acceptedSession = session.state;
|
|
2299
2420
|
// Check if MCP server is ready
|
|
2300
2421
|
if (!this._mcpServer) {
|
|
2422
|
+
const requestId = 'id' in jsonRpcRequest ? jsonRpcRequest.id ?? null : null;
|
|
2301
2423
|
responseFinalizer.finalize((response)=>{
|
|
2302
|
-
this._sendJsonRpcError(response, 503, -32603, 'Server not ready',
|
|
2424
|
+
this._sendJsonRpcError(response, 503, -32603, 'Server not ready', requestId);
|
|
2303
2425
|
});
|
|
2304
2426
|
return;
|
|
2305
2427
|
}
|
|
2306
|
-
|
|
2428
|
+
req.off('aborted', onAborted);
|
|
2429
|
+
const acceptedWork = this._acceptedWork.transfer(lease, ()=>this._receiveAndFinalize(jsonRpcRequest, session.id, responseFinalizer).catch((error)=>{
|
|
2430
|
+
responseFinalizer.finalize((response)=>{
|
|
2431
|
+
this._sendJsonRpcError(response, 200, -32603, 'Internal error', null, {
|
|
2432
|
+
data: (0,errors/* .getErrorMessage */.u1)(error)
|
|
2433
|
+
});
|
|
2434
|
+
});
|
|
2435
|
+
}));
|
|
2436
|
+
await acceptedWork;
|
|
2307
2437
|
} catch (error) {
|
|
2438
|
+
if (lease.signal.aborted) {
|
|
2439
|
+
if (lease.cancellationReason === 'shutdown') {
|
|
2440
|
+
responseFinalizer.finalize((response)=>{
|
|
2441
|
+
this._sendJsonRpcError(response, 503, -32603, 'Server is shutting down');
|
|
2442
|
+
});
|
|
2443
|
+
}
|
|
2444
|
+
return;
|
|
2445
|
+
}
|
|
2308
2446
|
responseFinalizer.finalize((response)=>{
|
|
2309
2447
|
this._sendJsonRpcError(response, 200, -32603, 'Internal error', null, {
|
|
2310
2448
|
data: (0,errors/* .getErrorMessage */.u1)(error)
|
|
2311
2449
|
});
|
|
2312
2450
|
});
|
|
2313
2451
|
} finally{
|
|
2452
|
+
req.off('aborted', onAborted);
|
|
2453
|
+
lease.release();
|
|
2314
2454
|
if (acceptedSession) acceptedSession.acceptedPostCount--;
|
|
2315
2455
|
clearTimeout(timeout);
|
|
2316
2456
|
this._activeRequests--;
|
|
@@ -2363,82 +2503,6 @@ function parseSessionRetentionOptions(options) {
|
|
|
2363
2503
|
httpResponse.end();
|
|
2364
2504
|
});
|
|
2365
2505
|
}
|
|
2366
|
-
/**
|
|
2367
|
-
* Handle GET /mcp — Optional SSE notification stream.
|
|
2368
|
-
*
|
|
2369
|
-
* Per the MCP Streamable HTTP spec, clients may open a GET request
|
|
2370
|
-
* to receive server-initiated notifications as SSE events.
|
|
2371
|
-
* Requires a valid Mcp-Session-Id in stateful mode.
|
|
2372
|
-
*/ _handleMcpGet(req, res) {
|
|
2373
|
-
if (!this._stateful) {
|
|
2374
|
-
// SSE notification streams require stateful mode
|
|
2375
|
-
res.writeHead(405, {
|
|
2376
|
-
'Content-Type': 'application/json',
|
|
2377
|
-
Allow: 'POST'
|
|
2378
|
-
});
|
|
2379
|
-
res.end(JSON.stringify({
|
|
2380
|
-
jsonrpc: '2.0',
|
|
2381
|
-
id: null,
|
|
2382
|
-
error: {
|
|
2383
|
-
code: -32601,
|
|
2384
|
-
message: 'GET not supported in stateless mode'
|
|
2385
|
-
}
|
|
2386
|
-
}));
|
|
2387
|
-
return;
|
|
2388
|
-
}
|
|
2389
|
-
// Require Mcp-Session-Id for GET requests
|
|
2390
|
-
const sessionId = this._getSessionIdFromHeader(req);
|
|
2391
|
-
if (!sessionId) {
|
|
2392
|
-
res.writeHead(400, {
|
|
2393
|
-
'Content-Type': 'application/json'
|
|
2394
|
-
});
|
|
2395
|
-
res.end(JSON.stringify({
|
|
2396
|
-
jsonrpc: '2.0',
|
|
2397
|
-
id: null,
|
|
2398
|
-
error: {
|
|
2399
|
-
code: -32600,
|
|
2400
|
-
message: 'Missing Mcp-Session-Id header'
|
|
2401
|
-
}
|
|
2402
|
-
}));
|
|
2403
|
-
return;
|
|
2404
|
-
}
|
|
2405
|
-
const session = this._sessions.get(asSessionId(sessionId));
|
|
2406
|
-
if (!session) {
|
|
2407
|
-
res.writeHead(404, {
|
|
2408
|
-
'Content-Type': 'application/json'
|
|
2409
|
-
});
|
|
2410
|
-
res.end(JSON.stringify({
|
|
2411
|
-
jsonrpc: '2.0',
|
|
2412
|
-
id: null,
|
|
2413
|
-
error: {
|
|
2414
|
-
code: -32001,
|
|
2415
|
-
message: 'Session not found'
|
|
2416
|
-
}
|
|
2417
|
-
}));
|
|
2418
|
-
return;
|
|
2419
|
-
}
|
|
2420
|
-
session.lastActivityAt = Date.now();
|
|
2421
|
-
// Set SSE headers
|
|
2422
|
-
res.writeHead(200, {
|
|
2423
|
-
'Content-Type': 'text/event-stream',
|
|
2424
|
-
'Cache-Control': 'no-cache',
|
|
2425
|
-
Connection: 'keep-alive',
|
|
2426
|
-
'Mcp-Session-Id': sessionId
|
|
2427
|
-
});
|
|
2428
|
-
// Send initial connected event
|
|
2429
|
-
this._sendSseEvent(res, 'connected', {
|
|
2430
|
-
sessionId,
|
|
2431
|
-
timestamp: Date.now()
|
|
2432
|
-
});
|
|
2433
|
-
// Track this notification stream
|
|
2434
|
-
session.notificationStreams.add(res);
|
|
2435
|
-
this._updateSessionMetrics();
|
|
2436
|
-
// Handle client disconnect
|
|
2437
|
-
req.on('close', ()=>{
|
|
2438
|
-
session.notificationStreams.delete(res);
|
|
2439
|
-
this._updateSessionMetrics();
|
|
2440
|
-
});
|
|
2441
|
-
}
|
|
2442
2506
|
/**
|
|
2443
2507
|
* Resolve or create a session for a stateful request.
|
|
2444
2508
|
*
|
|
@@ -2484,7 +2548,6 @@ function parseSessionRetentionOptions(options) {
|
|
|
2484
2548
|
id: newSessionId,
|
|
2485
2549
|
createdAt: now,
|
|
2486
2550
|
lastActivityAt: now,
|
|
2487
|
-
notificationStreams: new Set(),
|
|
2488
2551
|
acceptedPostCount: 0
|
|
2489
2552
|
};
|
|
2490
2553
|
this._sessions.set(newSessionId, sessionState);
|
|
@@ -2505,17 +2568,7 @@ function parseSessionRetentionOptions(options) {
|
|
|
2505
2568
|
}
|
|
2506
2569
|
}
|
|
2507
2570
|
_disposeSession(sessionId) {
|
|
2508
|
-
|
|
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();
|
|
2571
|
+
if (!this._sessions.delete(sessionId)) return;
|
|
2519
2572
|
this._updateSessionMetrics();
|
|
2520
2573
|
}
|
|
2521
2574
|
_stopSessionSweep() {
|
|
@@ -2534,31 +2587,6 @@ function parseSessionRetentionOptions(options) {
|
|
|
2534
2587
|
}
|
|
2535
2588
|
return undefined;
|
|
2536
2589
|
}
|
|
2537
|
-
/**
|
|
2538
|
-
* Send an SSE event to a specific client response stream.
|
|
2539
|
-
*/ _sendSseEvent(res, event, data) {
|
|
2540
|
-
try {
|
|
2541
|
-
res.write(`event: ${event}\n`);
|
|
2542
|
-
res.write(`data: ${JSON.stringify(data)}\n\n`);
|
|
2543
|
-
} catch {
|
|
2544
|
-
// Client disconnected — ignore
|
|
2545
|
-
}
|
|
2546
|
-
}
|
|
2547
|
-
/**
|
|
2548
|
-
* Broadcast a notification to all SSE streams in a given session.
|
|
2549
|
-
*
|
|
2550
|
-
* @param sessionId - Target session ID
|
|
2551
|
-
* @param event - SSE event name
|
|
2552
|
-
* @param data - Event payload
|
|
2553
|
-
*/ broadcastToSession(sessionId, event, data) {
|
|
2554
|
-
const session = this._sessions.get(asSessionId(sessionId));
|
|
2555
|
-
if (!session) {
|
|
2556
|
-
return;
|
|
2557
|
-
}
|
|
2558
|
-
for (const stream of session.notificationStreams){
|
|
2559
|
-
this._sendSseEvent(stream, event, data);
|
|
2560
|
-
}
|
|
2561
|
-
}
|
|
2562
2590
|
/**
|
|
2563
2591
|
* Handle GET /metrics endpoint.
|
|
2564
2592
|
*/ _handleMetrics(res) {
|
|
@@ -2617,11 +2645,6 @@ function parseSessionRetentionOptions(options) {
|
|
|
2617
2645
|
* Update session-related metrics.
|
|
2618
2646
|
*/ _updateSessionMetrics() {
|
|
2619
2647
|
this._metrics?.gauge('streamable_http_active_sessions', this._sessions.size, {}, 'Active Streamable HTTP sessions');
|
|
2620
|
-
let totalStreams = 0;
|
|
2621
|
-
for (const session of this._sessions.values()){
|
|
2622
|
-
totalStreams += session.notificationStreams.size;
|
|
2623
|
-
}
|
|
2624
|
-
this._metrics?.gauge('streamable_http_notification_streams', totalStreams, {}, 'Active SSE notification streams');
|
|
2625
2648
|
}
|
|
2626
2649
|
/**
|
|
2627
2650
|
* Stop transport server with graceful shutdown.
|
|
@@ -2630,6 +2653,7 @@ function parseSessionRetentionOptions(options) {
|
|
|
2630
2653
|
*/ stop(timeout) {
|
|
2631
2654
|
if (this._stopPromise) return this._stopPromise;
|
|
2632
2655
|
this._isShuttingDown = true;
|
|
2656
|
+
this._preDispatch.closeAdmission('shutdown');
|
|
2633
2657
|
this._stopRateLimitCleanup();
|
|
2634
2658
|
this._stopSessionSweep();
|
|
2635
2659
|
const shutdownTimeout = timeout ?? 30000;
|
|
@@ -2665,7 +2689,7 @@ function parseSessionRetentionOptions(options) {
|
|
|
2665
2689
|
});
|
|
2666
2690
|
const stopPromise = Promise.all([
|
|
2667
2691
|
serverClosed,
|
|
2668
|
-
this._acceptedWork.join()
|
|
2692
|
+
this._preDispatch.join().then(()=>this._acceptedWork.join())
|
|
2669
2693
|
]).then(()=>{
|
|
2670
2694
|
this.log('info', 'Streamable HTTP transport stopped');
|
|
2671
2695
|
});
|
|
@@ -3179,7 +3203,7 @@ async function main() {
|
|
|
3179
3203
|
/**
|
|
3180
3204
|
* Start Streamable HTTP transport (MCP spec recommended)
|
|
3181
3205
|
*/ async function startStreamableHttpTransport(server, thinkingServer, lifecycle) {
|
|
3182
|
-
const { StreamableHttpTransport } = await Promise.resolve(/* import() */).then(__webpack_require__.bind(__webpack_require__, "
|
|
3206
|
+
const { StreamableHttpTransport } = await Promise.resolve(/* import() */).then(__webpack_require__.bind(__webpack_require__, "q"));
|
|
3183
3207
|
const port = parseInt(process.env.STREAMABLE_HTTP_PORT || '9007', 10);
|
|
3184
3208
|
const host = process.env.STREAMABLE_HTTP_HOST || 'localhost';
|
|
3185
3209
|
const transportMetrics = thinkingServer.getContainer().resolve('Metrics');
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"summary.d.ts","sourceRoot":"","sources":["../../src/contracts/summary.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,gCAAgC,CAAC;AAC9D,OAAO,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAE/D
|
|
1
|
+
{"version":3,"file":"summary.d.ts","sourceRoot":"","sources":["../../src/contracts/summary.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,gCAAgC,CAAC;AAC9D,OAAO,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAE/D;;;;;;;;;;;;;GAaG;AACH,MAAM,WAAW,aAAa;IAC7B;;;;;;;;;OASG;IACH,GAAG,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAAC;IAE5B;;;;;;;;;;;OAWG;IACH,GAAG,CAAC,EAAE,EAAE,SAAS,GAAG,OAAO,GAAG,SAAS,CAAC;IAExC;;;;;;;;;;;;OAYG;IACH,UAAU,CAAC,SAAS,EAAE,SAAS,GAAG,SAAS,OAAO,EAAE,CAAC;IAErD;;;;;;;;;;;OAWG;IACH,SAAS,CAAC,SAAS,EAAE,SAAS,EAAE,QAAQ,EAAE,QAAQ,GAAG,SAAS,OAAO,EAAE,CAAC;IAExE;;;;;;;;;OASG;IACH,YAAY,CAAC,SAAS,EAAE,SAAS,GAAG,IAAI,CAAC;IAEzC;;;OAGG;IACH,QAAQ,IAAI,IAAI,CAAC;IAEjB;;;;;;;;;;;;OAYG;IACH,IAAI,CAAC,SAAS,CAAC,EAAE,SAAS,GAAG,MAAM,CAAC;CACpC"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { PersistenceBackend } from '../contracts/PersistenceBackend.js';
|
|
2
2
|
import { type BranchId, type SessionId } from '../contracts/ids.js';
|
|
3
|
-
import type { Summary } from '
|
|
3
|
+
import type { Summary } from './compression/Summary.js';
|
|
4
4
|
import type { Edge } from './graph/Edge.js';
|
|
5
5
|
import type { ThoughtData } from './thought.js';
|
|
6
6
|
export type RestoredBranch = {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PersistenceRestore.d.ts","sourceRoot":"","sources":["../../src/core/PersistenceRestore.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACX,kBAAkB,EAElB,MAAM,oCAAoC,CAAC;AAC5C,OAAO,EAAkC,KAAK,QAAQ,EAAE,KAAK,SAAS,EAAE,MAAM,qBAAqB,CAAC;AACpG,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"PersistenceRestore.d.ts","sourceRoot":"","sources":["../../src/core/PersistenceRestore.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACX,kBAAkB,EAElB,MAAM,oCAAoC,CAAC;AAC5C,OAAO,EAAkC,KAAK,QAAQ,EAAE,KAAK,SAAS,EAAE,MAAM,qBAAqB,CAAC;AACpG,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,0BAA0B,CAAC;AAaxD,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAC;AAE5C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAEhD,MAAM,MAAM,cAAc,GAAG;IAC5B,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC;IAC5B,QAAQ,CAAC,QAAQ,EAAE,SAAS,WAAW,EAAE,CAAC;CAC1C,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG;IAC7B,QAAQ,CAAC,SAAS,EAAE,SAAS,CAAC;IAC9B,QAAQ,CAAC,OAAO,EAAE,SAAS,WAAW,EAAE,CAAC;IACzC,QAAQ,CAAC,QAAQ,EAAE,SAAS,cAAc,EAAE,CAAC;IAC7C,QAAQ,CAAC,KAAK,EAAE,SAAS,IAAI,EAAE,CAAC;IAChC,QAAQ,CAAC,SAAS,EAAE,SAAS,OAAO,EAAE,CAAC;CACvC,CAAC;AAEF,MAAM,MAAM,0BAA0B,GAAG;IACxC,QAAQ,CAAC,QAAQ,EAAE,SAAS,eAAe,EAAE,CAAC;CAC9C,CAAC;AA2EF,wBAAsB,uBAAuB,CAC5C,OAAO,EAAE,kBAAkB,GACzB,OAAO,CAAC,0BAA0B,CAAC,CAiBrC"}
|