V4.9.6 feature (#4565)

* Dashboard submenu (#4545)

* add app submenu (#4452)

* add app submenu

* fix

* width & i18n

* optimize submenu code (#4515)

* optimize submenu code

* fix

* fix

* fix

* fix ts

* perf: dashboard sub menu

* doc

---------

Co-authored-by: heheer <heheer@sealos.io>

* feat: value format test

* doc

* Mcp export (#4555)

* feat: mcp server

* feat: mcp server

* feat: mcp server build

* update doc

* perf: path selector (#4556)

* perf: path selector

* fix: docker file path

* perf: add image endpoint to dataset search (#4557)

* perf: add image endpoint to dataset search

* fix: mcp_server url

* human in loop (#4558)

* Support interactive nodes for loops, and enhance the function of merging nested and loop node history messages. (#4552)

* feat: add LoopInteractive definition

* feat: Support LoopInteractive type and update related logic

* fix: Refactor loop handling logic and improve output value initialization

* feat: Add mergeSignId to dispatchLoop and dispatchRunAppNode responses

* feat: Enhance mergeChatResponseData to recursively merge plugin details and improve response handling

* refactor: Remove redundant comments in mergeChatResponseData for clarity

* perf: loop interactive

* perf: human in loop

---------

Co-authored-by: Theresa <63280168+sd0ric4@users.noreply.github.com>

* mcp server ui

* integrate mcp (#4549)

* integrate mcp

* delete unused code

* fix ts

* bug fix

* fix

* support whole mcp tools

* add try catch

* fix

* fix

* fix ts

* fix test

* fix ts

* fix: interactive in v1 completions

* doc

* fix: router path

* fix mcp integrate (#4563)

* fix mcp integrate

* fix ui

* fix: mcp ux

* feat: mcp call title

* remove repeat loading

* fix mcp tools avatar (#4564)

* fix

* fix avatar

* fix update version

* update doc

* fix: value format

* close server and remove cache

* perf: avatar

---------

Co-authored-by: heheer <heheer@sealos.io>
Co-authored-by: Theresa <63280168+sd0ric4@users.noreply.github.com>
This commit is contained in:
Archer
2025-04-16 22:18:51 +08:00
committed by GitHub
parent ab799e13cd
commit 952412f648
166 changed files with 6318 additions and 1263 deletions

View File

@@ -0,0 +1,313 @@
import { describe, it, expect } from 'vitest';
import { WorkflowIOValueTypeEnum } from '@fastgpt/global/core/workflow/constants';
import { valueTypeFormat } from '@fastgpt/global/core/workflow/runtime/utils';
describe('valueTypeFormat', () => {
// value 为字符串
const strTestList = [
{
value: 'a',
type: WorkflowIOValueTypeEnum.string,
result: 'a'
},
{
value: 'a',
type: WorkflowIOValueTypeEnum.number,
result: Number('a')
},
{
value: 'a',
type: WorkflowIOValueTypeEnum.boolean,
result: false
},
{
value: 'true',
type: WorkflowIOValueTypeEnum.boolean,
result: true
},
{
value: 'false',
type: WorkflowIOValueTypeEnum.boolean,
result: false
},
{
value: 'false',
type: WorkflowIOValueTypeEnum.arrayNumber,
result: ['false']
},
{
value: 'false',
type: WorkflowIOValueTypeEnum.arrayString,
result: ['false']
},
{
value: 'false',
type: WorkflowIOValueTypeEnum.object,
result: {}
},
{
value: 'false',
type: WorkflowIOValueTypeEnum.selectApp,
result: {}
},
{
value: 'false',
type: WorkflowIOValueTypeEnum.selectDataset,
result: []
},
{
value: 'saf',
type: WorkflowIOValueTypeEnum.selectDataset,
result: []
},
{
value: '[]',
type: WorkflowIOValueTypeEnum.selectDataset,
result: []
},
{
value: '{"a":1}',
type: WorkflowIOValueTypeEnum.object,
result: { a: 1 }
},
{
value: '[{"a":1}]',
type: WorkflowIOValueTypeEnum.arrayAny,
result: [{ a: 1 }]
},
{
value: '["111"]',
type: WorkflowIOValueTypeEnum.arrayString,
result: ['111']
}
];
strTestList.forEach((item, index) => {
it(`String test ${index}`, () => {
expect(valueTypeFormat(item.value, item.type)).toEqual(item.result);
});
});
// value 为 number
const numTestList = [
{
value: 1,
type: WorkflowIOValueTypeEnum.string,
result: '1'
},
{
value: 1,
type: WorkflowIOValueTypeEnum.number,
result: 1
},
{
value: 1,
type: WorkflowIOValueTypeEnum.boolean,
result: true
},
{
value: 0,
type: WorkflowIOValueTypeEnum.boolean,
result: false
},
{
value: 0,
type: WorkflowIOValueTypeEnum.any,
result: 0
},
{
value: 0,
type: WorkflowIOValueTypeEnum.arrayAny,
result: [0]
},
{
value: 0,
type: WorkflowIOValueTypeEnum.arrayNumber,
result: [0]
},
{
value: 0,
type: WorkflowIOValueTypeEnum.arrayString,
result: [0]
}
];
numTestList.forEach((item, index) => {
it(`Number test ${index}`, () => {
expect(valueTypeFormat(item.value, item.type)).toEqual(item.result);
});
});
// value 为 boolean
const boolTestList = [
{
value: true,
type: WorkflowIOValueTypeEnum.string,
result: 'true'
},
{
value: true,
type: WorkflowIOValueTypeEnum.number,
result: 1
},
{
value: false,
type: WorkflowIOValueTypeEnum.number,
result: 0
},
{
value: true,
type: WorkflowIOValueTypeEnum.boolean,
result: true
},
{
value: true,
type: WorkflowIOValueTypeEnum.any,
result: true
},
{
value: true,
type: WorkflowIOValueTypeEnum.arrayBoolean,
result: [true]
},
{
value: true,
type: WorkflowIOValueTypeEnum.object,
result: true
}
];
boolTestList.forEach((item, index) => {
it(`Boolean test ${index}`, () => {
expect(valueTypeFormat(item.value, item.type)).toEqual(item.result);
});
});
// value 为 object
const objTestList = [
{
value: { a: 1 },
type: WorkflowIOValueTypeEnum.string,
result: JSON.stringify({ a: 1 })
},
{
value: { a: 1 },
type: WorkflowIOValueTypeEnum.number,
result: Number({ a: 1 })
},
{
value: { a: 1 },
type: WorkflowIOValueTypeEnum.boolean,
result: Boolean({ a: 1 })
},
{
value: { a: 1 },
type: WorkflowIOValueTypeEnum.object,
result: { a: 1 }
},
{
value: { a: 1 },
type: WorkflowIOValueTypeEnum.arrayAny,
result: [{ a: 1 }]
}
];
objTestList.forEach((item, index) => {
it(`Object test ${index}`, () => {
expect(valueTypeFormat(item.value, item.type)).toEqual(item.result);
});
});
// value 为 array
const arrayTestList = [
{
value: [1, 2, 3],
type: WorkflowIOValueTypeEnum.string,
result: JSON.stringify([1, 2, 3])
},
{
value: [1, 2, 3],
type: WorkflowIOValueTypeEnum.number,
result: Number([1, 2, 3])
},
{
value: [1, 2, 3],
type: WorkflowIOValueTypeEnum.boolean,
result: Boolean([1, 2, 3])
},
{
value: [1, 2, 3],
type: WorkflowIOValueTypeEnum.arrayNumber,
result: [1, 2, 3]
},
{
value: [1, 2, 3],
type: WorkflowIOValueTypeEnum.arrayAny,
result: [1, 2, 3]
}
];
arrayTestList.forEach((item, index) => {
it(`Array test ${index}`, () => {
expect(valueTypeFormat(item.value, item.type)).toEqual(item.result);
});
});
// value 为 chatHistory
const chatHistoryTestList = [
{
value: [1, 2, 3],
type: WorkflowIOValueTypeEnum.chatHistory,
result: [1, 2, 3]
},
{
value: 1,
type: WorkflowIOValueTypeEnum.chatHistory,
result: 1
},
{
value: '1',
type: WorkflowIOValueTypeEnum.chatHistory,
result: 0
}
];
chatHistoryTestList.forEach((item, index) => {
it(`ChatHistory test ${index}`, () => {
expect(valueTypeFormat(item.value, item.type)).toEqual(item.result);
});
});
// value 为 null/undefined
// const nullTestList = [
// {
// value: undefined,
// type: WorkflowIOValueTypeEnum.string,
// result: ''
// },
// {
// value: undefined,
// type: WorkflowIOValueTypeEnum.number,
// result: 0
// },
// {
// value: undefined,
// type: WorkflowIOValueTypeEnum.boolean,
// result: false
// },
// {
// value: undefined,
// type: WorkflowIOValueTypeEnum.arrayAny,
// result: []
// },
// {
// value: undefined,
// type: WorkflowIOValueTypeEnum.object,
// result: {}
// },
// {
// value: undefined,
// type: WorkflowIOValueTypeEnum.chatHistory,
// result: []
// }
// ];
// nullTestList.forEach((item, index) => {
// it(`Null test ${index}`, () => {
// expect(valueTypeFormat(item.value, item.type)).toEqual(item.result);
// });
// });
});

View File

@@ -7,6 +7,7 @@ import {
storeNodes2RuntimeNodes
} from '@fastgpt/global/core/workflow/runtime/utils';
import { ChatItemValueTypeEnum } from '@fastgpt/global/core/chat/constants';
vi.mock(import('@fastgpt/service/common/string/tiktoken'), async (importOriginal) => {
const mod = await importOriginal();
return {