Skip to content

Commit 4502771

Browse files
committed
fix http toolset
1 parent 0ab5c29 commit 4502771

File tree

11 files changed

+346
-179
lines changed

11 files changed

+346
-179
lines changed

packages/global/core/app/jsonschema.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import SwaggerParser from '@apidevtools/swagger-parser';
55
import yaml from 'js-yaml';
66
import type { OpenAPIV3 } from 'openapi-types';
77
import type { OpenApiJsonSchema } from './httpTools/type';
8+
import { i18nT } from '../../../web/i18n/utils';
89

910
type SchemaInputValueType = 'string' | 'number' | 'integer' | 'boolean' | 'array' | 'object';
1011
export type JsonSchemaPropertiesItemType = {
@@ -180,7 +181,7 @@ export const str2OpenApiSchema = async (yamlStr = ''): Promise<OpenApiJsonSchema
180181
.filter(Boolean) as OpenApiJsonSchema['pathData'];
181182
return { pathData, serverPath };
182183
} catch (err) {
183-
throw new Error('Invalid Schema');
184+
return Promise.reject(i18nT('common:plugin.Invalid Schema'));
184185
}
185186
};
186187
export const getSchemaValueType = (schema: { type: string; items?: { type: string } }) => {

packages/service/core/app/http.ts

Lines changed: 28 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { getErrText } from '@fastgpt/global/common/error/utils';
55
import type { RequireOnlyOne } from '@fastgpt/global/common/type/utils';
66
import type { HttpToolConfigType } from '@fastgpt/global/core/app/type';
77
import { contentTypeMap, ContentTypes } from '@fastgpt/global/core/workflow/constants';
8+
import { replaceEditorVariable } from '@fastgpt/global/core/workflow/runtime/utils';
89

910
export type RunHTTPToolParams = {
1011
baseUrl: string;
@@ -32,40 +33,49 @@ const buildHttpRequest = ({
3233
staticHeaders,
3334
staticBody
3435
}: Omit<RunHTTPToolParams, 'baseUrl' | 'toolPath'>) => {
36+
const replaceVariables = (text: string) => {
37+
return replaceEditorVariable({
38+
text,
39+
nodes: [],
40+
variables: params
41+
});
42+
};
43+
3544
const body = (() => {
3645
if (!staticBody || staticBody.type === ContentTypes.none) {
37-
return ['POST', 'PUT', 'PATCH'].includes(method.toUpperCase()) ? params : undefined;
46+
return ['POST', 'PUT', 'PATCH'].includes(method.toUpperCase()) ? {} : undefined;
3847
}
3948

4049
if (staticBody.type === ContentTypes.json) {
41-
const staticContent = staticBody.content ? JSON.parse(staticBody.content) : {};
42-
return { ...staticContent, ...params };
50+
const contentWithReplacedVars = staticBody.content
51+
? replaceVariables(staticBody.content)
52+
: '{}';
53+
const staticContent = JSON.parse(contentWithReplacedVars);
54+
return { ...staticContent };
4355
}
4456

4557
if (staticBody.type === ContentTypes.formData) {
4658
const formData = new (require('form-data'))();
4759
staticBody.formData?.forEach(({ key, value }) => {
48-
formData.append(key, value);
49-
});
50-
Object.entries(params).forEach(([key, value]) => {
51-
formData.append(key, value);
60+
const replacedKey = replaceVariables(key);
61+
const replacedValue = replaceVariables(value);
62+
formData.append(replacedKey, replacedValue);
5263
});
5364
return formData;
5465
}
5566

5667
if (staticBody.type === ContentTypes.xWwwFormUrlencoded) {
5768
const urlencoded = new URLSearchParams();
5869
staticBody.formData?.forEach(({ key, value }) => {
59-
urlencoded.append(key, value);
60-
});
61-
Object.entries(params).forEach(([key, value]) => {
62-
urlencoded.append(key, String(value));
70+
const replacedKey = replaceVariables(key);
71+
const replacedValue = replaceVariables(value);
72+
urlencoded.append(replacedKey, replacedValue);
6373
});
6474
return urlencoded.toString();
6575
}
6676

6777
if (staticBody.type === ContentTypes.xml || staticBody.type === ContentTypes.raw) {
68-
return staticBody.content || '';
78+
return replaceVariables(staticBody.content || '');
6979
}
7080

7181
return undefined;
@@ -78,7 +88,9 @@ const buildHttpRequest = ({
7888
...(headerSecret ? getSecretValue({ storeSecret: headerSecret }) : {}),
7989
...(staticHeaders?.reduce(
8090
(acc, { key, value }) => {
81-
acc[key] = value;
91+
const replacedKey = replaceVariables(key);
92+
const replacedValue = replaceVariables(value);
93+
acc[replacedKey] = replacedValue;
8294
return acc;
8395
},
8496
{} as Record<string, string>
@@ -89,7 +101,9 @@ const buildHttpRequest = ({
89101
const staticParamsObj =
90102
staticParams?.reduce(
91103
(acc, { key, value }) => {
92-
acc[key] = value;
104+
const replacedKey = replaceVariables(key);
105+
const replacedValue = replaceVariables(value);
106+
acc[replacedKey] = replacedValue;
93107
return acc;
94108
},
95109
{} as Record<string, any>

packages/web/i18n/en/app.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"Add_tool": "Add tool",
33
"AutoOptimize": "Automatic optimization",
44
"Click_to_delete_this_field": "Click to delete this field",
5-
"Custom_params": "Custom parameters",
5+
"Custom_params": "input parameters",
66
"Edit_tool": "Edit tool",
77
"Filed_is_deprecated": "This field is deprecated",
88
"HTTPTools_Create_Type": "Create Type",
@@ -111,6 +111,7 @@
111111
"import_configs_failed": "Import configuration failed, please ensure the configuration is correct!",
112112
"import_configs_success": "Import Successful",
113113
"initial_form": "initial state",
114+
"input_params_tips": "Tool input parameters will not be passed directly to the request URL; they can be referenced on the right side using \"/\".",
114115
"interval.12_hours": "Every 12 Hours",
115116
"interval.2_hours": "Every 2 Hours",
116117
"interval.3_hours": "Every 3 Hours",

packages/web/i18n/zh-CN/app.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"Add_tool": "添加工具",
33
"AutoOptimize": "自动优化",
44
"Click_to_delete_this_field": "点击删除该字段",
5-
"Custom_params": "自定义参数",
5+
"Custom_params": "输入参数",
66
"Edit_tool": "编辑工具",
77
"Filed_is_deprecated": "该字段已弃用",
88
"HTTPTools_Create_Type": "创建方式",
@@ -114,6 +114,7 @@
114114
"import_configs_failed": "导入配置失败,请确保配置正常!",
115115
"import_configs_success": "导入成功",
116116
"initial_form": "初始状态",
117+
"input_params_tips": "工具的输入参数,不会直接传递到请求地址,可在右侧通过 \"/\" 来引用变量",
117118
"interval.12_hours": "每12小时",
118119
"interval.2_hours": "每2小时",
119120
"interval.3_hours": "每3小时",

packages/web/i18n/zh-Hant/app.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"Add_tool": "添加工具",
33
"AutoOptimize": "自動優化",
44
"Click_to_delete_this_field": "點擊刪除該字段",
5-
"Custom_params": "自定義參數",
5+
"Custom_params": "輸入參數",
66
"Filed_is_deprecated": "該字段已棄用",
77
"HTTPTools_Create_Type": "創建方式",
88
"HTTPTools_Create_Type_Tip": "選擇後不支持修改",
@@ -111,6 +111,7 @@
111111
"import_configs_failed": "匯入設定失敗,請確認設定是否正常!",
112112
"import_configs_success": "匯入成功",
113113
"initial_form": "初始狀態",
114+
"input_params_tips": "工具的輸入參數,不會直接傳遞到請求地址,可在右側通過 \"/\" 來引用變數",
114115
"interval.12_hours": "每 12 小時",
115116
"interval.2_hours": "每 2 小時",
116117
"interval.3_hours": "每 3 小時",

projects/app/src/pageComponents/app/detail/HTTPTools/ChatTest.tsx

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -52,18 +52,22 @@ const ChatTest = ({
5252
const { runAsync: runTool, loading: isRunning } = useRequest2(
5353
async (data: Record<string, any>) => {
5454
if (!currentTool) return;
55-
56-
return await postRunHTTPTool({
57-
baseUrl,
58-
params: data,
59-
headerSecret: currentTool.headerSecret || headerSecret,
60-
toolPath: currentTool.path,
61-
method: currentTool.method,
62-
customHeaders: customHeaders,
63-
staticParams: currentTool.staticParams,
64-
staticHeaders: currentTool.staticHeaders,
65-
staticBody: currentTool.staticBody
66-
});
55+
try {
56+
const result = await postRunHTTPTool({
57+
baseUrl,
58+
params: data,
59+
headerSecret: currentTool.headerSecret || headerSecret,
60+
toolPath: currentTool.path,
61+
method: currentTool.method,
62+
customHeaders: customHeaders,
63+
staticParams: currentTool.staticParams,
64+
staticHeaders: currentTool.staticHeaders,
65+
staticBody: currentTool.staticBody
66+
});
67+
return result;
68+
} catch (error) {
69+
return Promise.reject(error);
70+
}
6771
},
6872
{
6973
onSuccess: (res) => {
@@ -74,7 +78,8 @@ const ChatTest = ({
7478
} catch (error) {
7579
console.error(error);
7680
}
77-
}
81+
},
82+
errorToast: 'test'
7883
}
7984
);
8085

@@ -100,6 +105,7 @@ const ChatTest = ({
100105

101106
<Box px={[2, 5]} mb={6}>
102107
<LightRowTabs
108+
gap={4}
103109
list={tabList}
104110
value={activeTab}
105111
onChange={(value) => {

projects/app/src/pageComponents/app/detail/HTTPTools/CurlImportModal.tsx

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { parseCurl } from '@fastgpt/global/common/string/http';
77
import { useToast } from '@fastgpt/web/hooks/useToast';
88
import { type HttpMethod, ContentTypes } from '@fastgpt/global/core/workflow/constants';
99
import type { ParamItemType } from './ManualToolModal';
10+
import type { StoreSecretValueType } from '@fastgpt/global/common/secret/type';
1011

1112
export type CurlImportResult = {
1213
method: HttpMethod;
@@ -16,6 +17,7 @@ export type CurlImportResult = {
1617
bodyType: string;
1718
bodyContent?: string;
1819
bodyFormData?: ParamItemType[];
20+
headerSecret?: StoreSecretValueType;
1921
};
2022

2123
type CurlImportModalProps = {
@@ -46,6 +48,37 @@ const CurlImportModal = ({ onClose, onImport }: CurlImportModalProps) => {
4648
}));
4749
};
4850

51+
const { headerSecret, filteredHeaders } = (() => {
52+
let headerSecret: StoreSecretValueType | undefined;
53+
const filteredHeaders = parsed.headers.filter((header) => {
54+
if (header.key.toLowerCase() === 'authorization') {
55+
const authValue = header.value || '';
56+
if (authValue.startsWith('Bearer ')) {
57+
const token = authValue.substring(7).trim();
58+
headerSecret = {
59+
Bearer: {
60+
value: token,
61+
secret: ''
62+
}
63+
};
64+
return false;
65+
}
66+
if (authValue.startsWith('Basic ')) {
67+
const credentials = authValue.substring(6).trim();
68+
headerSecret = {
69+
Basic: {
70+
value: credentials,
71+
secret: ''
72+
}
73+
};
74+
return false;
75+
}
76+
}
77+
return true;
78+
});
79+
return { headerSecret, filteredHeaders };
80+
})();
81+
4982
const bodyType = (() => {
5083
if (!parsed.body || parsed.body === '{}') {
5184
return ContentTypes.none;
@@ -57,9 +90,10 @@ const CurlImportModal = ({ onClose, onImport }: CurlImportModalProps) => {
5790
method: parsed.method as HttpMethod,
5891
path: parsed.url,
5992
params: parsed.params.length > 0 ? convertToParamItemType(parsed.params) : undefined,
60-
headers: parsed.headers.length > 0 ? convertToParamItemType(parsed.headers) : undefined,
93+
headers: filteredHeaders.length > 0 ? convertToParamItemType(filteredHeaders) : undefined,
6194
bodyType,
62-
bodyContent: bodyType === ContentTypes.json ? parsed.body : undefined
95+
bodyContent: bodyType === ContentTypes.json ? parsed.body : undefined,
96+
...(headerSecret && { headerSecret })
6397
};
6498

6599
onImport(result);

projects/app/src/pageComponents/app/detail/HTTPTools/Edit.tsx

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { Box, Flex } from '@chakra-ui/react';
22
import { useSystem } from '@fastgpt/web/hooks/useSystem';
3-
import React, { useMemo, useState } from 'react';
3+
import React, { useEffect, useMemo, useState } from 'react';
44
import styles from '../SimpleApp/styles.module.scss';
55
import { cardStyles } from '../constants';
66
import AppCard from './AppCard';
@@ -37,6 +37,20 @@ const Edit = () => {
3737
}
3838
}, [appDetail.pluginData?.customHeaders]);
3939

40+
useEffect(() => {
41+
if (!currentTool || toolList.length === 0) {
42+
setCurrentTool(toolList[0]);
43+
return;
44+
}
45+
46+
const updatedTool = toolList.find((tool) => tool.name === currentTool.name);
47+
if (updatedTool) {
48+
setCurrentTool(updatedTool);
49+
} else {
50+
setCurrentTool(toolList[0]);
51+
}
52+
}, [toolSetData]);
53+
4054
return (
4155
<MyBox
4256
display={['block', 'flex']}

projects/app/src/pageComponents/app/detail/HTTPTools/EditForm.tsx

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -51,12 +51,6 @@ const EditForm = ({
5151
onClose: onCloseConfigModal
5252
} = useDisclosure();
5353

54-
const {
55-
onOpen: onOpenAddToolModal,
56-
isOpen: isOpenAddToolModal,
57-
onClose: onCloseAddToolModal
58-
} = useDisclosure();
59-
6054
const { runAsync: runDeleteHttpTool, loading: isDeletingTool } = useRequest2(
6155
async (updatedToolList: HttpToolConfigType[]) =>
6256
await putUpdateHttpPlugin({
@@ -100,7 +94,16 @@ const EditForm = ({
10094
<Button
10195
px={'2'}
10296
leftIcon={<MyIcon name={'common/addLight'} w={'18px'} />}
103-
onClick={onOpenAddToolModal}
97+
onClick={() =>
98+
setEditingManualTool({
99+
name: '',
100+
description: '',
101+
inputSchema: { type: 'object' },
102+
outputSchema: { type: 'object' },
103+
path: '',
104+
method: 'POST'
105+
})
106+
}
104107
>
105108
{t('common:Add')}
106109
</Button>
@@ -247,7 +250,6 @@ const EditForm = ({
247250
</Box>
248251

249252
{isOpenConfigModal && <SchemaConfigModal onClose={onCloseConfigModal} />}
250-
{isOpenAddToolModal && <ManualToolModal onClose={onCloseAddToolModal} />}
251253
{toolDetail && (
252254
<ToolDetailModal
253255
tool={toolDetail}

0 commit comments

Comments
 (0)