From 38e4aebfc8e169e083122dbb9d29c7edc4a3254b Mon Sep 17 00:00:00 2001 From: Riqwan Thamir Date: Tue, 13 Oct 2026 13:29:11 +0000 Subject: [PATCH] perf(core): Reduce Agent Builder round trips in an initial build (no-changelog) (#40719) Co-authored-by: Cursor --- .../agents-builder.service.session.test.ts | 8 +- .../agents/builder/agents-builder-prompts.ts | 109 ++++++++++-------- .../agents/builder/agents-builder.service.ts | 10 -- .../builder/interactive/finish-setup.tool.ts | 2 +- .../builder/prompts/initial-build.prompt.ts | 7 +- .../builder/prompts/llm-selection.prompt.ts | 2 +- .../builder/prompts/planner-todos.prompt.ts | 26 ----- .../builder/skills/external-services.skill.ts | 17 ++- .../agents/builder/skills/node-tools.skill.ts | 4 +- .../builder/skills/target-skills.skill.ts | 6 +- .../builder/skills/target-tasks.skill.ts | 6 +- 11 files changed, 90 insertions(+), 107 deletions(-) delete mode 100644 packages/cli/src/modules/agents/builder/prompts/planner-todos.prompt.ts diff --git a/packages/cli/src/modules/agents/builder/__tests__/agents-builder.service.session.test.ts b/packages/cli/src/modules/agents/builder/__tests__/agents-builder.service.session.test.ts index 752fae4e1db..b9cd50d3d32 100644 --- a/packages/cli/src/modules/agents/builder/__tests__/agents-builder.service.session.test.ts +++ b/packages/cli/src/modules/agents/builder/__tests__/agents-builder.service.session.test.ts @@ -125,11 +125,6 @@ const agentsSdkMocks = vi.hoisted(() => { function createObservationLogReflectFn(model: unknown, options: unknown) { return { model, options, kind: 'reflect' }; } - - function createPlannerTodosTool(): BuiltTool { - return { name: 'write_todos', description: 'planner todos tool' } as BuiltTool; - } - return { streamCalls, resumeCalls, @@ -147,7 +142,6 @@ const agentsSdkMocks = vi.hoisted(() => { MockMemory, createObservationLogObserveFn, createObservationLogReflectFn, - createPlannerTodosTool, }; }); @@ -157,7 +151,6 @@ vi.mock('@n8n/agents', async (importOriginal) => ({ Memory: agentsSdkMocks.MockMemory, createObservationLogObserveFn: agentsSdkMocks.createObservationLogObserveFn, createObservationLogReflectFn: agentsSdkMocks.createObservationLogReflectFn, - createPlannerTodosTool: agentsSdkMocks.createPlannerTodosTool, })); // Avoid a real `models.dev` catalog fetch — irrelevant to thread isolation and @@ -406,6 +399,7 @@ describe('AgentsBuilderService session isolation', () => { expect(agentsSdkMocks.registeredToolNames).toEqual( expect.arrayContaining(['resolve_llm', 'agent-context', 'ask_credential']), ); + expect(agentsSdkMocks.registeredToolNames).not.toContain('write_todos'); }); it('registers the parent MCP tools for an initial builder turn', async () => { diff --git a/packages/cli/src/modules/agents/builder/agents-builder-prompts.ts b/packages/cli/src/modules/agents/builder/agents-builder-prompts.ts index 4eaa2c19bb5..3043e3f93b8 100644 --- a/packages/cli/src/modules/agents/builder/agents-builder-prompts.ts +++ b/packages/cli/src/modules/agents/builder/agents-builder-prompts.ts @@ -126,7 +126,7 @@ mutation, batching what you can) and follow-up turns where the user asked to do setup in chat. - \`finish_setup\`: use ONCE, only in the trailing step of an initial build - when only blocked tasks remain — the model choice and every open decision + when only pending setup remains — the model choice and every open decision as \`questions\`, one \`credentialRequests\` entry per credential slot, and one \`channels\` entry per drafted channel integration. It shows the setup cards back-to-back without returning control to you between them — @@ -245,35 +245,54 @@ item.`; export const WORKFLOW_SECTION = `\ ## Workflow -1. For every request that builds or changes the agent, call \`write_todos\` - with the full plan first — even short ones. Mark tasks that cannot - proceed without user input as \`blocked\`, stating exactly what is - missing. -2. For fresh agents, call \`agent-context({ type: "config" })\` first. If \`model\` and \`credential\` are - already set (the system auto-selected a sensible default at creation), keep - them and mention the choice as changeable in your summary — do not call - \`resolve_llm\`. If \`model\` is empty, call \`resolve_llm\` once, silently. If it - resolves — including an auto-picked provider or newly provisioned free OpenAI - credits — use the result and mention the choice in your summary. If it - reports missing or ambiguous credentials, mark the model - task \`blocked\` and keep building: write the config with \`model: ""\` and - no \`credential\`. -3. Draft lightweight target-agent \`instructions\` containing its identity, - overall purpose, and universal rules, then write the config early; never +1. For every request that builds or changes the agent, plan the full build + before your first tool call, even for short requests. The plan names every + config change, tool, skill, task, and integration that the agent's + functions need. It also lists the pending setup: each item that cannot + proceed without user input, with exactly what is missing. Do not write the + plan out. Keep to it until every item is done or pending. +2. For fresh agents, start with one discovery response. Call these tools in + parallel in that response: \`agent-context({ type: "config" })\`, + \`load_skill\` for each runtime skill the plan needs, and the discovery + lookups the plan names — \`agent-context({ type: "integrations" })\` for a + chat channel, and one \`agent-context({ type: "integrations", queries })\` + call for each callable service. A discovery lookup does not need the skill + text first. +3. In the next response, call \`get_node_types\` for the node results you will + use, and resolve the model in the same response. If \`model\` and + \`credential\` are already set (the system auto-selected a sensible default + at creation), keep them and mention the choice as changeable in your + summary — do not call \`resolve_llm\`. If \`model\` is empty, call + \`resolve_llm\` once, silently. If it resolves — including an auto-picked + provider or newly provisioned free OpenAI credits — use the result and + mention the choice in your summary. If it reports missing or ambiguous + credentials, add the model choice to the pending setup and keep building: + write the config with \`model: ""\` and no \`credential\`. +4. Write the config once, with everything discovery found: the name, + lightweight target-agent \`instructions\` (identity, overall purpose, and + universal rules), the model, the node tools, and the drafts for setup the + user must finish (channel integrations, MCP servers, empty credential + slots). Do not write a partial config and patch it in the next step. Never write empty placeholders, and never wait for setup answers before writing instructions, tools, skills, or tasks. -4. Load relevant runtime skills before specialized discovery or asset work. -5. Perform discovery and create or update the tools, focused skills, and tasks - required by the target agent's functions, whether or not the user named - those artifact types explicitly. +5. Create or update the focused skills and tasks required by the target + agent's functions, whether or not the user named those artifact types + explicitly. Use \`patch_config\` only for changes that discovery could not + know before the config write. 6. Follow Config Freshness for every config mutation: chain each write from the \`configHash\` your previous write returned. 7. When both skill and task batches are fully specified, call \`create_skills\` and \`create_tasks\` in the same assistant response. Do not combine either with an interactive tool or \`write_config\`/\`patch_config\` in that response. -8. When only blocked tasks remain, call \`finish_setup\` once with every - pending item, per the Initial Build section, then resolve its results and - finish the plan. Base any follow-up patch on the \`config\` and +8. When only pending setup remains, call \`finish_setup\` once with every + pending item, per the Initial Build section. Before that call, check the + plan: every item that does not need user input must be done. The + \`finish_setup\` input is your record of the pending items. After it + returns, resolve each item from its results and finish every build step + that waited on that input. Outside an initial build, if pending setup + remains at the end of the turn, end with a summary of what is missing, and + finish those items in later turns as the user gives the input. Base any + follow-up patch on the \`config\` and \`configHash\` that \`finish_setup\` returns (or on your last \`configHash\` when it showed no card and returned none); do not read the config again. 9. After setup is complete and the agent is runnable, call \`call_agent\` once @@ -290,20 +309,22 @@ export const FEW_SHOT_FLOWS_SECTION = `\ ## Example flows ### New agent: "Build me an agent teammates can @mention in Slack to triage messages" -1. \`write_todos\` with the plan. \`agent-context({ type: "config" })\` first — if a model and - credential are already set (system auto-selected default), keep them and - mention the choice as changeable; otherwise \`resolve_llm({})\` once, - silently; if it reports missing credentials, mark the model task \`blocked\`. -2. \`write_config(...)\` with the \`configHash\` from step 1, the name and - instructions, and the model and credential only if \`resolve_llm\` ran — - or \`model: ""\` and no \`credential\` while the model task is blocked. - Omit fields that are already stored and unchanged. -3. Load \`agent-builder-external-services\` and call \`agent-context({ type: "integrations" })\`. -4. \`patch_config(...)\` with the \`configHash\` that \`write_config\` returned, - adding the returned Slack type to \`/integrations/-\` with \`credentialId: ""\`. -5. \`finish_setup({ channels: [{ integrationType: "slack" }] })\` — include - \`questions: []\` only if the model task is blocked; when - \`resolve_llm\` already resolved in step 1, pass only the channel. For a +1. In one response, in parallel: \`agent-context({ type: "config" })\`, + \`load_skill\` for \`agent-builder-external-services\`, and + \`agent-context({ type: "integrations" })\`. +2. If a model and credential are already set (system auto-selected default), + keep them and mention the choice as changeable; otherwise + \`resolve_llm({})\` once, silently; if it reports missing credentials, add + the model choice to the pending setup. +3. \`write_config(...)\` with the \`configHash\` from step 1, the name and + instructions, the returned Slack type in \`integrations\` with + \`credentialId: ""\`, and the model and credential only if + \`resolve_llm\` ran — or \`model: ""\` and no \`credential\` while the + model choice is pending. Omit fields that are already stored and unchanged. +4. \`finish_setup({ channels: [{ integrationType: "slack" }] })\` — include + \`questions: []\` only if the model choice is pending; when + the model is already set or \`resolve_llm\` resolved it in step 2, pass + only the channel. For a model answer, call \`resolve_llm\` with it, then \`patch_config(...)\` with the \`configHash\` that \`finish_setup\` returned, replacing \`/model\` and \`/credential\`. The channel @@ -314,18 +335,16 @@ export const FEW_SHOT_FLOWS_SECTION = `\ the agent panel. ### New agent: "Use Anthropic via OpenRouter" -1. \`write_todos\` with the plan. -2. \`resolve_llm({ provider: "openrouter" })\`. -3. \`agent-context({ type: "config" })\`. -4. \`write_config(...)\` with \`model: "openrouter/{resolvedModel}"\`, +1. \`resolve_llm({ provider: "openrouter" })\`. +2. \`agent-context({ type: "config" })\`. +3. \`write_config(...)\` with \`model: "openrouter/{resolvedModel}"\`, \`credential\`, and requested instructions. ### Change the existing model -1. \`write_todos\` with the plan. -2. \`ask_questions({ ... })\` for the new model choice, then +1. \`ask_questions({ ... })\` for the new model choice, then \`resolve_llm({ provider, model })\`. -3. \`agent-context({ type: "config" })\`. -4. \`patch_config(...)\` replacing \`/model\` and \`/credential\`. +2. \`agent-context({ type: "config" })\`. +3. \`patch_config(...)\` replacing \`/model\` and \`/credential\`. ### Add an explicitly requested n8n node tool to an existing agent 1. Load \`agent-builder-node-tools\`, then call \`search_nodes\` and diff --git a/packages/cli/src/modules/agents/builder/agents-builder.service.ts b/packages/cli/src/modules/agents/builder/agents-builder.service.ts index ac8ba06cbea..e374e60e0c9 100644 --- a/packages/cli/src/modules/agents/builder/agents-builder.service.ts +++ b/packages/cli/src/modules/agents/builder/agents-builder.service.ts @@ -38,10 +38,6 @@ import { getModelRecommendationsSection } from './agents-builder-model-recommend import { buildBuilderPrompt, buildBuilderSessionContext } from './agents-builder-prompts'; import { AgentsBuilderToolsService, type BuilderTools } from './agents-builder-tools.service'; import { BuilderCheckpointUnavailableError } from './errors'; -import { - BUILDER_PLANNER_TODOS_DESCRIPTION, - BUILDER_PLANNER_TODOS_SYSTEM_INSTRUCTION, -} from './prompts/planner-todos.prompt'; import { getBuilderRuntimeSkills } from './skills'; import { N8NCheckpointStorage } from '../integrations/n8n-checkpoint-storage'; import { N8nMemory } from '../integrations/n8n-memory'; @@ -376,16 +372,10 @@ export class AgentsBuilderService { agentId: string, session: InstanceAiBuilderSessionOptions, ): Promise { - const { createPlannerTodosTool } = await import('@n8n/agents'); - const plannerTodosTool = createPlannerTodosTool({ - description: BUILDER_PLANNER_TODOS_DESCRIPTION, - systemInstruction: BUILDER_PLANNER_TODOS_SYSTEM_INSTRUCTION, - }); const reportRequiredArtifactTool = await this.createRequiredArtifactTool(session); const builderTools = [ ...tools.json, ...tools.shared, - plannerTodosTool, ...(reportRequiredArtifactTool ? [reportRequiredArtifactTool] : []), ]; const claimedToolNames = new Set(builderTools.map((tool) => tool.name)); diff --git a/packages/cli/src/modules/agents/builder/interactive/finish-setup.tool.ts b/packages/cli/src/modules/agents/builder/interactive/finish-setup.tool.ts index f2eddc01a93..e814fb03dcd 100644 --- a/packages/cli/src/modules/agents/builder/interactive/finish-setup.tool.ts +++ b/packages/cli/src/modules/agents/builder/interactive/finish-setup.tool.ts @@ -439,7 +439,7 @@ export function buildFinishSetupTool(deps: FinishSetupToolDeps): BuiltTool { 'Collect everything still needed to finish the initial build in ONE guided flow: open ' + 'questions (including the model choice), credential slots, and chat-channel ' + 'setup. Call it at most once, only in the trailing step of an initial build ' + - 'when only blocked tasks remain, and never together with another interactive tool. ' + + 'when only pending setup remains, and never together with another interactive tool. ' + 'It shows setup cards back-to-back without returning control between them: questions, ' + 'then credentials, then one card per requested channel. Channel cards always run last ' + 'after every credential phase, including when earlier setup was skipped or dismissed. Pass ' + diff --git a/packages/cli/src/modules/agents/builder/prompts/initial-build.prompt.ts b/packages/cli/src/modules/agents/builder/prompts/initial-build.prompt.ts index 9c80bed53b4..1576eed180c 100644 --- a/packages/cli/src/modules/agents/builder/prompts/initial-build.prompt.ts +++ b/packages/cli/src/modules/agents/builder/prompts/initial-build.prompt.ts @@ -49,14 +49,15 @@ During an initial build: \`credential\` omitted (skip verification), node tools with credential slots omitted. Leave Episodic Memory disabled while its credential is missing. -- Mark setup-dependent plan tasks \`blocked\`, stating exactly what is missing. -- When only blocked tasks remain, call \`finish_setup\` ONCE with everything +- Add each setup-dependent item to the pending setup, stating exactly what is + missing. Keep building everything that does not depend on it. +- When only pending setup remains, call \`finish_setup\` ONCE with everything pending: the model choice and open decisions as \`questions\`, one \`credentialRequests\` entry per credential slot, and one \`channels\` entry per drafted channel integration — it configures or skips each channel itself, always as the last cards in the flow. Resolve its results — \`resolve_llm\` with the model answer, patch returned credential ids into the config, - verify MCP servers — and finish the plan. + verify MCP servers — and finish every build step that waited on that setup. - Do not call \`configure_channel\` again after \`finish_setup\` handles a channel card. - After \`finish_setup\`, end your reply with a short setup checklist for skipped or dismissed setup that remains unresolved — one line per item naming diff --git a/packages/cli/src/modules/agents/builder/prompts/llm-selection.prompt.ts b/packages/cli/src/modules/agents/builder/prompts/llm-selection.prompt.ts index 98dd824bace..91b2fbb0efd 100644 --- a/packages/cli/src/modules/agents/builder/prompts/llm-selection.prompt.ts +++ b/packages/cli/src/modules/agents/builder/prompts/llm-selection.prompt.ts @@ -15,7 +15,7 @@ Use this to resolve the target agent's main \`model\` and \`credential\`. 2. If \`resolve_llm\` succeeds, persist \`model = "{provider}/{model}"\` and \`credential = credentialId\`. If the result has \`claimedFreeOpenAiCredits: true\`, tell the user you set them up with free OpenAI credits. If the result's \`credentialName\` is "Gateway credits" (its \`credentialId\` is the managed tag), persist it like any credential and tell the user the model runs on Gateway credits — never surface the internal "n8n Connect" or "AI Gateway" names. If it has \`autoPicked: true\`, tell the user which provider and model you picked and that they can ask to change it — do not ask for confirmation and do not raise a trailing model question. 3. If the user asks to pick, change, confirm, or configure a model or main credential, ask via \`ask_questions\`; do not ask in prose. - Exception — when the user explicitly asks to use Gateway credits for the main model, do NOT ask: call \`resolve_llm\` with \`useGatewayCredits: true\` (and \`provider\` when the user named one). It resolves Gateway credits for that provider even if the user already has their own credential for it; persist the result (\`credentialName\` "Gateway credits") and tell the user the model runs on Gateway credits. If it returns \`gateway_credits_unsupported_provider\`, tell the user Gateway credits do not cover that provider and offer their own credential; if \`ambiguous_gateway_credits_provider\`, ask which provider via \`ask_questions\` using the returned \`providers\`; if \`gateway_credits_unavailable\`, tell the user Gateway credits are not available on this instance and resolve their own credential instead. On \`unknown_model\`, retry with a value from the returned \`availableModels\` or surface those options. -4. During an initial build, if \`resolve_llm\` reports missing or ambiguous credentials/provider, do not ask: mark the model task \`blocked\`, keep building with \`model: ""\` and no \`credential\`, and include the model choice as a question in the trailing \`finish_setup\` call — for ambiguity between multiple credentials of one provider, use the credential names from the resolve_llm result as the question's options — when it resolves, call \`resolve_llm\` with the answer (pass \`credentialId\` when the user picked a specific credential) and patch \`/model\` and \`/credential\` — base the patch on the \`config\` and \`configHash\` that \`finish_setup\` returned, and check that config first, since the user may have already set the model in the panel. For a model change on an existing agent, ask immediately instead, and never write \`model: ""\` over an existing model — keep the current model and credential until the new one is resolved. +4. During an initial build, if \`resolve_llm\` reports missing or ambiguous credentials/provider, do not ask: add the model choice to the pending setup, keep building with \`model: ""\` and no \`credential\`, and include the model choice as a question in the trailing \`finish_setup\` call — for ambiguity between multiple credentials of one provider, use the credential names from the resolve_llm result as the question's options — when it resolves, call \`resolve_llm\` with the answer (pass \`credentialId\` when the user picked a specific credential) and patch \`/model\` and \`/credential\` — base the patch on the \`config\` and \`configHash\` that \`finish_setup\` returned, and check that config first, since the user may have already set the model in the panel. For a model change on an existing agent, ask immediately instead, and never write \`model: ""\` over an existing model — keep the current model and credential until the new one is resolved. 5. If \`resolve_llm\` reports \`unknown_model\`, retry with a plausible value from the returned \`availableModels\` or ask via \`ask_questions\`. This can happen on the default no-model path too, when the credential cannot reach the provider's default model — the returned \`availableModels\` is that credential's live list, so pick from it rather than guessing or reusing the id you just tried. That list is capped — when \`availableModelsTruncated: true\` it is only a sample of \`totalAvailableModels\`, so ask via \`ask_questions\` instead of assuming the model the user wants is absent. If it reports \`model_lookup_failed\` (the provider's model list could not be fetched, e.g. a transient error — possible even on the default no-model path), retry \`resolve_llm\`; do not guess a model. 6. If \`call_agent\` fails with \`code: "invalid_model"\`, the provider rejected the model id, not the credential. Do not tell the user to check, revoke, or regenerate their API key. Call \`resolve_llm\` for that provider again, persist a model from its result, and retry the test run. 7. If the model is still unresolved when the user asks to run or publish the agent, leave the draft with \`model: ""\`, do not guess a model, and tell the user the agent needs a model and credential first — in the panel or here in chat. If they dismiss a model-change question on an existing agent, keep the current model and credential unchanged. diff --git a/packages/cli/src/modules/agents/builder/prompts/planner-todos.prompt.ts b/packages/cli/src/modules/agents/builder/prompts/planner-todos.prompt.ts deleted file mode 100644 index a9591463313..00000000000 --- a/packages/cli/src/modules/agents/builder/prompts/planner-todos.prompt.ts +++ /dev/null @@ -1,26 +0,0 @@ -/** - * Builder-specific model-visible text for the SDK's `createPlannerTodosTool`. - * The SDK ships domain-neutral defaults; these strings keep the agent - * builder's `write_todos` tool description/instructions unchanged from - * before the SDK text was made generic. - */ -export const BUILDER_PLANNER_TODOS_DESCRIPTION = - 'Create or update a structured task list for the current build. Use it to decompose the work, ' + - 'track progress, and record which tasks are blocked on user input. Use it for every build or ' + - 'change request. This tool only updates the task list; it does not perform work or ask the user.'; - -export const BUILDER_PLANNER_TODOS_SYSTEM_INSTRUCTION = [ - 'write_todos maintains your plan for the current build. It never asks the user or performs work itself.', - 'WHEN TO USE write_todos:', - '- Every request that builds or changes the agent, before other tool calls.', - '- You need to track progress or record tasks blocked on user input.', - 'WHEN NOT TO USE write_todos:', - '- Purely conversational replies with no build work.', - 'HOW TO USE write_todos:', - '- Write concrete, self-contained tasks; mark the first active task in_progress immediately.', - '- Mark a task blocked when it cannot proceed without user input, and state exactly what input is missing in the task content.', - '- Marking a task blocked IS the action for now. Do not ask the user about it while any non-blocked task remains; continue with unblocked tasks.', - '- When only blocked tasks remain: during an initial build, follow the Initial Build rules (call finish_setup); otherwise end your turn with a summary of what is missing, and unblock and finish the tasks in later turns as the user provides input.', - '- Update task status as soon as work completes; do not batch completions at the end.', - '- Do not call write_todos multiple times in parallel; send one full list update at a time.', -].join('\n'); diff --git a/packages/cli/src/modules/agents/builder/skills/external-services.skill.ts b/packages/cli/src/modules/agents/builder/skills/external-services.skill.ts index 612419bd540..0df7d9bb633 100644 --- a/packages/cli/src/modules/agents/builder/skills/external-services.skill.ts +++ b/packages/cli/src/modules/agents/builder/skills/external-services.skill.ts @@ -133,10 +133,13 @@ The \`integrations\` array controls how the target agent is triggered. agent; do not follow up with \`patch_config\`/\`write_config\` to write the credential. - ${INITIAL_BUILD_NOTE} Instead of \`configure_channel\`: after - \`agent-context({ type: "integrations" })\` returns the matching type, - \`patch_config\` (with the \`configHash\` from your latest config read or write) adding \`{ "type": "", "credentialId": "" }\` - to \`/integrations/-\` (include a minimal valid draft \`settings\` object for - telegram) so the channel appears in the agent panel as needing setup. Pass + \`agent-context({ type: "integrations" })\` returns the matching type, add + \`{ "type": "", "credentialId": "" }\` to \`integrations\` + in your single initial config write (include a minimal valid draft + \`settings\` object for telegram) so the channel appears in the agent panel + as needing setup. If the config is already written, \`patch_config\` (with + the \`configHash\` from your latest config read or write) adding it to + \`/integrations/-\` instead. Pass the same \`integrationType\` in the trailing \`finish_setup\` call's \`channels\` array — its card configures or skips the channel itself. Do not call \`configure_channel\` again after \`finish_setup\` handles the card. If @@ -227,8 +230,10 @@ Follow these steps for the selected MCP result: credential is already persisted. ${INITIAL_BUILD_NOTE} For MCP that means: pick the best candidate as an -assumption (above), then \`patch_config\` (with the \`configHash\` from your latest config read or write) a draft -\`/mcpServers/-\` entry using \`name\`, \`url\`, \`transport\`, +assumption (above), then add a draft \`mcpServers\` entry to your single +initial config write (or \`patch_config\` it to \`/mcpServers/-\`, with the +\`configHash\` from your latest config read or write, if the config is +already written) using \`name\`, \`url\`, \`transport\`, \`authentication\`, and \`metadata.nodeTypeName\` from \`selectedResult\` with \`credential\` omitted, and skip \`verify_mcp_server\` — there is nothing to authenticate yet. Include the credential in the trailing \`finish_setup\` call; diff --git a/packages/cli/src/modules/agents/builder/skills/node-tools.skill.ts b/packages/cli/src/modules/agents/builder/skills/node-tools.skill.ts index 78ea6f669f3..a85cdc0d870 100644 --- a/packages/cli/src/modules/agents/builder/skills/node-tools.skill.ts +++ b/packages/cli/src/modules/agents/builder/skills/node-tools.skill.ts @@ -48,8 +48,8 @@ specific-page fetching, use only \`n8n-nodes-base.httpRequestTool\`. Use only an exact URL explicitly supplied by the user for \`n8n-nodes-base.httpRequestTool\`. If the user has not supplied one, you MUST -ask which URL the tool should fetch. During an initial build, mark this setup -as blocked and include the URL question in the single trailing \`finish_setup\` +ask which URL the tool should fetch. During an initial build, add this to the +pending setup and include the URL question in the single trailing \`finish_setup\` call; add the tool with the returned URL after the user answers. On later turns, call \`${ASK_QUESTIONS_TOOL_NAME}\` and wait for the answer before mutating the config. Do not search for, derive, infer, guess, or invent a URL diff --git a/packages/cli/src/modules/agents/builder/skills/target-skills.skill.ts b/packages/cli/src/modules/agents/builder/skills/target-skills.skill.ts index e6569370164..04e20d1a64a 100644 --- a/packages/cli/src/modules/agents/builder/skills/target-skills.skill.ts +++ b/packages/cli/src/modules/agents/builder/skills/target-skills.skill.ts @@ -68,9 +68,9 @@ applicable sections are filled with real content (the actual steps, rules, examples, and edge cases). Derive missing domain detail from the user's stated goal as stated assumptions, and list them in your summary. Use \`ask_questions\` only when even a reasonable assumption is impossible — never -during an initial build: mark the task \`blocked\` instead, per the Initial -Build rules in your system prompt. Never create a placeholder or vague -skill. +during an initial build: add the open decision to the pending setup +instead, per the Initial Build rules in your system prompt. Never create a +placeholder or vague skill. ## Workflow diff --git a/packages/cli/src/modules/agents/builder/skills/target-tasks.skill.ts b/packages/cli/src/modules/agents/builder/skills/target-tasks.skill.ts index c52b0541f9e..6bbba6f9c29 100644 --- a/packages/cli/src/modules/agents/builder/skills/target-tasks.skill.ts +++ b/packages/cli/src/modules/agents/builder/skills/target-tasks.skill.ts @@ -74,9 +74,9 @@ BOTH of these are true for it: as an assumption. Use \`ask_questions\` only when even a reasonable assumption is impossible — -never during an initial build: mark the task \`blocked\` instead, per the -Initial Build rules in your system prompt. Never create a placeholder or -"refine-it-later" task. +never during an initial build: add the open decision to the pending setup +instead, per the Initial Build rules in your system prompt. Never create a +placeholder or "refine-it-later" task. ## Workflow