fix(OpenAI Node): Remove local shell, update simplify output logic (#20957)

This commit is contained in:
yehorkardash
2025-10-20 12:40:48 +03:00
committed by GitHub
parent 30ce501fa0
commit f282b0272e
4 changed files with 57 additions and 97 deletions
@@ -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 },
},
]);
@@ -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 = {
@@ -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;
@@ -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 {