reasonix 0.21.0 → 0.22.0
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/cli/index.js +344 -91
- package/dist/cli/index.js.map +1 -1
- package/dist/index.d.ts +31 -1
- package/dist/index.js +32 -26
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -1637,6 +1637,19 @@ interface SlowEvent {
|
|
|
1637
1637
|
p95Ms: number;
|
|
1638
1638
|
sampleSize: number;
|
|
1639
1639
|
}
|
|
1640
|
+
interface LatencyTrackerOptions {
|
|
1641
|
+
thresholdMs?: number;
|
|
1642
|
+
onSlow?: (ev: SlowEvent) => void;
|
|
1643
|
+
}
|
|
1644
|
+
declare class LatencyTracker {
|
|
1645
|
+
private readonly serverName;
|
|
1646
|
+
private samples;
|
|
1647
|
+
private wasOverThreshold;
|
|
1648
|
+
private readonly thresholdMs;
|
|
1649
|
+
private readonly onSlow?;
|
|
1650
|
+
constructor(serverName: string, opts?: LatencyTrackerOptions);
|
|
1651
|
+
record(elapsedMs: number): void;
|
|
1652
|
+
}
|
|
1640
1653
|
|
|
1641
1654
|
interface BridgeOptions {
|
|
1642
1655
|
/** Prefix for tool names — disambiguates collisions when bridging multiple servers. */
|
|
@@ -1660,6 +1673,12 @@ interface BridgeOptions {
|
|
|
1660
1673
|
slowThresholdMs?: number;
|
|
1661
1674
|
/** Fired exactly when the per-server p95 transitions over `slowThresholdMs`. */
|
|
1662
1675
|
onSlow?: (ev: SlowEvent) => void;
|
|
1676
|
+
/** Indirection so reconnect can swap the underlying client without re-registering tools. */
|
|
1677
|
+
host?: McpClientHost;
|
|
1678
|
+
}
|
|
1679
|
+
/** Mutable holder so `/mcp reconnect` can swap the underlying client without re-bridging tools. */
|
|
1680
|
+
interface McpClientHost {
|
|
1681
|
+
client: McpClient;
|
|
1663
1682
|
}
|
|
1664
1683
|
declare const DEFAULT_MAX_RESULT_CHARS = 32000;
|
|
1665
1684
|
/** ~6% of DeepSeek V3 context. Char cap alone fails on CJK (~1 char/token). */
|
|
@@ -1674,7 +1693,18 @@ interface BridgeResult {
|
|
|
1674
1693
|
reason: string;
|
|
1675
1694
|
}>;
|
|
1676
1695
|
}
|
|
1677
|
-
|
|
1696
|
+
/** Resolved bridge environment that `registerSingleMcpTool` needs. Stored on summaries so reconnect can append new tools later. */
|
|
1697
|
+
interface BridgeEnv {
|
|
1698
|
+
registry: ToolRegistry;
|
|
1699
|
+
host: McpClientHost;
|
|
1700
|
+
prefix: string;
|
|
1701
|
+
maxResultChars: number;
|
|
1702
|
+
tracker: LatencyTracker | null;
|
|
1703
|
+
onProgress?: BridgeOptions["onProgress"];
|
|
1704
|
+
}
|
|
1705
|
+
declare function bridgeMcpTools(client: McpClient, opts?: BridgeOptions): Promise<BridgeResult & {
|
|
1706
|
+
env: BridgeEnv;
|
|
1707
|
+
}>;
|
|
1678
1708
|
interface FlattenOptions {
|
|
1679
1709
|
/** Cap the flattened string at this many characters. Default: no cap. */
|
|
1680
1710
|
maxChars?: number;
|
package/dist/index.js
CHANGED
|
@@ -1065,6 +1065,26 @@ function computeP95(samples) {
|
|
|
1065
1065
|
// src/mcp/registry.ts
|
|
1066
1066
|
var DEFAULT_MAX_RESULT_CHARS = 32e3;
|
|
1067
1067
|
var DEFAULT_MAX_RESULT_TOKENS = 8e3;
|
|
1068
|
+
function registerSingleMcpTool(mcpTool, env) {
|
|
1069
|
+
if (!mcpTool.name) return "";
|
|
1070
|
+
const registeredName = `${env.prefix}${mcpTool.name}`;
|
|
1071
|
+
env.registry.register({
|
|
1072
|
+
name: registeredName,
|
|
1073
|
+
description: mcpTool.description ?? "",
|
|
1074
|
+
parameters: mcpTool.inputSchema,
|
|
1075
|
+
fn: async (args, ctx) => {
|
|
1076
|
+
const t0 = env.tracker ? Date.now() : 0;
|
|
1077
|
+
const live = env.host.client;
|
|
1078
|
+
const toolResult = await live.callTool(mcpTool.name, args, {
|
|
1079
|
+
onProgress: env.onProgress ? (info) => env.onProgress({ toolName: registeredName, ...info }) : void 0,
|
|
1080
|
+
signal: ctx?.signal
|
|
1081
|
+
});
|
|
1082
|
+
if (env.tracker) env.tracker.record(Date.now() - t0);
|
|
1083
|
+
return flattenMcpResult(toolResult, { maxChars: env.maxResultChars });
|
|
1084
|
+
}
|
|
1085
|
+
});
|
|
1086
|
+
return registeredName;
|
|
1087
|
+
}
|
|
1068
1088
|
async function bridgeMcpTools(client, opts = {}) {
|
|
1069
1089
|
const registry = opts.registry ?? new ToolRegistry({ autoFlatten: opts.autoFlatten });
|
|
1070
1090
|
const prefix = opts.namePrefix ?? "";
|
|
@@ -1072,39 +1092,25 @@ async function bridgeMcpTools(client, opts = {}) {
|
|
|
1072
1092
|
const result = { registry, registeredNames: [], skipped: [] };
|
|
1073
1093
|
const serverName = opts.serverName ?? prefix.replace(/_$/, "") ?? "anon";
|
|
1074
1094
|
const tracker = opts.onSlow ? new LatencyTracker(serverName, { thresholdMs: opts.slowThresholdMs, onSlow: opts.onSlow }) : null;
|
|
1095
|
+
const host = opts.host ?? { client };
|
|
1096
|
+
const env = {
|
|
1097
|
+
registry,
|
|
1098
|
+
host,
|
|
1099
|
+
prefix,
|
|
1100
|
+
maxResultChars,
|
|
1101
|
+
tracker,
|
|
1102
|
+
onProgress: opts.onProgress
|
|
1103
|
+
};
|
|
1075
1104
|
const listed = await client.listTools();
|
|
1076
1105
|
for (const mcpTool of listed.tools) {
|
|
1077
1106
|
if (!mcpTool.name) {
|
|
1078
1107
|
result.skipped.push({ name: "?", reason: "empty tool name" });
|
|
1079
1108
|
continue;
|
|
1080
1109
|
}
|
|
1081
|
-
const registeredName =
|
|
1082
|
-
|
|
1083
|
-
name: registeredName,
|
|
1084
|
-
description: mcpTool.description ?? "",
|
|
1085
|
-
parameters: mcpTool.inputSchema,
|
|
1086
|
-
fn: async (args, ctx) => {
|
|
1087
|
-
const t0 = tracker ? Date.now() : 0;
|
|
1088
|
-
const toolResult = await client.callTool(mcpTool.name, args, {
|
|
1089
|
-
// Forward server-side progress frames to the bridge caller,
|
|
1090
|
-
// tagged with the registered name so multi-server UIs can
|
|
1091
|
-
// disambiguate. No-op when `onProgress` isn't configured —
|
|
1092
|
-
// the client then also omits the _meta.progressToken and
|
|
1093
|
-
// the server won't emit progress.
|
|
1094
|
-
onProgress: opts.onProgress ? (info) => opts.onProgress({ toolName: registeredName, ...info }) : void 0,
|
|
1095
|
-
// Thread the tool-dispatch AbortSignal all the way down to
|
|
1096
|
-
// the MCP request so Esc truly cancels in flight — the
|
|
1097
|
-
// client will emit notifications/cancelled AND reject the
|
|
1098
|
-
// pending promise immediately, no "wait for subprocess".
|
|
1099
|
-
signal: ctx?.signal
|
|
1100
|
-
});
|
|
1101
|
-
if (tracker) tracker.record(Date.now() - t0);
|
|
1102
|
-
return flattenMcpResult(toolResult, { maxChars: maxResultChars });
|
|
1103
|
-
}
|
|
1104
|
-
});
|
|
1105
|
-
result.registeredNames.push(registeredName);
|
|
1110
|
+
const registeredName = registerSingleMcpTool(mcpTool, env);
|
|
1111
|
+
if (registeredName) result.registeredNames.push(registeredName);
|
|
1106
1112
|
}
|
|
1107
|
-
return result;
|
|
1113
|
+
return { ...result, env };
|
|
1108
1114
|
}
|
|
1109
1115
|
function flattenMcpResult(result, opts = {}) {
|
|
1110
1116
|
const parts = result.content.map(blockToString);
|