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/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
- declare function bridgeMcpTools(client: McpClient, opts?: BridgeOptions): Promise<BridgeResult>;
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 = `${prefix}${mcpTool.name}`;
1082
- registry.register({
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);