mirror of
https://github.com/n8n-io/n8n
synced 2026-04-21 15:47:20 +00:00
fix(ai-builder): Unify post-build credential setup into single setup-workflow flow (#28273)
This commit is contained in:
parent
733812b1a1
commit
8f8b70a301
4 changed files with 19 additions and 34 deletions
|
|
@ -197,8 +197,9 @@ Always pass \`conversationContext\` when spawning background agents (\`build-wor
|
|||
**Post-build flow** (for direct builds via \`build-workflow-with-agent\`):
|
||||
1. Builder finishes → check if the workflow has mocked credentials, missing parameters, or unconfigured triggers.
|
||||
2. If yes → call \`setup-workflow\` with the workflowId so the user can configure them through the setup UI.
|
||||
3. Ask the user if they want to test the workflow.
|
||||
4. Only call \`publish-workflow\` when the user explicitly asks to publish. Never publish automatically.
|
||||
3. When \`setup-workflow\` returns \`deferred: true\`, respect the user's decision — do not retry with \`setup-credentials\` or any other setup tool. The user chose to set things up later.
|
||||
4. Ask the user if they want to test the workflow.
|
||||
5. Only call \`publish-workflow\` when the user explicitly asks to publish. Never publish automatically.
|
||||
|
||||
## Tool Usage
|
||||
|
||||
|
|
@ -224,7 +225,7 @@ Examples: search "credential" to find setup/test/delete tools, search "file" for
|
|||
}## Safety
|
||||
|
||||
- **Destructive operations** show a confirmation UI automatically — don't ask via text.
|
||||
- **Credential setup** uses \`setup-workflow\` when a workflowId is available, or \`setup-credentials\` for standalone credential creation. For builds, credentials are auto-resolved when available and auto-mocked when missing — the user is prompted to finalize through the setup UI only after verification succeeds.
|
||||
- **Credential setup** uses \`setup-workflow\` when a workflowId is available — it handles credentials, parameters, and triggers in one step. Use \`setup-credentials\` only when the user explicitly asks to create a credential outside of any workflow context. Never call both tools for the same workflow.
|
||||
- **Never expose credential secrets** — metadata only.
|
||||
- **Be concise**. Ask for clarification when intent is ambiguous.
|
||||
- **Always end with a text response.** The user cannot see raw tool output. After every tool call sequence, reply with a brief summary of what you found or did — even if it's just one sentence. Never end your turn silently after tool calls.
|
||||
|
|
|
|||
|
|
@ -15,7 +15,6 @@ import { nanoid } from 'nanoid';
|
|||
import { createHash } from 'node:crypto';
|
||||
import { z } from 'zod';
|
||||
|
||||
import { createBrowserCredentialSetupTool } from './browser-credential-setup.tool';
|
||||
import {
|
||||
BUILDER_AGENT_PROMPT,
|
||||
createSandboxBuilderAgentPrompt,
|
||||
|
|
@ -43,7 +42,6 @@ import type { TriggerType, WorkflowBuildOutcome } from '../../workflow-loop';
|
|||
import type { BuilderWorkspace } from '../../workspace/builder-sandbox-factory';
|
||||
import { readFileViaSandbox } from '../../workspace/sandbox-fs';
|
||||
import { getWorkspaceRoot } from '../../workspace/sandbox-setup';
|
||||
import { createApplyWorkflowCredentialsTool } from '../workflows/apply-workflow-credentials.tool';
|
||||
import { buildCredentialMap, type CredentialMap } from '../workflows/resolve-credentials';
|
||||
import {
|
||||
createSubmitWorkflowTool,
|
||||
|
|
@ -131,13 +129,6 @@ The system tracks file hashes. If you edit the code and then call run-workflow o
|
|||
- If verification fails, call debug-execution, fix the code, re-submit, and retry once
|
||||
- If the same failure signature repeats, stop and explain the block
|
||||
|
||||
### Credential finalization
|
||||
|
||||
If verification succeeds with mocked credentials:
|
||||
1. call setup-credentials with credentialFlow stage "finalize"
|
||||
2. if it returns needsBrowserSetup=true, call browser-credential-setup then setup-credentials again
|
||||
3. call apply-workflow-credentials with the workItemId and selected credentials
|
||||
|
||||
### Resource discovery
|
||||
|
||||
Before writing code that uses external services, **resolve real resource IDs**:
|
||||
|
|
@ -204,7 +195,6 @@ export async function startBuildWorkflowAgentTask(
|
|||
'list-workflows',
|
||||
'list-credentials',
|
||||
'test-credential',
|
||||
'setup-credentials',
|
||||
'ask-user',
|
||||
'run-workflow',
|
||||
'get-execution',
|
||||
|
|
@ -227,10 +217,6 @@ export async function startBuildWorkflowAgentTask(
|
|||
}
|
||||
if (context.workflowTaskService && context.domainContext) {
|
||||
builderTools['verify-built-workflow'] = createVerifyBuiltWorkflowTool(context);
|
||||
builderTools['apply-workflow-credentials'] = createApplyWorkflowCredentialsTool(context);
|
||||
}
|
||||
if (context.browserMcpConfig) {
|
||||
builderTools['browser-credential-setup'] = createBrowserCredentialSetupTool(context);
|
||||
}
|
||||
} else {
|
||||
builderTools = {};
|
||||
|
|
|
|||
|
|
@ -54,24 +54,23 @@ describe('formatWorkflowLoopGuidance', () => {
|
|||
mockedCredentialTypes: ['slackOAuth2Api', 'gmailOAuth2'],
|
||||
};
|
||||
const result = formatWorkflowLoopGuidance(action);
|
||||
expect(result).toContain('setup-credentials');
|
||||
expect(result).toContain('slackOAuth2Api, gmailOAuth2');
|
||||
expect(result).toContain('finalize');
|
||||
expect(result).toContain('apply-workflow-credentials');
|
||||
expect(result).toContain('setup-workflow');
|
||||
expect(result).toContain('Do not call');
|
||||
});
|
||||
|
||||
it('should use workItemId from options when mockedCredentialTypes present', () => {
|
||||
it('should include workflowId in setup-workflow guidance when mockedCredentialTypes present', () => {
|
||||
const action: WorkflowLoopAction = {
|
||||
type: 'done',
|
||||
summary: 'Done with mocks',
|
||||
mockedCredentialTypes: ['notionApi'],
|
||||
workflowId: 'wf-42',
|
||||
};
|
||||
const result = formatWorkflowLoopGuidance(action, { workItemId: 'item-42' });
|
||||
expect(result).toContain('item-42');
|
||||
expect(result).not.toContain('unknown');
|
||||
const result = formatWorkflowLoopGuidance(action);
|
||||
expect(result).toContain('setup-workflow');
|
||||
expect(result).toContain('wf-42');
|
||||
});
|
||||
|
||||
it('should default workItemId to "unknown" when not provided and mocked credentials exist', () => {
|
||||
it('should default workflowId to "unknown" when not provided and mocked credentials exist', () => {
|
||||
const action: WorkflowLoopAction = {
|
||||
type: 'done',
|
||||
summary: 'Done with mocks',
|
||||
|
|
@ -251,14 +250,15 @@ describe('formatWorkflowLoopGuidance', () => {
|
|||
expect(occurrences).toBeGreaterThanOrEqual(2);
|
||||
});
|
||||
|
||||
it('should pass workItemId to done guidance with mocked credentials', () => {
|
||||
it('should include workflowId in done guidance with mocked credentials', () => {
|
||||
const action: WorkflowLoopAction = {
|
||||
type: 'done',
|
||||
summary: 'ok',
|
||||
mockedCredentialTypes: ['testApi'],
|
||||
workflowId: 'wf-xyz',
|
||||
};
|
||||
const result = formatWorkflowLoopGuidance(action, { workItemId: 'wi-xyz' });
|
||||
expect(result).toContain('wi-xyz');
|
||||
const result = formatWorkflowLoopGuidance(action);
|
||||
expect(result).toContain('wf-xyz');
|
||||
});
|
||||
|
||||
it('should not affect blocked or rebuild actions', () => {
|
||||
|
|
|
|||
|
|
@ -11,13 +11,11 @@ export function formatWorkflowLoopGuidance(
|
|||
switch (action.type) {
|
||||
case 'done': {
|
||||
if (action.mockedCredentialTypes?.length) {
|
||||
const types = action.mockedCredentialTypes.join(', ');
|
||||
return (
|
||||
'Workflow verified successfully with temporary mock data. ' +
|
||||
`Call \`setup-credentials\` with types [${types}] and ` +
|
||||
'credentialFlow stage "finalize" to let the user add real credentials. ' +
|
||||
'After the user selects credentials, call `apply-workflow-credentials` ' +
|
||||
`with the workItemId "${options.workItemId ?? 'unknown'}" and workflowId to apply them.`
|
||||
`Call \`setup-workflow\` with workflowId "${action.workflowId ?? 'unknown'}" ` +
|
||||
'to let the user configure credentials, parameters, and triggers through the setup UI. ' +
|
||||
'Do not call `setup-credentials` or `apply-workflow-credentials` — `setup-workflow` handles everything.'
|
||||
);
|
||||
}
|
||||
return `Workflow verified successfully. Report completion to the user.${action.workflowId ? ` Workflow ID: ${action.workflowId}` : ''}`;
|
||||
|
|
|
|||
Loading…
Reference in a new issue