@@ -2,7 +2,7 @@ import { afterAll, beforeEach, describe, expect, it, vi } from "vitest";
22import type { CallGatewayScopedOptions } from "../../gateway/call.js" ;
33import { createEmptyPluginRegistry } from "../../plugins/registry-empty.js" ;
44import { setActivePluginRegistry } from "../../plugins/runtime.js" ;
5- import { callGatewayTool , resolveGatewayOptions } from "./gateway.js" ;
5+ import { callGatewayTool , readGatewayCallOptions , resolveGatewayOptions } from "./gateway.js" ;
66
77const mocks = vi . hoisted ( ( ) => ( {
88 callGateway : vi . fn ( ) ,
@@ -68,6 +68,24 @@ describe("gateway tool defaults", () => {
6868 expect ( call . scopes ) . toEqual ( [ "operator.read" ] ) ;
6969 } ) ;
7070
71+ it ( "rejects invalid gateway timeoutMs before RPC" , async ( ) => {
72+ expect ( ( ) => readGatewayCallOptions ( { timeoutMs : - 1 } ) ) . toThrow (
73+ "timeoutMs must be a positive integer" ,
74+ ) ;
75+ expect ( ( ) => readGatewayCallOptions ( { timeoutMs : 1.5 } ) ) . toThrow (
76+ "timeoutMs must be a positive integer" ,
77+ ) ;
78+ expect ( mocks . callGateway ) . not . toHaveBeenCalled ( ) ;
79+ } ) ;
80+
81+ it ( "accepts string gateway timeoutMs through the shared numeric reader" , async ( ) => {
82+ mocks . callGateway . mockResolvedValueOnce ( { ok : true } ) ;
83+
84+ await callGatewayTool ( "health" , readGatewayCallOptions ( { timeoutMs : "5000" } ) , { } ) ;
85+
86+ expect ( capturedGatewayCall ( ) . timeoutMs ) . toBe ( 5000 ) ;
87+ } ) ;
88+
7189 it ( "uses OPENCLAW_GATEWAY_TOKEN for allowlisted local overrides" , ( ) => {
7290 process . env . OPENCLAW_GATEWAY_TOKEN = "env-token" ;
7391 const opts = resolveGatewayOptions ( { gatewayUrl : "ws://127.0.0.1:18789" } ) ;
0 commit comments