async function callTool()

in src/tools/callTool.ts [23:155]


async function callTool(
  agent: OpenApiClientInstance,
  apiKey: string,
  actionTool: ActionTool,
  input?: Record<string, any>,
) {

  let apiRequestConfigs: OpenApi.Params = {} as any;
  let query: any = {};
  let body: any = {};

  // API版本号
  const version = actionTool?.annotations?.version;

  try {

    // 原来使用特定调用的方式
    // import * as DataWorksPublic20240518Classes from '@alicloud/dataworks-public20240518';
    // const FunctionClass = (DataWorksPublic20240518Classes as any)[`${apiKey}Request`];
    // const request = Reflect.construct(FunctionClass, input as any);
    // const runtime = new Util.RuntimeOptions({});
    // // 把apiKey第一个大小改小写
    // const funcName = `${apiKey.charAt(0).toLowerCase()}${apiKey.slice(1) || ''}WithOptions`;
    // return await (agent as any)[funcName](request, runtime);

    // 使用泛化方式调用
    // https://help.aliyun.com/zh/sdk/developer-reference/generalized-call-node-js

    // path 为空就是 RPC
    const style = isEmptyStr(actionTool?.annotations?.path) ? 'RPC' : 'ROA';

    const method = actionTool?.annotations?.method;

    let hasInQueryParams = false;
    let hasInBodyParams = false;
    let hasInByteParams = false;
    let hasInFormDataParams = false;

    // 需要重新 assign 下
    const _input: any = { ...input };

    Object.keys(_input)?.forEach((key) => {
      let value = _input[key];

      // if (isNumber(value)) {
      //   // 查看值有没有溢出,如果溢出了就用string
      //   if (value > Number.MAX_SAFE_INTEGER || value < Number.MIN_SAFE_INTEGER) {
      //     value = String(value);
      //   }
      // }

      const paramMeta = actionTool?.annotations?.pmd?.[key];
      if (paramMeta?.in === 'body') {
        hasInBodyParams = true;
        body[key] = value;
      } else if (paramMeta?.in === 'formData') {
        hasInFormDataParams = true;
        if (paramMeta?.style === 'json') {
          body[key] = toJSONString(value);
        } else {
          body[key] = value;
        }
      } else if (paramMeta?.in === 'byte') {
        hasInByteParams = true;
        body[key] = value;
      } else if (paramMeta?.in === 'query') {
        hasInQueryParams = true;
        if (paramMeta?.style === 'json') {
          query[key] = toJSONString(value);
        } else {
          query[key] = value;
        }
      } else {
        query[key] = value;
      }
    });

    const reqBodyType = hasInByteParams ? 'byte' : hasInFormDataParams ? 'formData' : 'json';

    const bodyJson = toJSONString(body);
    if (reqBodyType === 'byte') {
      body = Buffer.from(bodyJson);
    } else if (reqBodyType === 'json') {
      body = bodyJson;
    }

    const configs: OpenApiConfigs = {
      style, // API风格
      action: apiKey, // API 名称
      version,
      protocol: 'HTTPS', // API协议
      method, // 请求方法
      authType: 'AK',
      pathname: `/`, // 接口 PATH
      reqBodyType, // 接口请求体内容格式
      bodyType: 'string', // 使用 string,如果使用 json 在 sdk 里会有精度丢失的问题
    };

    if (['GET', 'DELETE'].includes(method || '')) delete configs.reqBodyType;

    apiRequestConfigs = new OpenApi.Params(configs);

    // GET DELETE 这边需要把 body 设定为空,不然签名不会过
    if (['GET', 'DELETE'].includes(method || '')) body = null;

    const request = new OpenApi.OpenApiRequest({ query, body });
    // runtime default settings https://github.com/aliyun/tea-util/blob/5f4bdebef3b57d33207b6bc44af6ed5e1a009959/ts/test/client.spec.ts#L133
    const runtime = new Util.RuntimeOptions({
      readTimeout: process.env.OPEN_API_READ_TIMEOUT ? Number(process.env.OPEN_API_READ_TIMEOUT) : 10000,
      connectTimeout: process.env.OPEN_API_CONNECT_TIMEOUT ? Number(process.env.OPEN_API_CONNECT_TIMEOUT) : 10000,
    });
    // 查看 https://github.com/aliyun/darabonba-openapi/blob/master/ts/src/client.ts
    const res = await (agent as any)?.callApi?.(apiRequestConfigs, request, runtime);
    let result: IAlibabaCloudOpenApiJsonResponse['body'] | null = null;
    try {
      // 当执行成功,只取 message.body 的信息
      const obj = res?.statusCode === 200 && res?.body ? res?.body : res;
      result = parseJSONString(obj);
      await record({ success: true, toolName: apiKey, requestId: result?.RequestId, version });
    } catch (e) {
      console.error(e);
    }

    return result;

  } catch (error: any) {
    const verbose = isVerboseMode();
    const errorMsg = `Call tool failed: ${error.message}, api key: ${apiKey}, api request configs: ${toJSONString(apiRequestConfigs)}, query: ${toJSONString(query)}, body: ${toJSONString(body)}${verbose ? `, env info: ${getEnvInfo()}` : ''}`;
    const recordErr = `Call tool failed: ${error.message}, api key: ${apiKey}, api request configs: ${toJSONString(apiRequestConfigs)}, query: ${toJSONString(query)}, body: ${toJSONString(body)}`;
    await record({ success: false, toolName: apiKey, version, error: recordErr });
    throw new Error(errorMsg);
  }
};