perf: optimize workflow tool responses for token efficiency (v2.29.0) (#479)

* perf: optimize workflow tool responses for token efficiency (v2.29.0)

Reduce response sizes by 75-90% for 4 workflow management tools:

- n8n_update_partial_workflow: Returns {id, name, active, operationsApplied}
- n8n_create_workflow: Returns {id, name, active, nodeCount}
- n8n_update_full_workflow: Returns {id, name, active, nodeCount}
- n8n_delete_workflow: Returns {id, name, deleted: true}

AI agents can use n8n_get_workflow with mode 'structure' if they need
to verify the current workflow state after operations.

Conceived by Romuald Członkowski - https://www.aiadvisors.pl/en

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* fix: update tests and add nodeCount to partial update response

- Fix handleCreateWorkflow test to expect minimal response
- Fix handleDeleteWorkflow test to expect minimal response
- Add nodeCount to n8n_update_partial_workflow response for consistency
- Update documentation and CHANGELOG

Conceived by Romuald Członkowski - https://www.aiadvisors.pl/en

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* fix: update handlers-workflow-diff tests for minimal response

Update 3 more tests that expected full workflow in response:
- should apply diff operations successfully
- should activate workflow after successful update
- should deactivate workflow after successful update

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* fix: update integration tests to use minimal response format

Integration tests now verify minimal response format and use
client.getWorkflow() to fetch actual workflow state for verification.

Conceived by Romuald Czlonkowski - www.aiadvisors.pl/en

* fix: update create/update workflow integration tests for minimal response

Integration tests now verify minimal response and use client.getWorkflow()
to fetch actual workflow state for detailed verification.

Conceived by Romuald Czlonkowski - www.aiadvisors.pl/en

* fix: add type assertions to fix TypeScript errors in tests

Conceived by Romuald Czlonkowski - www.aiadvisors.pl/en

---------

Co-authored-by: Romuald Członkowski <romualdczlonkowski@MacBook-Pro-Romuald.local>
Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
Romuald Członkowski
2025-12-09 16:36:17 +01:00
committed by GitHub
parent 130dd44ea5
commit b92e511463
27 changed files with 301 additions and 107 deletions

View File

@@ -99,7 +99,13 @@ describe('Integration: handleUpdatePartialWorkflow', () => {
);
expect(response.success).toBe(true);
const updated = response.data as any;
// Response now returns minimal data - verify with a follow-up get
const responseData = response.data as any;
expect(responseData.id).toBe(created.id);
expect(responseData.nodeCount).toBe(2);
// Fetch actual workflow to verify changes
const updated = await client.getWorkflow(created.id);
expect(updated.nodes).toHaveLength(2);
expect(updated.nodes.find((n: any) => n.name === 'Set')).toBeDefined();
});
@@ -171,7 +177,13 @@ describe('Integration: handleUpdatePartialWorkflow', () => {
);
expect(response.success).toBe(true);
const updated = response.data as any;
// Response now returns minimal data - verify with a follow-up get
const responseData = response.data as any;
expect(responseData.id).toBe(created.id);
expect(responseData.nodeCount).toBe(1);
// Fetch actual workflow to verify changes
const updated = await client.getWorkflow(created.id);
expect(updated.nodes).toHaveLength(1);
expect(updated.nodes.find((n: any) => n.name === 'HTTP Request')).toBeUndefined();
});
@@ -238,9 +250,14 @@ describe('Integration: handleUpdatePartialWorkflow', () => {
);
expect(response.success).toBe(true);
const updated = response.data as any;
// Response now returns minimal data - verify with a follow-up get
expect((response.data as any).id).toBe(created.id);
// Fetch actual workflow to verify changes
const updated = await client.getWorkflow(created.id);
const webhookNode = updated.nodes.find((n: any) => n.name === 'Webhook');
expect(webhookNode.parameters.path).toBe('updated-path');
expect(webhookNode).toBeDefined();
expect(webhookNode!.parameters.path).toBe('updated-path');
});
it('should update nested parameters', async () => {
@@ -274,10 +291,15 @@ describe('Integration: handleUpdatePartialWorkflow', () => {
);
expect(response.success).toBe(true);
const updated = response.data as any;
// Response now returns minimal data - verify with a follow-up get
expect((response.data as any).id).toBe(created.id);
// Fetch actual workflow to verify changes
const updated = await client.getWorkflow(created.id);
const webhookNode = updated.nodes.find((n: any) => n.name === 'Webhook');
expect(webhookNode.parameters.httpMethod).toBe('POST');
expect(webhookNode.parameters.path).toBe('new-path');
expect(webhookNode).toBeDefined();
expect(webhookNode!.parameters.httpMethod).toBe('POST');
expect(webhookNode!.parameters.path).toBe('new-path');
});
});
@@ -312,9 +334,14 @@ describe('Integration: handleUpdatePartialWorkflow', () => {
);
expect(response.success).toBe(true);
const updated = response.data as any;
// Response now returns minimal data - verify with a follow-up get
expect((response.data as any).id).toBe(created.id);
// Fetch actual workflow to verify changes
const updated = await client.getWorkflow(created.id);
const webhookNode = updated.nodes.find((n: any) => n.name === 'Webhook');
expect(webhookNode.position).toEqual(newPosition);
expect(webhookNode).toBeDefined();
expect(webhookNode!.position).toEqual(newPosition);
});
});
@@ -346,9 +373,14 @@ describe('Integration: handleUpdatePartialWorkflow', () => {
);
expect(response.success).toBe(true);
const updated = response.data as any;
// Response now returns minimal data - verify with a follow-up get
expect((response.data as any).id).toBe(created.id);
// Fetch actual workflow to verify changes
const updated = await client.getWorkflow(created.id);
const webhookNode = updated.nodes.find((n: any) => n.name === 'Webhook');
expect(webhookNode.disabled).toBe(true);
expect(webhookNode).toBeDefined();
expect(webhookNode!.disabled).toBe(true);
});
it('should enable a disabled node', async () => {
@@ -389,10 +421,15 @@ describe('Integration: handleUpdatePartialWorkflow', () => {
);
expect(response.success).toBe(true);
const updated = response.data as any;
// Response now returns minimal data - verify with a follow-up get
expect((response.data as any).id).toBe(created.id);
// Fetch actual workflow to verify changes
const updated = await client.getWorkflow(created.id);
const webhookNode = updated.nodes.find((n: any) => n.name === 'Webhook');
expect(webhookNode).toBeDefined();
// After enabling, disabled should be false or undefined (both mean enabled)
expect(webhookNode.disabled).toBeFalsy();
expect(webhookNode!.disabled).toBeFalsy();
});
});
});
@@ -434,7 +471,11 @@ describe('Integration: handleUpdatePartialWorkflow', () => {
);
expect(response.success).toBe(true);
const updated = response.data as any;
// Response now returns minimal data - verify with a follow-up get
expect((response.data as any).id).toBe(created.id);
// Fetch actual workflow to verify changes
const updated = await client.getWorkflow(created.id);
expect(updated.connections).toBeDefined();
expect(updated.connections.Webhook).toBeDefined();
});
@@ -658,8 +699,11 @@ describe('Integration: handleUpdatePartialWorkflow', () => {
);
expect(response.success).toBe(true);
const updated = response.data as any;
// Response now returns minimal data - verify with a follow-up get
expect((response.data as any).id).toBe(created.id);
// Fetch actual workflow to verify changes
const updated = await client.getWorkflow(created.id);
// Note: n8n API may not return all settings in response
// The operation should succeed even if settings aren't reflected in the response
expect(updated.settings).toBeDefined();
@@ -822,7 +866,13 @@ describe('Integration: handleUpdatePartialWorkflow', () => {
);
expect(response.success).toBe(true);
const updated = response.data as any;
// Response now returns minimal data - verify with a follow-up get
const responseData = response.data as any;
expect(responseData.id).toBe(created.id);
expect(responseData.nodeCount).toBe(2);
// Fetch actual workflow to verify changes
const updated = await client.getWorkflow(created.id);
expect(updated.nodes).toHaveLength(2);
expect(updated.connections.Webhook).toBeDefined();
});
@@ -1040,7 +1090,13 @@ describe('Integration: handleUpdatePartialWorkflow', () => {
// Should succeed
expect(response.success).toBe(true);
const updated = response.data as any;
// Response now returns minimal data - verify with a follow-up get
const responseData = response.data as any;
expect(responseData.id).toBe(created.id);
expect(responseData.nodeCount).toBe(5); // Original 4 + 1 new
// Fetch actual workflow to verify changes
const updated = await client.getWorkflow(created.id);
expect(updated.nodes).toHaveLength(5); // Original 4 + 1 new
expect(updated.nodes.find((n: any) => n.name === 'Process Data')).toBeDefined();
});