reasonix 0.11.2 → 0.12.6
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/dashboard/app.css +2346 -0
- package/dashboard/app.js +3913 -0
- package/dashboard/codemirror.js +36 -0
- package/dashboard/index.html +19 -0
- package/dist/cli/{chunk-JDVY4JDU.js → chunk-PKPWI33U.js} +3 -1
- package/dist/cli/index.js +2646 -191
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/{prompt-YRY4HPMZ.js → prompt-HNDDXDRH.js} +2 -2
- package/dist/index.d.ts +181 -31
- package/dist/index.js +221 -24
- package/dist/index.js.map +1 -1
- package/package.json +102 -76
- /package/dist/cli/{chunk-JDVY4JDU.js.map → chunk-PKPWI33U.js.map} +0 -0
- /package/dist/cli/{prompt-YRY4HPMZ.js.map → prompt-HNDDXDRH.js.map} +0 -0
package/dist/index.js
CHANGED
|
@@ -1358,25 +1358,32 @@ function coerceToToolCall(candidateJson, allowedNames) {
|
|
|
1358
1358
|
var StormBreaker = class {
|
|
1359
1359
|
windowSize;
|
|
1360
1360
|
threshold;
|
|
1361
|
+
isMutating;
|
|
1361
1362
|
recent = [];
|
|
1362
|
-
constructor(windowSize = 6, threshold = 3) {
|
|
1363
|
+
constructor(windowSize = 6, threshold = 3, isMutating) {
|
|
1363
1364
|
this.windowSize = windowSize;
|
|
1364
1365
|
this.threshold = threshold;
|
|
1366
|
+
this.isMutating = isMutating;
|
|
1365
1367
|
}
|
|
1366
1368
|
inspect(call) {
|
|
1367
|
-
const
|
|
1368
|
-
if (!
|
|
1369
|
-
const
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
)
|
|
1369
|
+
const name = call.function?.name;
|
|
1370
|
+
if (!name) return { suppress: false };
|
|
1371
|
+
const args = call.function?.arguments ?? "";
|
|
1372
|
+
const mutating = this.isMutating ? this.isMutating(call) : false;
|
|
1373
|
+
const readOnly = !mutating;
|
|
1374
|
+
if (mutating) {
|
|
1375
|
+
for (let i = this.recent.length - 1; i >= 0; i--) {
|
|
1376
|
+
if (this.recent[i].readOnly) this.recent.splice(i, 1);
|
|
1377
|
+
}
|
|
1378
|
+
}
|
|
1379
|
+
const count = this.recent.reduce((n, e) => e.name === name && e.args === args ? n + 1 : n, 0);
|
|
1373
1380
|
if (count >= this.threshold - 1) {
|
|
1374
1381
|
return {
|
|
1375
1382
|
suppress: true,
|
|
1376
|
-
reason: `call-storm suppressed: ${
|
|
1383
|
+
reason: `call-storm suppressed: ${name} called with identical args ${count + 1} times within window=${this.windowSize}`
|
|
1377
1384
|
};
|
|
1378
1385
|
}
|
|
1379
|
-
this.recent.push(
|
|
1386
|
+
this.recent.push({ name, args, readOnly });
|
|
1380
1387
|
while (this.recent.length > this.windowSize) this.recent.shift();
|
|
1381
1388
|
return { suppress: false };
|
|
1382
1389
|
}
|
|
@@ -1384,11 +1391,6 @@ var StormBreaker = class {
|
|
|
1384
1391
|
this.recent.length = 0;
|
|
1385
1392
|
}
|
|
1386
1393
|
};
|
|
1387
|
-
function signature(call) {
|
|
1388
|
-
const name = call.function?.name;
|
|
1389
|
-
if (!name) return null;
|
|
1390
|
-
return [name, call.function?.arguments ?? ""];
|
|
1391
|
-
}
|
|
1392
1394
|
|
|
1393
1395
|
// src/repair/truncation.ts
|
|
1394
1396
|
function repairTruncatedJson(input) {
|
|
@@ -1466,7 +1468,7 @@ var ToolCallRepair = class {
|
|
|
1466
1468
|
opts;
|
|
1467
1469
|
constructor(opts) {
|
|
1468
1470
|
this.opts = opts;
|
|
1469
|
-
this.storm = new StormBreaker(opts.stormWindow ?? 6, opts.stormThreshold ?? 3);
|
|
1471
|
+
this.storm = new StormBreaker(opts.stormWindow ?? 6, opts.stormThreshold ?? 3, opts.isMutating);
|
|
1470
1472
|
}
|
|
1471
1473
|
/**
|
|
1472
1474
|
* Drop the StormBreaker's sliding window of recent (name, args)
|
|
@@ -1490,13 +1492,13 @@ var ToolCallRepair = class {
|
|
|
1490
1492
|
allowedNames: this.opts.allowedToolNames,
|
|
1491
1493
|
maxCalls: this.opts.maxScavenge ?? 4
|
|
1492
1494
|
});
|
|
1493
|
-
const seenSignatures = new Set(declaredCalls.map(
|
|
1495
|
+
const seenSignatures = new Set(declaredCalls.map(signature));
|
|
1494
1496
|
const merged = [...declaredCalls];
|
|
1495
1497
|
for (const sc of scavenged.calls) {
|
|
1496
|
-
if (!seenSignatures.has(
|
|
1498
|
+
if (!seenSignatures.has(signature(sc))) {
|
|
1497
1499
|
merged.push(sc);
|
|
1498
1500
|
report.scavenged++;
|
|
1499
|
-
seenSignatures.add(
|
|
1501
|
+
seenSignatures.add(signature(sc));
|
|
1500
1502
|
}
|
|
1501
1503
|
}
|
|
1502
1504
|
report.notes.push(...scavenged.notes);
|
|
@@ -1522,7 +1524,7 @@ var ToolCallRepair = class {
|
|
|
1522
1524
|
return { calls: filtered, report };
|
|
1523
1525
|
}
|
|
1524
1526
|
};
|
|
1525
|
-
function
|
|
1527
|
+
function signature(call) {
|
|
1526
1528
|
return `${call.function?.name ?? ""}::${call.function?.arguments ?? ""}`;
|
|
1527
1529
|
}
|
|
1528
1530
|
|
|
@@ -1661,6 +1663,12 @@ function outputCostUsd(model, usage) {
|
|
|
1661
1663
|
if (!p) return 0;
|
|
1662
1664
|
return usage.completionTokens * p.output / 1e6;
|
|
1663
1665
|
}
|
|
1666
|
+
function cacheSavingsUsd(model, hitTokens) {
|
|
1667
|
+
if (hitTokens <= 0) return 0;
|
|
1668
|
+
const p = DEEPSEEK_PRICING[model];
|
|
1669
|
+
if (!p) return 0;
|
|
1670
|
+
return hitTokens * (p.inputCacheMiss - p.inputCacheHit) / 1e6;
|
|
1671
|
+
}
|
|
1664
1672
|
function claudeEquivalentCost(usage) {
|
|
1665
1673
|
return (usage.promptTokens * CLAUDE_SONNET_PRICING.input + usage.completionTokens * CLAUDE_SONNET_PRICING.output) / 1e6;
|
|
1666
1674
|
}
|
|
@@ -1751,6 +1759,13 @@ var CacheFirstLoop = class {
|
|
|
1751
1759
|
branchOptions;
|
|
1752
1760
|
/** See ReconfigurableOptions — mutable so `/effort` can flip mid-session. */
|
|
1753
1761
|
reasoningEffort;
|
|
1762
|
+
/**
|
|
1763
|
+
* Auto-escalation toggle. `true` lets the loop self-promote to pro
|
|
1764
|
+
* mid-turn (NEEDS_PRO marker / failure threshold); `false` keeps it
|
|
1765
|
+
* pinned to `model`. Mutable so the dashboard's preset switcher can
|
|
1766
|
+
* flip it live alongside `model`.
|
|
1767
|
+
*/
|
|
1768
|
+
autoEscalate = true;
|
|
1754
1769
|
sessionName;
|
|
1755
1770
|
/**
|
|
1756
1771
|
* Hook list, mutable so `/hooks reload` can swap it without
|
|
@@ -1815,6 +1830,7 @@ var CacheFirstLoop = class {
|
|
|
1815
1830
|
this.tools = opts.tools ?? new ToolRegistry();
|
|
1816
1831
|
this.model = opts.model ?? "deepseek-v4-flash";
|
|
1817
1832
|
this.reasoningEffort = opts.reasoningEffort ?? "max";
|
|
1833
|
+
if (opts.autoEscalate !== void 0) this.autoEscalate = opts.autoEscalate;
|
|
1818
1834
|
this.maxToolIters = opts.maxToolIters ?? 64;
|
|
1819
1835
|
this.hooks = opts.hooks ?? [];
|
|
1820
1836
|
this.hookCwd = opts.hookCwd ?? process.cwd();
|
|
@@ -1832,7 +1848,26 @@ var CacheFirstLoop = class {
|
|
|
1832
1848
|
this._streamPreference = opts.stream ?? true;
|
|
1833
1849
|
this.stream = this.branchEnabled ? false : this._streamPreference;
|
|
1834
1850
|
const allowedNames = /* @__PURE__ */ new Set([...this.prefix.toolSpecs.map((s) => s.function.name)]);
|
|
1835
|
-
|
|
1851
|
+
const registry = this.tools;
|
|
1852
|
+
const isMutating = (call) => {
|
|
1853
|
+
const name = call.function?.name;
|
|
1854
|
+
if (!name) return false;
|
|
1855
|
+
const def = registry.get(name);
|
|
1856
|
+
if (!def) return false;
|
|
1857
|
+
if (def.readOnlyCheck) {
|
|
1858
|
+
let args = {};
|
|
1859
|
+
try {
|
|
1860
|
+
args = JSON.parse(call.function?.arguments ?? "{}") ?? {};
|
|
1861
|
+
} catch {
|
|
1862
|
+
}
|
|
1863
|
+
try {
|
|
1864
|
+
if (def.readOnlyCheck(args)) return false;
|
|
1865
|
+
} catch {
|
|
1866
|
+
}
|
|
1867
|
+
}
|
|
1868
|
+
return def.readOnly !== true;
|
|
1869
|
+
};
|
|
1870
|
+
this.repair = new ToolCallRepair({ allowedToolNames: allowedNames, isMutating });
|
|
1836
1871
|
this.sessionName = opts.session ?? null;
|
|
1837
1872
|
if (this.sessionName) {
|
|
1838
1873
|
const prior = loadSessionMessages(this.sessionName);
|
|
@@ -2013,6 +2048,7 @@ var CacheFirstLoop = class {
|
|
|
2013
2048
|
if (opts.model !== void 0) this.model = opts.model;
|
|
2014
2049
|
if (opts.stream !== void 0) this._streamPreference = opts.stream;
|
|
2015
2050
|
if (opts.reasoningEffort !== void 0) this.reasoningEffort = opts.reasoningEffort;
|
|
2051
|
+
if (opts.autoEscalate !== void 0) this.autoEscalate = opts.autoEscalate;
|
|
2016
2052
|
if (opts.branch !== void 0) {
|
|
2017
2053
|
if (typeof opts.branch === "number") {
|
|
2018
2054
|
this.branchOptions = { budget: opts.branch };
|
|
@@ -2128,7 +2164,7 @@ var CacheFirstLoop = class {
|
|
|
2128
2164
|
if (repair.truncationsFixed > 0) bump("truncated", repair.truncationsFixed);
|
|
2129
2165
|
if (repair.stormsBroken > 0) bump("storm-broken", repair.stormsBroken);
|
|
2130
2166
|
}
|
|
2131
|
-
if (bumped && !this._escalateThisTurn && this._turnFailureCount >= FAILURE_ESCALATION_THRESHOLD) {
|
|
2167
|
+
if (bumped && !this._escalateThisTurn && this.autoEscalate && this._turnFailureCount >= FAILURE_ESCALATION_THRESHOLD) {
|
|
2132
2168
|
this._escalateThisTurn = true;
|
|
2133
2169
|
return true;
|
|
2134
2170
|
}
|
|
@@ -2373,7 +2409,7 @@ var CacheFirstLoop = class {
|
|
|
2373
2409
|
const callBuf = /* @__PURE__ */ new Map();
|
|
2374
2410
|
const readyIndices = /* @__PURE__ */ new Set();
|
|
2375
2411
|
const callModel = this.modelForCurrentCall();
|
|
2376
|
-
const bufferForEscalation = callModel !== ESCALATION_MODEL;
|
|
2412
|
+
const bufferForEscalation = this.autoEscalate && callModel !== ESCALATION_MODEL;
|
|
2377
2413
|
let escalationBuf = "";
|
|
2378
2414
|
let escalationBufFlushed = false;
|
|
2379
2415
|
for await (const chunk of this.client.stream({
|
|
@@ -2485,7 +2521,7 @@ var CacheFirstLoop = class {
|
|
|
2485
2521
|
};
|
|
2486
2522
|
return;
|
|
2487
2523
|
}
|
|
2488
|
-
if (this.modelForCurrentCall() !== ESCALATION_MODEL && this.isEscalationRequest(assistantContent)) {
|
|
2524
|
+
if (this.autoEscalate && this.modelForCurrentCall() !== ESCALATION_MODEL && this.isEscalationRequest(assistantContent)) {
|
|
2489
2525
|
const { reason } = this.parseEscalationMarker(assistantContent);
|
|
2490
2526
|
this._escalateThisTurn = true;
|
|
2491
2527
|
const reasonSuffix = reason ? ` \u2014 ${reason}` : "";
|
|
@@ -7325,6 +7361,159 @@ var SseTransport = class {
|
|
|
7325
7361
|
}
|
|
7326
7362
|
};
|
|
7327
7363
|
|
|
7364
|
+
// src/mcp/streamable-http.ts
|
|
7365
|
+
import { createParser as createParser3 } from "eventsource-parser";
|
|
7366
|
+
var SESSION_HEADER = "mcp-session-id";
|
|
7367
|
+
var StreamableHttpTransport = class {
|
|
7368
|
+
url;
|
|
7369
|
+
extraHeaders;
|
|
7370
|
+
queue = [];
|
|
7371
|
+
waiters = [];
|
|
7372
|
+
controller = new AbortController();
|
|
7373
|
+
/** Session id minted by server on (typically) the initialize response. */
|
|
7374
|
+
sessionId = null;
|
|
7375
|
+
closed = false;
|
|
7376
|
+
/** Background SSE read-loops kicked off by send(); awaited on close(). */
|
|
7377
|
+
streams = /* @__PURE__ */ new Set();
|
|
7378
|
+
constructor(opts) {
|
|
7379
|
+
this.url = opts.url;
|
|
7380
|
+
this.extraHeaders = opts.headers ?? {};
|
|
7381
|
+
}
|
|
7382
|
+
async send(message) {
|
|
7383
|
+
if (this.closed) throw new Error("MCP Streamable HTTP transport is closed");
|
|
7384
|
+
const headers = {
|
|
7385
|
+
"content-type": "application/json",
|
|
7386
|
+
// Both accepted — server picks. application/json first signals a
|
|
7387
|
+
// mild preference for the simpler shape when the response is a
|
|
7388
|
+
// single message.
|
|
7389
|
+
accept: "application/json, text/event-stream",
|
|
7390
|
+
...this.extraHeaders
|
|
7391
|
+
};
|
|
7392
|
+
if (this.sessionId !== null) headers["mcp-session-id"] = this.sessionId;
|
|
7393
|
+
let res;
|
|
7394
|
+
try {
|
|
7395
|
+
res = await fetch(this.url, {
|
|
7396
|
+
method: "POST",
|
|
7397
|
+
headers,
|
|
7398
|
+
body: JSON.stringify(message),
|
|
7399
|
+
signal: this.controller.signal
|
|
7400
|
+
});
|
|
7401
|
+
} catch (err) {
|
|
7402
|
+
throw new Error(`MCP Streamable HTTP POST ${this.url} failed: ${err.message}`);
|
|
7403
|
+
}
|
|
7404
|
+
const serverSessionId = res.headers.get(SESSION_HEADER);
|
|
7405
|
+
if (serverSessionId && this.sessionId === null) {
|
|
7406
|
+
this.sessionId = serverSessionId;
|
|
7407
|
+
}
|
|
7408
|
+
if (res.status === 404 && this.sessionId !== null) {
|
|
7409
|
+
await res.body?.cancel().catch(() => void 0);
|
|
7410
|
+
throw new Error(
|
|
7411
|
+
`MCP Streamable HTTP session expired (server returned 404 with Mcp-Session-Id "${this.sessionId}"). Reinitialize the client.`
|
|
7412
|
+
);
|
|
7413
|
+
}
|
|
7414
|
+
if (!res.ok) {
|
|
7415
|
+
const body = await res.text().catch(() => "");
|
|
7416
|
+
throw new Error(
|
|
7417
|
+
`MCP Streamable HTTP POST ${this.url} \u2192 ${res.status} ${res.statusText}${body ? `: ${body}` : ""}`
|
|
7418
|
+
);
|
|
7419
|
+
}
|
|
7420
|
+
if (res.status === 202) {
|
|
7421
|
+
await res.body?.cancel().catch(() => void 0);
|
|
7422
|
+
return;
|
|
7423
|
+
}
|
|
7424
|
+
const ct = (res.headers.get("content-type") ?? "").toLowerCase();
|
|
7425
|
+
if (ct.includes("application/json")) {
|
|
7426
|
+
let parsed;
|
|
7427
|
+
try {
|
|
7428
|
+
parsed = await res.json();
|
|
7429
|
+
} catch (err) {
|
|
7430
|
+
throw new Error(`MCP Streamable HTTP body wasn't valid JSON: ${err.message}`);
|
|
7431
|
+
}
|
|
7432
|
+
if (Array.isArray(parsed)) {
|
|
7433
|
+
for (const item of parsed) this.pushMessage(item);
|
|
7434
|
+
} else {
|
|
7435
|
+
this.pushMessage(parsed);
|
|
7436
|
+
}
|
|
7437
|
+
return;
|
|
7438
|
+
}
|
|
7439
|
+
if (ct.includes("text/event-stream")) {
|
|
7440
|
+
if (!res.body) {
|
|
7441
|
+
throw new Error("MCP Streamable HTTP SSE response had no body");
|
|
7442
|
+
}
|
|
7443
|
+
const stream = this.consumeStream(res.body);
|
|
7444
|
+
this.streams.add(stream);
|
|
7445
|
+
stream.finally(() => this.streams.delete(stream));
|
|
7446
|
+
return;
|
|
7447
|
+
}
|
|
7448
|
+
await res.body?.cancel().catch(() => void 0);
|
|
7449
|
+
}
|
|
7450
|
+
async *messages() {
|
|
7451
|
+
while (true) {
|
|
7452
|
+
if (this.queue.length > 0) {
|
|
7453
|
+
yield this.queue.shift();
|
|
7454
|
+
continue;
|
|
7455
|
+
}
|
|
7456
|
+
if (this.closed) return;
|
|
7457
|
+
const next = await new Promise((resolve9) => {
|
|
7458
|
+
this.waiters.push(resolve9);
|
|
7459
|
+
});
|
|
7460
|
+
if (next === null) return;
|
|
7461
|
+
yield next;
|
|
7462
|
+
}
|
|
7463
|
+
}
|
|
7464
|
+
async close() {
|
|
7465
|
+
if (this.closed) return;
|
|
7466
|
+
this.closed = true;
|
|
7467
|
+
while (this.waiters.length > 0) this.waiters.shift()(null);
|
|
7468
|
+
try {
|
|
7469
|
+
this.controller.abort();
|
|
7470
|
+
} catch {
|
|
7471
|
+
}
|
|
7472
|
+
await Promise.allSettled(Array.from(this.streams));
|
|
7473
|
+
}
|
|
7474
|
+
/** Visible for tests — confirm session header round-trip. */
|
|
7475
|
+
getSessionId() {
|
|
7476
|
+
return this.sessionId;
|
|
7477
|
+
}
|
|
7478
|
+
// ---------- internals ----------
|
|
7479
|
+
async consumeStream(body) {
|
|
7480
|
+
const parser = createParser3({
|
|
7481
|
+
onEvent: (ev) => {
|
|
7482
|
+
const type = ev.event ?? "message";
|
|
7483
|
+
if (type !== "message") return;
|
|
7484
|
+
try {
|
|
7485
|
+
const parsed = JSON.parse(ev.data);
|
|
7486
|
+
this.pushMessage(parsed);
|
|
7487
|
+
} catch {
|
|
7488
|
+
}
|
|
7489
|
+
}
|
|
7490
|
+
});
|
|
7491
|
+
const decoder = new TextDecoder();
|
|
7492
|
+
try {
|
|
7493
|
+
for await (const chunk of body) {
|
|
7494
|
+
if (this.closed) break;
|
|
7495
|
+
parser.feed(decoder.decode(chunk, { stream: true }));
|
|
7496
|
+
}
|
|
7497
|
+
} catch (err) {
|
|
7498
|
+
if (!this.closed) {
|
|
7499
|
+
this.pushMessage({
|
|
7500
|
+
jsonrpc: "2.0",
|
|
7501
|
+
id: null,
|
|
7502
|
+
error: {
|
|
7503
|
+
code: -32e3,
|
|
7504
|
+
message: `Streamable HTTP stream error: ${err.message}`
|
|
7505
|
+
}
|
|
7506
|
+
});
|
|
7507
|
+
}
|
|
7508
|
+
}
|
|
7509
|
+
}
|
|
7510
|
+
pushMessage(msg) {
|
|
7511
|
+
const waiter = this.waiters.shift();
|
|
7512
|
+
if (waiter) waiter(msg);
|
|
7513
|
+
else this.queue.push(msg);
|
|
7514
|
+
}
|
|
7515
|
+
};
|
|
7516
|
+
|
|
7328
7517
|
// src/mcp/shell-split.ts
|
|
7329
7518
|
function shellSplit(input) {
|
|
7330
7519
|
const tokens = [];
|
|
@@ -7377,6 +7566,7 @@ function shellSplit(input) {
|
|
|
7377
7566
|
// src/mcp/spec.ts
|
|
7378
7567
|
var NAME_PREFIX = /^([a-zA-Z_][a-zA-Z0-9_]*)=(.*)$/;
|
|
7379
7568
|
var HTTP_URL = /^https?:\/\//i;
|
|
7569
|
+
var STREAMABLE_PREFIX = /^streamable\+(https?:\/\/.+)$/i;
|
|
7380
7570
|
function parseMcpSpec(input) {
|
|
7381
7571
|
const trimmed = input.trim();
|
|
7382
7572
|
if (!trimmed) {
|
|
@@ -7388,6 +7578,10 @@ function parseMcpSpec(input) {
|
|
|
7388
7578
|
if (!body) {
|
|
7389
7579
|
throw new Error(`MCP spec has name but no command: ${input}`);
|
|
7390
7580
|
}
|
|
7581
|
+
const streamMatch = STREAMABLE_PREFIX.exec(body);
|
|
7582
|
+
if (streamMatch) {
|
|
7583
|
+
return { transport: "streamable-http", name, url: streamMatch[1] };
|
|
7584
|
+
}
|
|
7391
7585
|
if (HTTP_URL.test(body)) {
|
|
7392
7586
|
return { transport: "sse", name, url: body };
|
|
7393
7587
|
}
|
|
@@ -8000,7 +8194,8 @@ function emptyBucket(label, since) {
|
|
|
8000
8194
|
cacheHitTokens: 0,
|
|
8001
8195
|
cacheMissTokens: 0,
|
|
8002
8196
|
costUsd: 0,
|
|
8003
|
-
claudeEquivUsd: 0
|
|
8197
|
+
claudeEquivUsd: 0,
|
|
8198
|
+
cacheSavingsUsd: 0
|
|
8004
8199
|
};
|
|
8005
8200
|
}
|
|
8006
8201
|
function addToBucket(b, r) {
|
|
@@ -8011,6 +8206,7 @@ function addToBucket(b, r) {
|
|
|
8011
8206
|
b.cacheMissTokens += r.cacheMissTokens;
|
|
8012
8207
|
b.costUsd += r.costUsd;
|
|
8013
8208
|
b.claudeEquivUsd += r.claudeEquivUsd;
|
|
8209
|
+
b.cacheSavingsUsd += cacheSavingsUsd(r.model, r.cacheHitTokens);
|
|
8014
8210
|
}
|
|
8015
8211
|
function aggregateUsage(records, opts = {}) {
|
|
8016
8212
|
const now = opts.now ?? Date.now();
|
|
@@ -8112,6 +8308,7 @@ export {
|
|
|
8112
8308
|
SseTransport,
|
|
8113
8309
|
StdioTransport,
|
|
8114
8310
|
StormBreaker,
|
|
8311
|
+
StreamableHttpTransport,
|
|
8115
8312
|
ToolCallRepair,
|
|
8116
8313
|
ToolRegistry,
|
|
8117
8314
|
USER_MEMORY_DIR,
|