mirror of
https://github.com/n8n-io/n8n.git
synced 2026-10-12 02:19:43 +00:00
fix(core): Hide get-json from Instance AI (#36146)
This commit is contained in:
@@ -213,12 +213,12 @@ describe('workflows tool', () => {
|
||||
expect(context.workflowService.publish).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should allow code inspection but reject raw update on orchestrator surface', () => {
|
||||
it('should allow code inspection but reject raw workflow actions on orchestrator surface', () => {
|
||||
const context = createMockContext();
|
||||
const tool = createWorkflowsTool(context, 'orchestrator');
|
||||
const schema = getInputSchema(tool);
|
||||
|
||||
expect(schema.safeParse({ action: 'get-json', workflowId: 'w1' }).success).toBe(true);
|
||||
expect(schema.safeParse({ action: 'get-json', workflowId: 'w1' }).success).toBe(false);
|
||||
expect(schema.safeParse({ action: 'get-as-code', workflowId: 'w1' }).success).toBe(true);
|
||||
expect(
|
||||
schema.safeParse({
|
||||
@@ -227,6 +227,8 @@ describe('workflows tool', () => {
|
||||
workflow: { name: 'WF', nodes: [], connections: {} },
|
||||
}).success,
|
||||
).toBe(false);
|
||||
expect(getDescription(tool)).toContain('TypeScript SDK code');
|
||||
expect(getDescription(tool)).not.toContain('WorkflowJSON');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -645,6 +647,8 @@ describe('workflows tool', () => {
|
||||
structure: '// generated code',
|
||||
note: STRUCTURE_ONLY_NOTE,
|
||||
});
|
||||
expect(STRUCTURE_ONLY_NOTE).toContain('get-as-code');
|
||||
expect(STRUCTURE_ONLY_NOTE).not.toContain('get-json');
|
||||
const codegenInput = vi.mocked(generateWorkflowCode).mock.calls[0][0];
|
||||
expect(codegenInput).toMatchObject({ name: 'Test WF' });
|
||||
expect(JSON.stringify(codegenInput)).not.toContain('conditions');
|
||||
|
||||
@@ -127,7 +127,7 @@ export function createAllTools(context: InstanceAiContext): InstanceAiToolRegist
|
||||
/**
|
||||
* Creates orchestrator domain tools. Skills run in the orchestrator now, so
|
||||
* domain tools keep their workflow-building surface while hiding raw full
|
||||
* WorkflowJSON update actions.
|
||||
* WorkflowJSON read and update actions.
|
||||
*/
|
||||
export function createOrchestratorDomainTools(context: InstanceAiContext): InstanceAiToolRegistry {
|
||||
const tools: Array<[string, BuiltTool]> = [
|
||||
|
||||
+17
@@ -20,6 +20,9 @@ function makeContext(
|
||||
domainContext.workflowService.get = vi
|
||||
.fn()
|
||||
.mockResolvedValue({ id: 'w1', name: 'Test', nodes: [], connections: {}, active: false });
|
||||
domainContext.workflowService.getAsWorkflowJSON = vi
|
||||
.fn()
|
||||
.mockResolvedValue({ name: 'Eval setup', nodes: [], connections: {} });
|
||||
domainContext.workflowService.updateFromWorkflowJSON = vi
|
||||
.fn()
|
||||
.mockResolvedValue({ id: 'w1', name: 'Test', versionId: 'v1', nodes: [], connections: {} });
|
||||
@@ -79,6 +82,7 @@ describe('buildEvalSetupTools', () => {
|
||||
|
||||
expect(schema.safeParse({ action: 'get-json', workflowId: 'w1' }).success).toBe(true);
|
||||
expect(schema.safeParse({ action: 'get', workflowId: 'w1' }).success).toBe(false);
|
||||
expect(schema.safeParse({ action: 'get-as-code', workflowId: 'w1' }).success).toBe(false);
|
||||
expect(
|
||||
schema.safeParse({
|
||||
action: 'update',
|
||||
@@ -96,6 +100,19 @@ describe('buildEvalSetupTools', () => {
|
||||
).toBe(false);
|
||||
});
|
||||
|
||||
it('reads raw workflow JSON through the eval setup workflow tool', async () => {
|
||||
const ctx = makeContext('require_approval');
|
||||
const workflows = buildEvalSetupTools(ctx).get('workflows');
|
||||
|
||||
const result = await workflows?.handler!({ action: 'get-json', workflowId: 'w1' }, {} as never);
|
||||
|
||||
expect(ctx.domainContext!.workflowService.getAsWorkflowJSON).toHaveBeenCalledWith(
|
||||
'w1',
|
||||
undefined,
|
||||
);
|
||||
expect(result).toEqual({ name: 'Eval setup', nodes: [], connections: {} });
|
||||
});
|
||||
|
||||
it('leaves the original workflows tool in place when admin has blocked updates', () => {
|
||||
const ctx = makeContext('blocked');
|
||||
const tools = buildEvalSetupTools(ctx);
|
||||
|
||||
@@ -383,7 +383,7 @@ function getSupportedWorkflowActionSchemas(
|
||||
return {
|
||||
list: listAction,
|
||||
get: getAction,
|
||||
'get-json': getJsonAction,
|
||||
...(surface !== 'orchestrator' ? { 'get-json': getJsonAction } : {}),
|
||||
'get-as-code': getAsCodeAction,
|
||||
delete: deleteAction,
|
||||
unarchive: unarchiveAction,
|
||||
|
||||
@@ -218,6 +218,14 @@ describe('createBuildWorkflowTool', () => {
|
||||
expect(tool.description).toContain('workflow-builder');
|
||||
expect(tool.description).toContain('data-table-manager');
|
||||
expect(tool.description).toContain('load_skill');
|
||||
expect(tool.description).toContain(
|
||||
'Use TypeScript SDK .workflow.ts source for new and existing workflows.',
|
||||
);
|
||||
expect(tool.description).not.toContain('WorkflowJSON .json source for existing workflow edits');
|
||||
expect(buildWorkflowInputSchema.shape.filePath.description).toContain(
|
||||
'Workspace-relative path to the TypeScript SDK workflow source file',
|
||||
);
|
||||
expect(buildWorkflowInputSchema.shape.filePath.description).not.toContain('WorkflowJSON');
|
||||
});
|
||||
|
||||
it('builds a new workflow from a workspace source file', async () => {
|
||||
|
||||
@@ -141,7 +141,7 @@ export const buildWorkflowInputSchema = z
|
||||
'Pass a workspace-relative path like src/workflows/my-workflow.workflow.ts.',
|
||||
})
|
||||
.describe(
|
||||
'Workspace-relative path to the workflow source file to build, e.g. src/workflows/my-workflow.workflow.ts. Supports TypeScript SDK files and WorkflowJSON .json files.',
|
||||
'Workspace-relative path to the TypeScript SDK workflow source file to build, e.g. src/workflows/my-workflow.workflow.ts.',
|
||||
),
|
||||
sourceCode: z
|
||||
.string()
|
||||
@@ -351,7 +351,7 @@ export function createBuildWorkflowTool(context: InstanceAiContext) {
|
||||
'Build and save a workflow from workflow source. ' +
|
||||
'Load `workflow-builder` via `load_skill` before calling this tool. ' +
|
||||
'When the workflow creates or writes Data Tables, also load `data-table-manager` first. ' +
|
||||
'Use TypeScript SDK source for new workflows, or WorkflowJSON .json source for existing workflow edits. ' +
|
||||
'Use TypeScript SDK .workflow.ts source for new and existing workflows. ' +
|
||||
'Prefer writing the file with `workspace_write_file` / `workspace_str_replace_file` so `workflow-sdk validate` can run on it, then call this tool with filePath. ' +
|
||||
'For a one-shot create/rewrite you may pass `sourceCode` instead (the tool writes filePath and builds).',
|
||||
)
|
||||
|
||||
@@ -5,7 +5,7 @@ import { NodeConnectionTypes } from 'n8n-workflow';
|
||||
import type { WorkflowNode } from '../../types';
|
||||
|
||||
export const STRUCTURE_ONLY_NOTE =
|
||||
'Node parameters omitted to keep context small. Pass full: true to include them in one call, or use get-json / get-as-code (optionally with versionId) for parameter-level detail.';
|
||||
'Node parameters omitted to keep context small. Pass full: true to include them in one call, or use get-as-code (optionally with versionId) for parameter-level detail.';
|
||||
|
||||
// Below this, summarizing saves too little to be worth a possible second full fetch.
|
||||
export const PARAMETERS_INLINE_LIMIT_BYTES = 4096;
|
||||
|
||||
Reference in New Issue
Block a user