poe-code 3.0.427 → 3.0.428
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/dist/index.js +2412 -2135
- package/dist/index.js.map +4 -4
- package/dist/metafile.json +1 -1
- package/dist/providers/poe-agent.js.map +1 -1
- package/package.json +2 -1
- package/packages/agent-trace-viewer/dist/breakdown.d.ts +5 -1
- package/packages/agent-trace-viewer/dist/breakdown.js +54 -5
- package/packages/agent-trace-viewer/dist/context.d.ts +1 -1
- package/packages/agent-trace-viewer/dist/context.js +2 -5
- package/packages/agent-trace-viewer/dist/loader.js +45 -2
- package/packages/agent-trace-viewer/dist/render.d.ts +4 -1
- package/packages/agent-trace-viewer/dist/render.js +63 -19
- package/packages/agent-trace-viewer/dist/run.js +31 -7
- package/packages/agent-trace-viewer/dist/token-cache.d.ts +10 -0
- package/packages/agent-trace-viewer/dist/token-cache.js +56 -0
- package/packages/agent-trace-viewer/dist/types.d.ts +5 -0
- package/packages/agent-traces/dist/types.d.ts +1 -0
- package/packages/tiny-http-mcp-server/dist/cli.js +23 -18
- package/packages/tiny-http-mcp-server/dist/http-transport.d.ts +6 -0
- package/packages/tiny-http-mcp-server/dist/http-transport.js +89 -55
- package/packages/tokenfill/dist/index.d.ts +0 -1
- package/packages/tokenfill/dist/index.js +0 -1
- package/packages/toolcraft-design/dist/explorer/reducer.js +14 -2
- package/packages/tokenfill/dist/estimate.d.ts +0 -2
- package/packages/tokenfill/dist/estimate.js +0 -38
|
@@ -68,6 +68,7 @@ export interface StreamableHttpTransportOptions {
|
|
|
68
68
|
sessionTtlMs?: number;
|
|
69
69
|
maxStreamsPerSession?: number;
|
|
70
70
|
maxSseEventHistory?: number;
|
|
71
|
+
sseKeepAliveMs?: number;
|
|
71
72
|
maxConcurrentToolCalls?: number;
|
|
72
73
|
sessionStore?: SessionStore;
|
|
73
74
|
requestIdGenerator?: () => string;
|
|
@@ -88,6 +89,7 @@ export declare class StreamableHttpTransport {
|
|
|
88
89
|
private readonly sessionTtlMs;
|
|
89
90
|
private readonly maxStreamsPerSession;
|
|
90
91
|
private readonly maxSseEventHistory;
|
|
92
|
+
private readonly sseKeepAliveMs;
|
|
91
93
|
private readonly maxConcurrentToolCalls;
|
|
92
94
|
private readonly sessionStore;
|
|
93
95
|
private readonly requestIdGenerator;
|
|
@@ -101,6 +103,7 @@ export declare class StreamableHttpTransport {
|
|
|
101
103
|
private nextNotificationEventId;
|
|
102
104
|
private nextRequestId;
|
|
103
105
|
private activeToolCalls;
|
|
106
|
+
private sseKeepAliveInterval;
|
|
104
107
|
constructor(server: Server, options?: StreamableHttpTransportOptions, runWithRequestContext?: RequestContextRunner);
|
|
105
108
|
handleRequest(req: IncomingMessage, res: ServerResponse): Promise<void>;
|
|
106
109
|
close(): Promise<void>;
|
|
@@ -122,6 +125,9 @@ export declare class StreamableHttpTransport {
|
|
|
122
125
|
private createLocalMessageSession;
|
|
123
126
|
private ensureLocalMessageSession;
|
|
124
127
|
private closeStreamsForSession;
|
|
128
|
+
private startSseKeepAlive;
|
|
129
|
+
private stopSseKeepAliveIfIdle;
|
|
130
|
+
private stopSseKeepAlive;
|
|
125
131
|
private sendNotificationToSession;
|
|
126
132
|
private recordSseEvent;
|
|
127
133
|
private replaySseEvents;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { validateHeaderValue } from "node:http";
|
|
2
2
|
import { JSON_RPC_ERROR_CODES } from "tiny-stdio-mcp-server";
|
|
3
|
-
import { formatErrorResponse, formatSuccessResponse
|
|
4
|
-
import { JsonRpcMessageError, readAndClassifyBody
|
|
5
|
-
import { createSessionStore, defaultSessionIdGenerator
|
|
3
|
+
import { formatErrorResponse, formatSuccessResponse } from "tiny-stdio-mcp-server/jsonrpc";
|
|
4
|
+
import { JsonRpcMessageError, readAndClassifyBody } from "./parse-body.js";
|
|
5
|
+
import { createSessionStore, defaultSessionIdGenerator } from "./session.js";
|
|
6
6
|
import { formatSseEvent, SSE_HEADERS } from "./sse.js";
|
|
7
7
|
const ALLOWED_METHODS = "POST, GET, DELETE, OPTIONS";
|
|
8
8
|
const MCP_SESSION_ID_HEADER = "Mcp-Session-Id";
|
|
@@ -30,6 +30,7 @@ export class StreamableHttpTransport {
|
|
|
30
30
|
sessionTtlMs;
|
|
31
31
|
maxStreamsPerSession;
|
|
32
32
|
maxSseEventHistory;
|
|
33
|
+
sseKeepAliveMs;
|
|
33
34
|
maxConcurrentToolCalls;
|
|
34
35
|
sessionStore;
|
|
35
36
|
requestIdGenerator;
|
|
@@ -43,13 +44,13 @@ export class StreamableHttpTransport {
|
|
|
43
44
|
nextNotificationEventId = 1;
|
|
44
45
|
nextRequestId = 1;
|
|
45
46
|
activeToolCalls = 0;
|
|
47
|
+
sseKeepAliveInterval;
|
|
46
48
|
constructor(server, options = {}, runWithRequestContext = async (_req, callback) => callback()) {
|
|
47
49
|
this.server = server;
|
|
48
50
|
this.runWithRequestContext = runWithRequestContext;
|
|
49
|
-
this.sessionIdGenerator =
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
: defaultSessionIdGenerator;
|
|
51
|
+
this.sessionIdGenerator = hasOwnProperty(options, "sessionIdGenerator")
|
|
52
|
+
? options.sessionIdGenerator
|
|
53
|
+
: defaultSessionIdGenerator;
|
|
53
54
|
this.enableJsonResponse = options.enableJsonResponse ?? false;
|
|
54
55
|
this.allowedOrigins = new Set(options.allowedOrigins ?? []);
|
|
55
56
|
this.allowedHosts = new Set((options.allowedHosts ?? LOCAL_HOSTS).map((host) => this.normalizeHost(host)));
|
|
@@ -57,13 +58,15 @@ export class StreamableHttpTransport {
|
|
|
57
58
|
this.maxBatchSize = validateOptionalIntegerOption("maxBatchSize", options.maxBatchSize, 1);
|
|
58
59
|
this.maxSessions = validateOptionalIntegerOption("maxSessions", options.maxSessions, 1);
|
|
59
60
|
this.sessionTtlMs = validateOptionalIntegerOption("sessionTtlMs", options.sessionTtlMs, 1);
|
|
60
|
-
this.maxStreamsPerSession =
|
|
61
|
+
this.maxStreamsPerSession =
|
|
62
|
+
validateOptionalIntegerOption("maxStreamsPerSession", options.maxStreamsPerSession, 1) ?? 1;
|
|
61
63
|
this.maxSseEventHistory =
|
|
62
64
|
validateOptionalIntegerOption("maxSseEventHistory", options.maxSseEventHistory, 0) ?? 100;
|
|
65
|
+
this.sseKeepAliveMs =
|
|
66
|
+
validateOptionalIntegerOption("sseKeepAliveMs", options.sseKeepAliveMs, 0) ?? 30_000;
|
|
63
67
|
this.maxConcurrentToolCalls = validateOptionalIntegerOption("maxConcurrentToolCalls", options.maxConcurrentToolCalls, 1);
|
|
64
68
|
this.sessionStore = options.sessionStore ?? createSessionStore();
|
|
65
|
-
this.requestIdGenerator =
|
|
66
|
-
options.requestIdGenerator ?? (() => `req-${this.nextRequestId++}`);
|
|
69
|
+
this.requestIdGenerator = options.requestIdGenerator ?? (() => `req-${this.nextRequestId++}`);
|
|
67
70
|
this.observability = options.observability ?? {};
|
|
68
71
|
this.trustedProxy = options.trustedProxy ?? false;
|
|
69
72
|
}
|
|
@@ -80,7 +83,7 @@ export class StreamableHttpTransport {
|
|
|
80
83
|
requestId,
|
|
81
84
|
method: req.method ?? "",
|
|
82
85
|
path: req.url ?? "",
|
|
83
|
-
sessionId: this.readSessionId(req)
|
|
86
|
+
sessionId: this.readSessionId(req)
|
|
84
87
|
});
|
|
85
88
|
try {
|
|
86
89
|
this.purgeExpiredSessions();
|
|
@@ -108,7 +111,7 @@ export class StreamableHttpTransport {
|
|
|
108
111
|
return;
|
|
109
112
|
default:
|
|
110
113
|
this.respondWithStatus(res, 405, undefined, {
|
|
111
|
-
Allow: ALLOWED_METHODS
|
|
114
|
+
Allow: ALLOWED_METHODS
|
|
112
115
|
});
|
|
113
116
|
}
|
|
114
117
|
}
|
|
@@ -119,7 +122,7 @@ export class StreamableHttpTransport {
|
|
|
119
122
|
method: req.method ?? "",
|
|
120
123
|
durationMs: Date.now() - startedAt,
|
|
121
124
|
error,
|
|
122
|
-
sessionId: this.readSessionId(req)
|
|
125
|
+
sessionId: this.readSessionId(req)
|
|
123
126
|
});
|
|
124
127
|
if (!res.headersSent) {
|
|
125
128
|
this.respondWithStatus(res, 500);
|
|
@@ -136,11 +139,12 @@ export class StreamableHttpTransport {
|
|
|
136
139
|
method: req.method ?? "",
|
|
137
140
|
statusCode: res.statusCode,
|
|
138
141
|
durationMs: Date.now() - startedAt,
|
|
139
|
-
sessionId: this.readSessionId(req)
|
|
142
|
+
sessionId: this.readSessionId(req)
|
|
140
143
|
});
|
|
141
144
|
}
|
|
142
145
|
}
|
|
143
146
|
async close() {
|
|
147
|
+
this.stopSseKeepAlive();
|
|
144
148
|
for (const sessionId of [...this.sseStreams.keys()]) {
|
|
145
149
|
this.closeStreamsForSession(sessionId);
|
|
146
150
|
}
|
|
@@ -162,7 +166,7 @@ export class StreamableHttpTransport {
|
|
|
162
166
|
try {
|
|
163
167
|
classified = await readAndClassifyBody(req, undefined, {
|
|
164
168
|
maxBytes: this.maxRequestBytes,
|
|
165
|
-
maxBatchSize: this.maxBatchSize
|
|
169
|
+
maxBatchSize: this.maxBatchSize
|
|
166
170
|
});
|
|
167
171
|
}
|
|
168
172
|
catch (error) {
|
|
@@ -211,7 +215,8 @@ export class StreamableHttpTransport {
|
|
|
211
215
|
}
|
|
212
216
|
sessionId = headerSessionId;
|
|
213
217
|
this.touchSession(sessionId);
|
|
214
|
-
if (session?.protocolVersion !== undefined &&
|
|
218
|
+
if (session?.protocolVersion !== undefined &&
|
|
219
|
+
!this.acceptsProtocolVersion(req, session.protocolVersion)) {
|
|
215
220
|
this.respondWithStatus(res, 400);
|
|
216
221
|
return;
|
|
217
222
|
}
|
|
@@ -224,7 +229,7 @@ export class StreamableHttpTransport {
|
|
|
224
229
|
if (message === null) {
|
|
225
230
|
responses.push(formatErrorResponse(null, {
|
|
226
231
|
code: JSON_RPC_ERROR_CODES.INVALID_REQUEST,
|
|
227
|
-
message: "Invalid Request"
|
|
232
|
+
message: "Invalid Request"
|
|
228
233
|
}));
|
|
229
234
|
continue;
|
|
230
235
|
}
|
|
@@ -232,35 +237,35 @@ export class StreamableHttpTransport {
|
|
|
232
237
|
continue;
|
|
233
238
|
}
|
|
234
239
|
const session = sessionId === undefined ? undefined : this.sessionStore.get(sessionId);
|
|
235
|
-
if (session !== undefined
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
+
if (session !== undefined &&
|
|
241
|
+
message.method !== "initialize" &&
|
|
242
|
+
message.method !== "notifications/initialized" &&
|
|
243
|
+
message.method !== "ping" &&
|
|
244
|
+
!session.initialized) {
|
|
240
245
|
if (this.isRequest(message)) {
|
|
241
246
|
responses.push(formatErrorResponse(message.id, {
|
|
242
247
|
code: JSON_RPC_ERROR_CODES.INVALID_REQUEST,
|
|
243
|
-
message: "Session not initialized"
|
|
248
|
+
message: "Session not initialized"
|
|
244
249
|
}));
|
|
245
250
|
}
|
|
246
251
|
continue;
|
|
247
252
|
}
|
|
248
253
|
const requestId = this.responseRequestIds.get(res) ?? "";
|
|
249
254
|
const toolName = this.readToolName(message);
|
|
250
|
-
if (message.method === "tools/call"
|
|
251
|
-
|
|
252
|
-
|
|
255
|
+
if (message.method === "tools/call" &&
|
|
256
|
+
this.maxConcurrentToolCalls !== undefined &&
|
|
257
|
+
this.activeToolCalls >= this.maxConcurrentToolCalls) {
|
|
253
258
|
if (this.isRequest(message)) {
|
|
254
259
|
responses.push(formatErrorResponse(message.id, {
|
|
255
260
|
code: -32000,
|
|
256
|
-
message: "Too many concurrent tool calls"
|
|
261
|
+
message: "Too many concurrent tool calls"
|
|
257
262
|
}));
|
|
258
263
|
}
|
|
259
264
|
continue;
|
|
260
265
|
}
|
|
261
266
|
const messageHandler = sessionId === undefined
|
|
262
267
|
? this.server.handleMessage
|
|
263
|
-
: this.sessionMessages.get(sessionId)?.handleMessage ?? this.server.handleMessage;
|
|
268
|
+
: (this.sessionMessages.get(sessionId)?.handleMessage ?? this.server.handleMessage);
|
|
264
269
|
const isToolCall = message.method === "tools/call";
|
|
265
270
|
const toolStartedAt = Date.now();
|
|
266
271
|
if (isToolCall) {
|
|
@@ -269,7 +274,7 @@ export class StreamableHttpTransport {
|
|
|
269
274
|
type: "tool.start",
|
|
270
275
|
requestId,
|
|
271
276
|
sessionId,
|
|
272
|
-
toolName
|
|
277
|
+
toolName
|
|
273
278
|
});
|
|
274
279
|
}
|
|
275
280
|
let handled;
|
|
@@ -289,7 +294,7 @@ export class StreamableHttpTransport {
|
|
|
289
294
|
sessionId,
|
|
290
295
|
toolName,
|
|
291
296
|
ok: this.isToolCallOk(error, result),
|
|
292
|
-
durationMs: Date.now() - toolStartedAt
|
|
297
|
+
durationMs: Date.now() - toolStartedAt
|
|
293
298
|
});
|
|
294
299
|
}
|
|
295
300
|
if (session !== undefined && error === undefined) {
|
|
@@ -299,8 +304,8 @@ export class StreamableHttpTransport {
|
|
|
299
304
|
session.protocolVersion = initializeResult.protocolVersion;
|
|
300
305
|
}
|
|
301
306
|
}
|
|
302
|
-
else if (message.method === "notifications/initialized"
|
|
303
|
-
|
|
307
|
+
else if (message.method === "notifications/initialized" &&
|
|
308
|
+
session.protocolVersion !== undefined) {
|
|
304
309
|
session.initialized = true;
|
|
305
310
|
}
|
|
306
311
|
}
|
|
@@ -337,7 +342,7 @@ export class StreamableHttpTransport {
|
|
|
337
342
|
async handleGet(req, res) {
|
|
338
343
|
if (this.sessionIdGenerator === undefined) {
|
|
339
344
|
this.respondWithStatus(res, 405, undefined, {
|
|
340
|
-
Allow: ALLOWED_METHODS
|
|
345
|
+
Allow: ALLOWED_METHODS
|
|
341
346
|
});
|
|
342
347
|
return;
|
|
343
348
|
}
|
|
@@ -356,9 +361,9 @@ export class StreamableHttpTransport {
|
|
|
356
361
|
return;
|
|
357
362
|
}
|
|
358
363
|
this.touchSession(sessionId);
|
|
359
|
-
if (session.initialized
|
|
360
|
-
|
|
361
|
-
|
|
364
|
+
if (session.initialized &&
|
|
365
|
+
session.protocolVersion !== undefined &&
|
|
366
|
+
!this.acceptsProtocolVersion(req, session.protocolVersion)) {
|
|
362
367
|
this.respondWithStatus(res, 400);
|
|
363
368
|
return;
|
|
364
369
|
}
|
|
@@ -374,10 +379,11 @@ export class StreamableHttpTransport {
|
|
|
374
379
|
this.sseStreams.set(sessionId, streams);
|
|
375
380
|
}
|
|
376
381
|
streams.add(res);
|
|
382
|
+
this.startSseKeepAlive();
|
|
377
383
|
this.emit({
|
|
378
384
|
type: "stream.opened",
|
|
379
385
|
sessionId,
|
|
380
|
-
streamCount: streams.size
|
|
386
|
+
streamCount: streams.size
|
|
381
387
|
});
|
|
382
388
|
const cleanup = () => {
|
|
383
389
|
const activeStreams = this.sseStreams.get(sessionId);
|
|
@@ -389,12 +395,13 @@ export class StreamableHttpTransport {
|
|
|
389
395
|
this.emit({
|
|
390
396
|
type: "stream.closed",
|
|
391
397
|
sessionId,
|
|
392
|
-
streamCount: activeStreams.size
|
|
398
|
+
streamCount: activeStreams.size
|
|
393
399
|
});
|
|
394
400
|
}
|
|
395
401
|
if (activeStreams.size === 0) {
|
|
396
402
|
this.sseStreams.delete(sessionId);
|
|
397
403
|
}
|
|
404
|
+
this.stopSseKeepAliveIfIdle();
|
|
398
405
|
};
|
|
399
406
|
req.on("close", cleanup);
|
|
400
407
|
res.on("close", cleanup);
|
|
@@ -406,7 +413,7 @@ export class StreamableHttpTransport {
|
|
|
406
413
|
handleDelete(req, res) {
|
|
407
414
|
if (this.sessionIdGenerator === undefined) {
|
|
408
415
|
this.respondWithStatus(res, 405, undefined, {
|
|
409
|
-
Allow: ALLOWED_METHODS
|
|
416
|
+
Allow: ALLOWED_METHODS
|
|
410
417
|
});
|
|
411
418
|
return;
|
|
412
419
|
}
|
|
@@ -416,7 +423,8 @@ export class StreamableHttpTransport {
|
|
|
416
423
|
return;
|
|
417
424
|
}
|
|
418
425
|
const session = this.getActiveSession(sessionId);
|
|
419
|
-
if (session?.protocolVersion !== undefined &&
|
|
426
|
+
if (session?.protocolVersion !== undefined &&
|
|
427
|
+
!this.acceptsProtocolVersion(req, session.protocolVersion)) {
|
|
420
428
|
this.respondWithStatus(res, 400);
|
|
421
429
|
return;
|
|
422
430
|
}
|
|
@@ -431,7 +439,7 @@ export class StreamableHttpTransport {
|
|
|
431
439
|
const method = Array.isArray(requestedMethod) ? requestedMethod[0] : requestedMethod;
|
|
432
440
|
if (method !== undefined && !ALLOWED_METHODS.split(", ").includes(method)) {
|
|
433
441
|
this.respondWithStatus(res, 405, undefined, {
|
|
434
|
-
Allow: ALLOWED_METHODS
|
|
442
|
+
Allow: ALLOWED_METHODS
|
|
435
443
|
});
|
|
436
444
|
return;
|
|
437
445
|
}
|
|
@@ -441,8 +449,8 @@ export class StreamableHttpTransport {
|
|
|
441
449
|
"Access-Control-Allow-Methods": ALLOWED_METHODS,
|
|
442
450
|
"Access-Control-Allow-Headers": Array.isArray(requestedHeaders)
|
|
443
451
|
? requestedHeaders.join(", ")
|
|
444
|
-
: requestedHeaders ?? DEFAULT_ALLOWED_HEADERS,
|
|
445
|
-
"Access-Control-Max-Age": "600"
|
|
452
|
+
: (requestedHeaders ?? DEFAULT_ALLOWED_HEADERS),
|
|
453
|
+
"Access-Control-Max-Age": "600"
|
|
446
454
|
});
|
|
447
455
|
}
|
|
448
456
|
readSessionId(req) {
|
|
@@ -546,7 +554,7 @@ export class StreamableHttpTransport {
|
|
|
546
554
|
const messageSession = this.createLocalMessageSession(sessionId);
|
|
547
555
|
if (session.protocolVersion !== undefined) {
|
|
548
556
|
await messageSession.handleMessage("initialize", {
|
|
549
|
-
protocolVersion: session.protocolVersion
|
|
557
|
+
protocolVersion: session.protocolVersion
|
|
550
558
|
});
|
|
551
559
|
if (session.initialized) {
|
|
552
560
|
await messageSession.handleMessage("notifications/initialized");
|
|
@@ -565,6 +573,35 @@ export class StreamableHttpTransport {
|
|
|
565
573
|
}
|
|
566
574
|
}
|
|
567
575
|
this.sseStreams.delete(sessionId);
|
|
576
|
+
this.stopSseKeepAliveIfIdle();
|
|
577
|
+
}
|
|
578
|
+
startSseKeepAlive() {
|
|
579
|
+
if (this.sseKeepAliveMs === 0 || this.sseKeepAliveInterval !== undefined) {
|
|
580
|
+
return;
|
|
581
|
+
}
|
|
582
|
+
this.sseKeepAliveInterval = setInterval(() => {
|
|
583
|
+
for (const streams of this.sseStreams.values()) {
|
|
584
|
+
for (const response of streams) {
|
|
585
|
+
if (!response.writableEnded) {
|
|
586
|
+
response.write(": keepalive\n\n");
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
}, this.sseKeepAliveMs);
|
|
591
|
+
this.sseKeepAliveInterval.unref();
|
|
592
|
+
}
|
|
593
|
+
stopSseKeepAliveIfIdle() {
|
|
594
|
+
if ([...this.sseStreams.values()].some((streams) => streams.size > 0)) {
|
|
595
|
+
return;
|
|
596
|
+
}
|
|
597
|
+
this.stopSseKeepAlive();
|
|
598
|
+
}
|
|
599
|
+
stopSseKeepAlive() {
|
|
600
|
+
if (this.sseKeepAliveInterval === undefined) {
|
|
601
|
+
return;
|
|
602
|
+
}
|
|
603
|
+
clearInterval(this.sseKeepAliveInterval);
|
|
604
|
+
this.sseKeepAliveInterval = undefined;
|
|
568
605
|
}
|
|
569
606
|
sendNotificationToSession(sessionId, notification) {
|
|
570
607
|
if (!this.sessionStore.get(sessionId)?.initialized) {
|
|
@@ -579,7 +616,7 @@ export class StreamableHttpTransport {
|
|
|
579
616
|
}
|
|
580
617
|
const event = formatSseEvent({
|
|
581
618
|
id: String(id),
|
|
582
|
-
data
|
|
619
|
+
data
|
|
583
620
|
});
|
|
584
621
|
let latestResponse;
|
|
585
622
|
for (const response of streams) {
|
|
@@ -659,7 +696,7 @@ export class StreamableHttpTransport {
|
|
|
659
696
|
}
|
|
660
697
|
}
|
|
661
698
|
const host = req.headers.host;
|
|
662
|
-
return Array.isArray(host) ? host[0] ?? "127.0.0.1" : host ?? "127.0.0.1";
|
|
699
|
+
return Array.isArray(host) ? (host[0] ?? "127.0.0.1") : (host ?? "127.0.0.1");
|
|
663
700
|
}
|
|
664
701
|
readForwardedHeader(req, headerName) {
|
|
665
702
|
const value = req.headers[headerName];
|
|
@@ -686,9 +723,7 @@ export class StreamableHttpTransport {
|
|
|
686
723
|
if (colonCount > 1) {
|
|
687
724
|
return normalized;
|
|
688
725
|
}
|
|
689
|
-
return normalized.includes(":")
|
|
690
|
-
? normalized.split(":")[0] ?? normalized
|
|
691
|
-
: normalized;
|
|
726
|
+
return normalized.includes(":") ? (normalized.split(":")[0] ?? normalized) : normalized;
|
|
692
727
|
}
|
|
693
728
|
acceptsConfiguredResponse(req) {
|
|
694
729
|
const expectedType = this.enableJsonResponse ? "application/json" : "text/event-stream";
|
|
@@ -727,8 +762,7 @@ export class StreamableHttpTransport {
|
|
|
727
762
|
if (typeof result !== "object" || result === null || Array.isArray(result)) {
|
|
728
763
|
return true;
|
|
729
764
|
}
|
|
730
|
-
return !(hasOwnProperty(result, "isError")
|
|
731
|
-
&& result.isError === true);
|
|
765
|
+
return !(hasOwnProperty(result, "isError") && result.isError === true);
|
|
732
766
|
}
|
|
733
767
|
respondWithJsonRpcError(res, statusCode, errorCode, message, id = null) {
|
|
734
768
|
this.respondWithStatus(res, statusCode, undefined, { "Content-Type": "application/json" }, formatErrorResponse(id, { code: errorCode, message }));
|
|
@@ -749,19 +783,19 @@ export class StreamableHttpTransport {
|
|
|
749
783
|
? {}
|
|
750
784
|
: {
|
|
751
785
|
"Access-Control-Allow-Origin": origin,
|
|
752
|
-
"Access-Control-Expose-Headers": "Mcp-Session-Id, X-Request-Id"
|
|
753
|
-
})
|
|
786
|
+
"Access-Control-Expose-Headers": "Mcp-Session-Id, X-Request-Id"
|
|
787
|
+
})
|
|
754
788
|
};
|
|
755
789
|
if (sessionId === undefined) {
|
|
756
790
|
return {
|
|
757
791
|
...baseHeaders,
|
|
758
|
-
...(headers ?? {})
|
|
792
|
+
...(headers ?? {})
|
|
759
793
|
};
|
|
760
794
|
}
|
|
761
795
|
return {
|
|
762
796
|
...baseHeaders,
|
|
763
797
|
...(headers ?? {}),
|
|
764
|
-
[MCP_SESSION_ID_HEADER]: sessionId
|
|
798
|
+
[MCP_SESSION_ID_HEADER]: sessionId
|
|
765
799
|
};
|
|
766
800
|
}
|
|
767
801
|
emit(event) {
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
export { countTokens, createTokenizer, DEFAULT_ENCODING } from "./tokenizer.js";
|
|
2
|
-
export { estimateTokens } from "./estimate.js";
|
|
3
2
|
export type { Tokenizer, TokenizerOptions } from "./tokenizer.js";
|
|
4
3
|
export { tokenfill } from "./tokenfill.js";
|
|
5
4
|
export type { TokenfillOptions, TokenfillResult } from "./tokenfill.js";
|
|
@@ -77,9 +77,13 @@ function stepKey(state, key, runtimeHandles) {
|
|
|
77
77
|
case "bottom":
|
|
78
78
|
return setCursor(state, state.filtered.length - 1);
|
|
79
79
|
case "pageUp":
|
|
80
|
-
return
|
|
80
|
+
return isDetailBlobFocused(state)
|
|
81
|
+
? detailScroll(state, -detailBodyHeight(state))
|
|
82
|
+
: moveCursor(state, -pageSize(state));
|
|
81
83
|
case "pageDown":
|
|
82
|
-
return
|
|
84
|
+
return isDetailBlobFocused(state)
|
|
85
|
+
? detailScroll(state, detailBodyHeight(state))
|
|
86
|
+
: moveCursor(state, pageSize(state));
|
|
83
87
|
case "focusNext":
|
|
84
88
|
return focusNext(state);
|
|
85
89
|
case "escape":
|
|
@@ -328,8 +332,16 @@ function moveCursor(state, delta) {
|
|
|
328
332
|
if (state.focused === "detail" && hasDetailCursor(state)) {
|
|
329
333
|
return moveDetailCursor(state, delta);
|
|
330
334
|
}
|
|
335
|
+
if (isDetailBlobFocused(state)) {
|
|
336
|
+
return detailScroll(state, delta);
|
|
337
|
+
}
|
|
331
338
|
return setCursor(state, state.cursor + delta);
|
|
332
339
|
}
|
|
340
|
+
function isDetailBlobFocused(state) {
|
|
341
|
+
return (state.focused === "detail" &&
|
|
342
|
+
!hasDetailCursor(state) &&
|
|
343
|
+
(state.detail.items?.length ?? 0) > 0);
|
|
344
|
+
}
|
|
333
345
|
function moveDetailCursor(state, delta) {
|
|
334
346
|
const max = Math.max(0, (state.detail.items?.length ?? 0) - 1);
|
|
335
347
|
const cursor = clamp(state.detail.cursor + delta, 0, max);
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import { countTokens } from "./tokenizer.js";
|
|
2
|
-
export const EXACT_COUNT_CHAR_LIMIT = 8192;
|
|
3
|
-
const SAMPLE_CHUNK_LENGTH = 2048;
|
|
4
|
-
export function estimateTokens(text) {
|
|
5
|
-
if (text.length <= EXACT_COUNT_CHAR_LIMIT) {
|
|
6
|
-
return countTokens(text);
|
|
7
|
-
}
|
|
8
|
-
const middleStart = Math.floor(text.length / 2 - SAMPLE_CHUNK_LENGTH / 2);
|
|
9
|
-
const sample = [
|
|
10
|
-
text.slice(0, SAMPLE_CHUNK_LENGTH),
|
|
11
|
-
text.slice(middleStart, middleStart + SAMPLE_CHUNK_LENGTH),
|
|
12
|
-
text.slice(text.length - SAMPLE_CHUNK_LENGTH)
|
|
13
|
-
]
|
|
14
|
-
.map(trimBrokenSurrogates)
|
|
15
|
-
.join("");
|
|
16
|
-
const sampleTokens = countTokens(sample);
|
|
17
|
-
if (sampleTokens === 0) {
|
|
18
|
-
return 0;
|
|
19
|
-
}
|
|
20
|
-
return Math.round((text.length / sample.length) * sampleTokens);
|
|
21
|
-
}
|
|
22
|
-
function trimBrokenSurrogates(value) {
|
|
23
|
-
let start = 0;
|
|
24
|
-
let end = value.length;
|
|
25
|
-
if (end > start && isLowSurrogate(value.charCodeAt(start))) {
|
|
26
|
-
start += 1;
|
|
27
|
-
}
|
|
28
|
-
if (end > start && isHighSurrogate(value.charCodeAt(end - 1))) {
|
|
29
|
-
end -= 1;
|
|
30
|
-
}
|
|
31
|
-
return value.slice(start, end);
|
|
32
|
-
}
|
|
33
|
-
function isHighSurrogate(code) {
|
|
34
|
-
return code >= 0xd800 && code <= 0xdbff;
|
|
35
|
-
}
|
|
36
|
-
function isLowSurrogate(code) {
|
|
37
|
-
return code >= 0xdc00 && code <= 0xdfff;
|
|
38
|
-
}
|