mirror of
https://github.com/n8n-io/n8n.git
synced 2026-09-24 23:22:38 +08:00
fix(OpenAI Node): Remove local shell, update simplify output logic (#20957)
This commit is contained in:
Vendored
+53
-44
@@ -58,7 +58,7 @@ describe('OpenAI Response Operation', () => {
|
||||
],
|
||||
options: {},
|
||||
builtInTools: {},
|
||||
simplify: true,
|
||||
simplify: false,
|
||||
hideTools: 'show',
|
||||
'options.maxToolsIterations': 15,
|
||||
};
|
||||
@@ -107,7 +107,7 @@ describe('OpenAI Response Operation', () => {
|
||||
|
||||
expect(result).toEqual([
|
||||
{
|
||||
json: mockResponse.output,
|
||||
json: mockResponse,
|
||||
pairedItem: { item: 0 },
|
||||
},
|
||||
]);
|
||||
@@ -116,9 +116,9 @@ describe('OpenAI Response Operation', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('should execute with simplified output disabled', async () => {
|
||||
it('should execute with simplified output enabled', async () => {
|
||||
mockExecuteFunctions.getNodeParameter.mockImplementation((param: string) => {
|
||||
if (param === 'simplify') return false;
|
||||
if (param === 'simplify') return true;
|
||||
return 'default';
|
||||
});
|
||||
|
||||
@@ -126,11 +126,26 @@ describe('OpenAI Response Operation', () => {
|
||||
id: 'resp_123',
|
||||
status: 'completed',
|
||||
output: [
|
||||
{
|
||||
type: 'reasoning',
|
||||
role: 'assistant',
|
||||
content: [{ type: 'some_reasoning_output', text: 'Response text' }],
|
||||
},
|
||||
{
|
||||
type: 'tool_call',
|
||||
role: 'assistant',
|
||||
content: [{ type: 'some_tool_call_output', text: 'Response text' }],
|
||||
},
|
||||
{
|
||||
type: 'message',
|
||||
role: 'assistant',
|
||||
content: [{ type: 'output_text', text: 'Response text' }],
|
||||
},
|
||||
{
|
||||
type: 'message',
|
||||
role: 'assistant',
|
||||
content: [{ type: 'output_text', text: 'Response text 2' }],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
@@ -145,43 +160,24 @@ describe('OpenAI Response Operation', () => {
|
||||
|
||||
expect(result).toEqual([
|
||||
{
|
||||
json: mockResponse,
|
||||
json: {
|
||||
output: [
|
||||
{
|
||||
type: 'message',
|
||||
role: 'assistant',
|
||||
content: [{ type: 'output_text', text: 'Response text' }],
|
||||
},
|
||||
{
|
||||
type: 'message',
|
||||
role: 'assistant',
|
||||
content: [{ type: 'output_text', text: 'Response text 2' }],
|
||||
},
|
||||
],
|
||||
},
|
||||
pairedItem: { item: 0 },
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it('should handle multiple output items with simplified output', async () => {
|
||||
const mockResponse = {
|
||||
id: 'resp_123',
|
||||
status: 'completed',
|
||||
output: [
|
||||
{
|
||||
type: 'message',
|
||||
role: 'assistant',
|
||||
content: [{ type: 'output_text', text: 'First response' }],
|
||||
},
|
||||
{
|
||||
type: 'message',
|
||||
role: 'assistant',
|
||||
content: [{ type: 'output_text', text: 'Second response' }],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
mockCreateRequest.mockResolvedValue({
|
||||
model: 'gpt-4o',
|
||||
input: [],
|
||||
});
|
||||
mockApiRequest.mockResolvedValue(mockResponse);
|
||||
mockGetConnectedTools.mockResolvedValue([]);
|
||||
|
||||
const result = await execute.call(mockExecuteFunctions, 0);
|
||||
|
||||
// With simplify=true, should return the entire output array as a single item
|
||||
expect(result).toHaveLength(1);
|
||||
expect(result[0].json).toEqual(mockResponse.output);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Background Mode', () => {
|
||||
@@ -207,6 +203,7 @@ describe('OpenAI Response Operation', () => {
|
||||
mockExecuteFunctions.getNodeParameter.mockImplementation((param: string) => {
|
||||
if (param === 'options.backgroundMode.values.enabled') return true;
|
||||
if (param === 'options.backgroundMode.values.timeout') return 300;
|
||||
if (param === 'simplify') return false;
|
||||
return 'default';
|
||||
});
|
||||
|
||||
@@ -230,7 +227,7 @@ describe('OpenAI Response Operation', () => {
|
||||
);
|
||||
expect(result).toEqual([
|
||||
{
|
||||
json: completedResponse.output,
|
||||
json: completedResponse,
|
||||
pairedItem: { item: 0 },
|
||||
},
|
||||
]);
|
||||
@@ -239,6 +236,7 @@ describe('OpenAI Response Operation', () => {
|
||||
it('should throw error when background mode fails', async () => {
|
||||
mockExecuteFunctions.getNodeParameter.mockImplementation((param: string) => {
|
||||
if (param === 'options.backgroundMode.values.enabled') return true;
|
||||
if (param === 'simplify') return false;
|
||||
return 'default';
|
||||
});
|
||||
|
||||
@@ -317,7 +315,7 @@ describe('OpenAI Response Operation', () => {
|
||||
expect(mockApiRequest).toHaveBeenCalledTimes(2);
|
||||
expect(result).toEqual([
|
||||
{
|
||||
json: finalResponse.output,
|
||||
json: finalResponse,
|
||||
pairedItem: { item: 0 },
|
||||
},
|
||||
]);
|
||||
@@ -526,7 +524,7 @@ describe('OpenAI Response Operation', () => {
|
||||
expect(mockApiRequest).toHaveBeenCalledTimes(2);
|
||||
expect(result).toEqual([
|
||||
{
|
||||
json: finalResponse.output,
|
||||
json: finalResponse,
|
||||
pairedItem: { item: 0 },
|
||||
},
|
||||
]);
|
||||
@@ -561,7 +559,7 @@ describe('OpenAI Response Operation', () => {
|
||||
expect(mockApiRequest).toHaveBeenCalledTimes(1);
|
||||
expect(result).toEqual([
|
||||
{
|
||||
json: responseWithOnlyReasoning.output,
|
||||
json: responseWithOnlyReasoning,
|
||||
pairedItem: { item: 0 },
|
||||
},
|
||||
]);
|
||||
@@ -597,7 +595,12 @@ describe('OpenAI Response Operation', () => {
|
||||
|
||||
const result = await execute.call(mockExecuteFunctions, 0);
|
||||
|
||||
expect((result[0].json as any)[0].content[0].text).toBe('invalid json');
|
||||
expect(result).toEqual([
|
||||
{
|
||||
json: mockResponse,
|
||||
pairedItem: { item: 0 },
|
||||
},
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -605,6 +608,7 @@ describe('OpenAI Response Operation', () => {
|
||||
it('should handle empty messages array', async () => {
|
||||
mockExecuteFunctions.getNodeParameter.mockImplementation((param: string) => {
|
||||
if (param === 'responses.values') return [];
|
||||
if (param === 'simplify') return false;
|
||||
return 'default';
|
||||
});
|
||||
|
||||
@@ -625,7 +629,11 @@ describe('OpenAI Response Operation', () => {
|
||||
|
||||
expect(result).toEqual([
|
||||
{
|
||||
json: [],
|
||||
json: {
|
||||
id: 'resp_123',
|
||||
status: 'completed',
|
||||
output: [],
|
||||
},
|
||||
pairedItem: { item: 0 },
|
||||
},
|
||||
]);
|
||||
@@ -634,6 +642,7 @@ describe('OpenAI Response Operation', () => {
|
||||
it('should handle tools hidden for unsupported models', async () => {
|
||||
mockExecuteFunctions.getNodeParameter.mockImplementation((param: string) => {
|
||||
if (param === 'hideTools') return 'hide';
|
||||
if (param === 'simplify') return false;
|
||||
return 'default';
|
||||
});
|
||||
|
||||
@@ -661,7 +670,7 @@ describe('OpenAI Response Operation', () => {
|
||||
expect(mockGetConnectedTools).not.toHaveBeenCalled();
|
||||
expect(result).toEqual([
|
||||
{
|
||||
json: mockResponse.output,
|
||||
json: mockResponse,
|
||||
pairedItem: { item: 0 },
|
||||
},
|
||||
]);
|
||||
|
||||
-39
@@ -1057,45 +1057,6 @@ describe('OpenAI Responses Helper Functions', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle built-in tools - local shell', async () => {
|
||||
const executeFunctions = createExecuteFunctionsMock({});
|
||||
const options = {
|
||||
model: 'gpt-4',
|
||||
messages: [
|
||||
{
|
||||
role: 'user',
|
||||
type: 'text',
|
||||
content: 'Hello',
|
||||
},
|
||||
],
|
||||
options: {},
|
||||
builtInTools: {
|
||||
localShell: true,
|
||||
},
|
||||
tools: undefined,
|
||||
};
|
||||
|
||||
const result = await createRequest.call(executeFunctions, 0, options);
|
||||
|
||||
expect(result).toEqual({
|
||||
model: 'gpt-4',
|
||||
input: [
|
||||
{
|
||||
role: 'user',
|
||||
content: [{ type: 'input_text', text: 'Hello' }],
|
||||
},
|
||||
],
|
||||
parallel_tool_calls: true,
|
||||
store: true,
|
||||
tools: [
|
||||
{
|
||||
type: 'local_shell',
|
||||
},
|
||||
],
|
||||
background: false,
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle built-in tools - file search', async () => {
|
||||
const executeFunctions = createExecuteFunctionsMock({});
|
||||
const options = {
|
||||
|
||||
-6
@@ -274,12 +274,6 @@ export async function createRequest(
|
||||
});
|
||||
}
|
||||
|
||||
if (builtInTools.localShell) {
|
||||
newTools.push({
|
||||
type: 'local_shell',
|
||||
});
|
||||
}
|
||||
|
||||
if (builtInTools.fileSearch) {
|
||||
const vectorStoreIds = get(builtInTools.fileSearch, 'vectorStoreIds', '[]') as string;
|
||||
const filters = get(builtInTools.fileSearch, 'filters', '{}') as string;
|
||||
|
||||
+4
-8
@@ -242,13 +242,6 @@ const properties: INodeProperties[] = [
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
displayName: 'Local Shell',
|
||||
name: 'localShell',
|
||||
type: 'boolean',
|
||||
default: true,
|
||||
description: 'Whether to allow the model to execute shell commands in a local environment',
|
||||
},
|
||||
{
|
||||
displayName: 'Code Interpreter',
|
||||
name: 'codeInterpreter',
|
||||
@@ -787,8 +780,11 @@ export async function execute(this: IExecuteFunctions, i: number): Promise<INode
|
||||
const returnData: INodeExecutionData[] = [];
|
||||
|
||||
if (simplify) {
|
||||
const messages = response.output.filter((item) => item.type === 'message');
|
||||
returnData.push({
|
||||
json: response.output as unknown as IDataObject,
|
||||
json: {
|
||||
output: messages as unknown as IDataObject,
|
||||
},
|
||||
pairedItem: { item: i },
|
||||
});
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user