@n8n/instance-ai 1.10.1 → 1.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (221) hide show
  1. package/README.md +128 -0
  2. package/dist/agent/instance-agent.js +8 -0
  3. package/dist/agent/instance-agent.js.map +1 -1
  4. package/dist/agent/shared-prompts.d.ts +1 -0
  5. package/dist/agent/shared-prompts.js +25 -0
  6. package/dist/agent/shared-prompts.js.map +1 -1
  7. package/dist/agent/sub-agent-debriefing.d.ts +8 -8
  8. package/dist/agent/system-prompt.d.ts +2 -0
  9. package/dist/agent/system-prompt.js +52 -93
  10. package/dist/agent/system-prompt.js.map +1 -1
  11. package/dist/build.tsbuildinfo +1 -1
  12. package/dist/constants/max-steps.d.ts +0 -1
  13. package/dist/constants/max-steps.js +0 -1
  14. package/dist/constants/max-steps.js.map +1 -1
  15. package/dist/index.d.ts +123 -33
  16. package/dist/index.js +103 -96
  17. package/dist/index.js.map +1 -1
  18. package/dist/knowledge-base/build-templates-index.d.ts +12 -0
  19. package/dist/knowledge-base/build-templates-index.js +113 -0
  20. package/dist/knowledge-base/build-templates-index.js.map +1 -0
  21. package/dist/knowledge-base/extract-builder-templates-archive.d.ts +2 -0
  22. package/dist/knowledge-base/extract-builder-templates-archive.js +89 -0
  23. package/dist/knowledge-base/extract-builder-templates-archive.js.map +1 -0
  24. package/dist/knowledge-base/materialize-knowledge-base.d.ts +67 -0
  25. package/dist/knowledge-base/materialize-knowledge-base.js +186 -0
  26. package/dist/knowledge-base/materialize-knowledge-base.js.map +1 -0
  27. package/dist/mcp/mcp-client-manager.js +6 -1
  28. package/dist/mcp/mcp-client-manager.js.map +1 -1
  29. package/dist/parsers/pdf-parser.js +4 -0
  30. package/dist/parsers/pdf-parser.js.map +1 -1
  31. package/dist/planned-tasks/planned-task-service.d.ts +5 -1
  32. package/dist/planned-tasks/planned-task-service.js +29 -1
  33. package/dist/planned-tasks/planned-task-service.js.map +1 -1
  34. package/dist/runtime/run-state-registry.d.ts +8 -0
  35. package/dist/runtime/run-state-registry.js.map +1 -1
  36. package/dist/runtime/terminal-response-guard.d.ts +2 -1
  37. package/dist/runtime/terminal-response-guard.js +20 -0
  38. package/dist/runtime/terminal-response-guard.js.map +1 -1
  39. package/dist/skills/materialize-runtime-skills.d.ts +1 -7
  40. package/dist/skills/materialize-runtime-skills.js +96 -176
  41. package/dist/skills/materialize-runtime-skills.js.map +1 -1
  42. package/dist/storage/index.d.ts +1 -1
  43. package/dist/storage/planned-task-storage.js +1 -0
  44. package/dist/storage/planned-task-storage.js.map +1 -1
  45. package/dist/storage/terminal-outcome-storage.d.ts +2 -2
  46. package/dist/storage/workflow-loop-storage.d.ts +199 -70
  47. package/dist/storage/workflow-loop-storage.js +107 -0
  48. package/dist/storage/workflow-loop-storage.js.map +1 -1
  49. package/dist/stream/work-summary-accumulator.d.ts +6 -6
  50. package/dist/tools/attachments/parse-file.tool.d.ts +18 -18
  51. package/dist/tools/credentials.tool.d.ts +2 -5
  52. package/dist/tools/credentials.tool.js +2 -6
  53. package/dist/tools/credentials.tool.js.map +1 -1
  54. package/dist/tools/executions.tool.js +53 -7
  55. package/dist/tools/executions.tool.js.map +1 -1
  56. package/dist/tools/index.js +3 -9
  57. package/dist/tools/index.js.map +1 -1
  58. package/dist/tools/nodes/node-search-engine.d.ts +2 -0
  59. package/dist/tools/nodes/node-search-engine.js +66 -7
  60. package/dist/tools/nodes/node-search-engine.js.map +1 -1
  61. package/dist/tools/nodes.tool.js +10 -3
  62. package/dist/tools/nodes.tool.js.map +1 -1
  63. package/dist/tools/orchestration/complete-checkpoint.tool.js +69 -0
  64. package/dist/tools/orchestration/complete-checkpoint.tool.js.map +1 -1
  65. package/dist/tools/orchestration/delegate.schemas.d.ts +5 -5
  66. package/dist/tools/orchestration/delegate.tool.js +1 -1
  67. package/dist/tools/orchestration/delegate.tool.js.map +1 -1
  68. package/dist/tools/orchestration/plan.tool.js +96 -60
  69. package/dist/tools/orchestration/plan.tool.js.map +1 -1
  70. package/dist/tools/orchestration/report-verification-verdict.tool.d.ts +9 -6
  71. package/dist/tools/orchestration/report-verification-verdict.tool.js +6 -1
  72. package/dist/tools/orchestration/report-verification-verdict.tool.js.map +1 -1
  73. package/dist/tools/orchestration/verify-built-workflow.tool.js +3 -2
  74. package/dist/tools/orchestration/verify-built-workflow.tool.js.map +1 -1
  75. package/dist/tools/tool-ids.d.ts +0 -5
  76. package/dist/tools/tool-ids.js +3 -7
  77. package/dist/tools/tool-ids.js.map +1 -1
  78. package/dist/tools/workflows/build-workflow.tool.d.ts +8 -2
  79. package/dist/tools/workflows/build-workflow.tool.js +371 -17
  80. package/dist/tools/workflows/build-workflow.tool.js.map +1 -1
  81. package/dist/tools/workflows/materialize-node-type.tool.d.ts +4 -4
  82. package/dist/tools/workflows/materialize-node-type.tool.js +2 -2
  83. package/dist/tools/workflows/materialize-node-type.tool.js.map +1 -1
  84. package/dist/tools/workflows/setup-workflow.schema.d.ts +32 -32
  85. package/dist/tools/workflows/submit-workflow.tool.d.ts +16 -12
  86. package/dist/tools/workflows/submit-workflow.tool.js +9 -2
  87. package/dist/tools/workflows/submit-workflow.tool.js.map +1 -1
  88. package/dist/tools/workflows/write-sandbox-file.tool.js +2 -2
  89. package/dist/tools/workflows/write-sandbox-file.tool.js.map +1 -1
  90. package/dist/tools/workflows.tool.js +5 -0
  91. package/dist/tools/workflows.tool.js.map +1 -1
  92. package/dist/tracing/langsmith-tracing.js +6 -1
  93. package/dist/tracing/langsmith-tracing.js.map +1 -1
  94. package/dist/tracing/trace-payloads.js +2 -6
  95. package/dist/tracing/trace-payloads.js.map +1 -1
  96. package/dist/types.d.ts +48 -9
  97. package/dist/types.js.map +1 -1
  98. package/dist/workflow-builder/build-failure-tracker.d.ts +10 -0
  99. package/dist/workflow-builder/build-failure-tracker.js +36 -0
  100. package/dist/workflow-builder/build-failure-tracker.js.map +1 -0
  101. package/dist/workflow-builder/index.d.ts +1 -0
  102. package/dist/workflow-builder/index.js +4 -1
  103. package/dist/workflow-builder/index.js.map +1 -1
  104. package/dist/workflow-loop/guidance.js +10 -6
  105. package/dist/workflow-loop/guidance.js.map +1 -1
  106. package/dist/workflow-loop/index.d.ts +3 -2
  107. package/dist/workflow-loop/index.js +14 -1
  108. package/dist/workflow-loop/index.js.map +1 -1
  109. package/dist/workflow-loop/runtime.js +3 -1
  110. package/dist/workflow-loop/runtime.js.map +1 -1
  111. package/dist/workflow-loop/verification-obligation.d.ts +15 -0
  112. package/dist/workflow-loop/verification-obligation.js +140 -0
  113. package/dist/workflow-loop/verification-obligation.js.map +1 -0
  114. package/dist/workflow-loop/workflow-loop-controller.js +26 -1
  115. package/dist/workflow-loop/workflow-loop-controller.js.map +1 -1
  116. package/dist/workflow-loop/workflow-loop-state.d.ts +416 -62
  117. package/dist/workflow-loop/workflow-loop-state.js +66 -1
  118. package/dist/workflow-loop/workflow-loop-state.js.map +1 -1
  119. package/dist/workspace/builder-templates-service.js.map +1 -1
  120. package/dist/workspace/compute-workspace-content-hash.d.ts +1 -0
  121. package/dist/workspace/compute-workspace-content-hash.js +15 -0
  122. package/dist/workspace/compute-workspace-content-hash.js.map +1 -0
  123. package/dist/workspace/create-workspace.d.ts +9 -43
  124. package/dist/workspace/create-workspace.js +45 -55
  125. package/dist/workspace/create-workspace.js.map +1 -1
  126. package/dist/workspace/lazy-runtime-workspace.js +1 -1
  127. package/dist/workspace/lazy-runtime-workspace.js.map +1 -1
  128. package/dist/workspace/prebaked-workspace-bundle.d.ts +39 -0
  129. package/dist/workspace/prebaked-workspace-bundle.js +75 -0
  130. package/dist/workspace/prebaked-workspace-bundle.js.map +1 -0
  131. package/dist/workspace/sandbox-fs.d.ts +9 -24
  132. package/dist/workspace/sandbox-fs.js +2 -16
  133. package/dist/workspace/sandbox-fs.js.map +1 -1
  134. package/dist/workspace/sandbox-setup.d.ts +1 -7
  135. package/dist/workspace/sandbox-setup.js +28 -170
  136. package/dist/workspace/sandbox-setup.js.map +1 -1
  137. package/dist/workspace/snapshot-image-context.d.ts +5 -0
  138. package/dist/workspace/snapshot-image-context.js +36 -0
  139. package/dist/workspace/snapshot-image-context.js.map +1 -0
  140. package/dist/workspace/snapshot-manager.d.ts +9 -9
  141. package/dist/workspace/snapshot-manager.js +57 -67
  142. package/dist/workspace/snapshot-manager.js.map +1 -1
  143. package/dist/workspace/template-telemetry.js +4 -4
  144. package/dist/workspace/template-telemetry.js.map +1 -1
  145. package/dist/workspace/workspace-file-content.d.ts +2 -0
  146. package/dist/workspace/workspace-file-content.js +11 -0
  147. package/dist/workspace/workspace-file-content.js.map +1 -0
  148. package/dist/workspace/workspace-files.d.ts +20 -0
  149. package/dist/workspace/workspace-files.js +74 -0
  150. package/dist/workspace/workspace-files.js.map +1 -0
  151. package/dist/workspace/workspace-manifest.d.ts +12 -0
  152. package/dist/workspace/workspace-manifest.js +28 -0
  153. package/dist/workspace/workspace-manifest.js.map +1 -0
  154. package/package.json +21 -15
  155. package/skills/data-table-manager/SKILL.md +6 -6
  156. package/skills/debugging-executions/SKILL.md +44 -0
  157. package/skills/planned-task-runtime/SKILL.md +163 -0
  158. package/skills/planning/SKILL.md +137 -0
  159. package/skills/post-build-flow/SKILL.md +119 -0
  160. package/skills/post-build-flow/references/trigger-input-data-shapes.md +38 -0
  161. package/skills/workflow-builder/SKILL.md +608 -0
  162. package/dist/tools/best-practices/index.d.ts +0 -2
  163. package/dist/tools/best-practices/index.js +0 -10
  164. package/dist/tools/best-practices/index.js.map +0 -1
  165. package/dist/tools/best-practices/techniques.d.ts +0 -1
  166. package/dist/tools/best-practices/techniques.js +0 -7
  167. package/dist/tools/best-practices/techniques.js.map +0 -1
  168. package/dist/tools/orchestration/add-plan-item.tool.d.ts +0 -5
  169. package/dist/tools/orchestration/add-plan-item.tool.js +0 -89
  170. package/dist/tools/orchestration/add-plan-item.tool.js.map +0 -1
  171. package/dist/tools/orchestration/blueprint-accumulator.d.ts +0 -49
  172. package/dist/tools/orchestration/blueprint-accumulator.js +0 -176
  173. package/dist/tools/orchestration/blueprint-accumulator.js.map +0 -1
  174. package/dist/tools/orchestration/blueprint.schema.d.ts +0 -182
  175. package/dist/tools/orchestration/blueprint.schema.js +0 -56
  176. package/dist/tools/orchestration/blueprint.schema.js.map +0 -1
  177. package/dist/tools/orchestration/build-workflow-agent.prompt.d.ts +0 -8
  178. package/dist/tools/orchestration/build-workflow-agent.prompt.js +0 -466
  179. package/dist/tools/orchestration/build-workflow-agent.prompt.js.map +0 -1
  180. package/dist/tools/orchestration/build-workflow-agent.tool.d.ts +0 -148
  181. package/dist/tools/orchestration/build-workflow-agent.tool.js +0 -1498
  182. package/dist/tools/orchestration/build-workflow-agent.tool.js.map +0 -1
  183. package/dist/tools/orchestration/builder-memory-compaction.d.ts +0 -42
  184. package/dist/tools/orchestration/builder-memory-compaction.js +0 -132
  185. package/dist/tools/orchestration/builder-memory-compaction.js.map +0 -1
  186. package/dist/tools/orchestration/plan-agent-prompt.d.ts +0 -1
  187. package/dist/tools/orchestration/plan-agent-prompt.js +0 -83
  188. package/dist/tools/orchestration/plan-agent-prompt.js.map +0 -1
  189. package/dist/tools/orchestration/plan-with-agent.tool.d.ts +0 -27
  190. package/dist/tools/orchestration/plan-with-agent.tool.js +0 -710
  191. package/dist/tools/orchestration/plan-with-agent.tool.js.map +0 -1
  192. package/dist/tools/orchestration/submit-plan.tool.d.ts +0 -3
  193. package/dist/tools/orchestration/submit-plan.tool.js +0 -98
  194. package/dist/tools/orchestration/submit-plan.tool.js.map +0 -1
  195. package/dist/tools/templates.tool.d.ts +0 -1
  196. package/dist/tools/templates.tool.js +0 -58
  197. package/dist/tools/templates.tool.js.map +0 -1
  198. package/dist/workspace/daytona-auth-manager.d.ts +0 -26
  199. package/dist/workspace/daytona-auth-manager.js +0 -90
  200. package/dist/workspace/daytona-auth-manager.js.map +0 -1
  201. package/dist/workspace/daytona-filesystem.d.ts +0 -25
  202. package/dist/workspace/daytona-filesystem.js +0 -132
  203. package/dist/workspace/daytona-filesystem.js.map +0 -1
  204. package/dist/workspace/daytona-sandbox.d.ts +0 -71
  205. package/dist/workspace/daytona-sandbox.js +0 -368
  206. package/dist/workspace/daytona-sandbox.js.map +0 -1
  207. package/dist/workspace/lazy-daytona.d.ts +0 -2
  208. package/dist/workspace/lazy-daytona.js +0 -12
  209. package/dist/workspace/lazy-daytona.js.map +0 -1
  210. package/dist/workspace/local-filesystem.d.ts +0 -48
  211. package/dist/workspace/local-filesystem.js +0 -250
  212. package/dist/workspace/local-filesystem.js.map +0 -1
  213. package/dist/workspace/local-sandbox.d.ts +0 -28
  214. package/dist/workspace/local-sandbox.js +0 -121
  215. package/dist/workspace/local-sandbox.js.map +0 -1
  216. package/dist/workspace/n8n-sandbox-filesystem.d.ts +0 -25
  217. package/dist/workspace/n8n-sandbox-filesystem.js +0 -128
  218. package/dist/workspace/n8n-sandbox-filesystem.js.map +0 -1
  219. package/dist/workspace/n8n-sandbox-sandbox.d.ts +0 -35
  220. package/dist/workspace/n8n-sandbox-sandbox.js +0 -143
  221. package/dist/workspace/n8n-sandbox-sandbox.js.map +0 -1
@@ -1,1498 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.buildWorkflowAgentInputSchema = exports.DETACHED_BUILDER_REQUIREMENTS = void 0;
4
- exports.getBuilderSessionMemory = getBuilderSessionMemory;
5
- exports.builderWorkflowWorkspaceLayout = builderWorkflowWorkspaceLayout;
6
- exports.materializeBuilderRuntimeSkills = materializeBuilderRuntimeSkills;
7
- exports.buildWarmBuilderFollowUp = buildWarmBuilderFollowUp;
8
- exports.recordSuccessfulWorkflowBuilds = recordSuccessfulWorkflowBuilds;
9
- exports.determineVerificationReadiness = determineVerificationReadiness;
10
- exports.determineSetupRequirement = determineSetupRequirement;
11
- exports.mergeLatestVerificationIntoOutcome = mergeLatestVerificationIntoOutcome;
12
- exports.withTerminalLoopState = withTerminalLoopState;
13
- exports.finalizeBuildResult = finalizeBuildResult;
14
- exports.createMainWorkflowSnapshot = createMainWorkflowSnapshot;
15
- exports.shouldFinalSubmitMainWorkflow = shouldFinalSubmitMainWorkflow;
16
- exports.supportingWorkflowIdsFromSubmitAttempts = supportingWorkflowIdsFromSubmitAttempts;
17
- exports.resultFromPostStreamError = resultFromPostStreamError;
18
- exports.resultFromTerminalRemediation = resultFromTerminalRemediation;
19
- exports.resultFromLaterFailedMainSubmit = resultFromLaterFailedMainSubmit;
20
- exports.attemptFromAutoResubmit = attemptFromAutoResubmit;
21
- exports.shouldRecoverSavedWorkflowAfterFailedSubmit = shouldRecoverSavedWorkflowAfterFailedSubmit;
22
- exports.settleMissingMainWorkflowSubmit = settleMissingMainWorkflowSubmit;
23
- exports.startBuildWorkflowAgentTask = startBuildWorkflowAgentTask;
24
- exports.createBuildWorkflowAgentTool = createBuildWorkflowAgentTool;
25
- const agents_1 = require("@n8n/agents");
26
- const workflow_sdk_1 = require("@n8n/workflow-sdk");
27
- const n8n_workflow_1 = require("n8n-workflow");
28
- const nanoid_1 = require("nanoid");
29
- const node_crypto_1 = require("node:crypto");
30
- const zod_1 = require("zod");
31
- const agent_persistence_1 = require("./agent-persistence");
32
- const build_workflow_agent_prompt_1 = require("./build-workflow-agent.prompt");
33
- const builder_memory_compaction_1 = require("./builder-memory-compaction");
34
- const display_utils_1 = require("./display-utils");
35
- const tracing_utils_1 = require("./tracing-utils");
36
- const verify_built_workflow_tool_1 = require("./verify-built-workflow.tool");
37
- const runtime_workspace_1 = require("../../agent/runtime-workspace");
38
- const sub_agent_briefing_1 = require("../../agent/sub-agent-briefing");
39
- const max_steps_1 = require("../../constants/max-steps");
40
- const materialize_runtime_skills_1 = require("../../skills/materialize-runtime-skills");
41
- const runtime_skills_1 = require("../../skills/runtime-skills");
42
- const consume_with_hitl_1 = require("../../stream/consume-with-hitl");
43
- const tool_registry_1 = require("../../tool-registry");
44
- const langsmith_tracing_1 = require("../../tracing/langsmith-tracing");
45
- const extract_code_1 = require("../../workflow-builder/extract-code");
46
- const workflow_loop_1 = require("../../workflow-loop");
47
- const sandbox_fs_1 = require("../../workspace/sandbox-fs");
48
- const sandbox_setup_1 = require("../../workspace/sandbox-setup");
49
- const scoped_workspace_1 = require("../../workspace/scoped-workspace");
50
- const template_telemetry_1 = require("../../workspace/template-telemetry");
51
- const credentials_tool_1 = require("../credentials.tool");
52
- const data_tables_tool_1 = require("../data-tables.tool");
53
- const ask_user_tool_1 = require("../shared/ask-user.tool");
54
- const resolve_credentials_1 = require("../workflows/resolve-credentials");
55
- const submit_workflow_identity_1 = require("../workflows/submit-workflow-identity");
56
- const workflow_json_utils_1 = require("../workflows/workflow-json-utils");
57
- const workflows_tool_1 = require("../workflows.tool");
58
- const WORKFLOW_NOT_SUBMITTED_FAILURE_SIGNATURE = 'workflow:not_submitted';
59
- const WORKFLOW_FINAL_SUBMIT_FAILED_FAILURE_SIGNATURE = 'workflow:final_submit_failed';
60
- function getBuilderSessionMemory(context, useSharedWorkspace) {
61
- return useSharedWorkspace ? context.memory : undefined;
62
- }
63
- const BUILDER_WORK_ITEMS_DIR = 'builder-work-items';
64
- function safeWorkItemPathSegment(workItemId) {
65
- const slug = workItemId
66
- .replace(/[^A-Za-z0-9_-]+/g, '-')
67
- .replace(/^-+|-+$/g, '')
68
- .slice(0, 48);
69
- const hash = (0, node_crypto_1.createHash)('sha256').update(workItemId).digest('hex').slice(0, 8);
70
- return `${slug || 'work-item'}-${hash}`;
71
- }
72
- function builderWorkflowWorkspaceLayout(root, workItemId) {
73
- const relativeWorkItemRoot = `${BUILDER_WORK_ITEMS_DIR}/${safeWorkItemPathSegment(workItemId)}`;
74
- const workItemRoot = `${root}/${relativeWorkItemRoot}`;
75
- return {
76
- workItemRoot,
77
- sourceDir: `${workItemRoot}/src`,
78
- chunksDir: `${workItemRoot}/chunks`,
79
- mainWorkflowPath: `${workItemRoot}/src/workflow.ts`,
80
- tsconfigPath: `${workItemRoot}/tsconfig.json`,
81
- relativeMainWorkflowPath: `${relativeWorkItemRoot}/src/workflow.ts`,
82
- };
83
- }
84
- function renderBuilderTaskTsconfig() {
85
- return `${JSON.stringify({
86
- extends: '../../tsconfig.json',
87
- include: ['src/**/*.ts', 'chunks/**/*.ts'],
88
- }, null, 2)}\n`;
89
- }
90
- async function writeBuilderWorkspaceFile(workspace, filePath, content) {
91
- if (workspace.filesystem) {
92
- await workspace.filesystem.writeFile(filePath, content, { recursive: true });
93
- return;
94
- }
95
- await (0, sandbox_fs_1.writeFileViaSandbox)(workspace, filePath, content);
96
- }
97
- async function materializeBuilderRuntimeSkills(context, workspace, root) {
98
- const source = context.runtimeSkillCatalog ?? context.runtimeSkills;
99
- if (!(0, runtime_skills_1.hasRuntimeSkills)(source)) {
100
- return { workspace, source };
101
- }
102
- let materialized;
103
- try {
104
- const workspaceRoot = await (0, sandbox_setup_1.getWorkspaceRoot)(workspace);
105
- materialized = await (0, materialize_runtime_skills_1.createPrebakedRuntimeSkillsFromWorkspace)({
106
- source,
107
- workspace,
108
- root: workspaceRoot,
109
- workspaceRoot: root,
110
- logger: context.logger,
111
- });
112
- }
113
- catch (error) {
114
- context.logger.debug('Could not inspect prebaked runtime skills; materializing live', {
115
- error: error instanceof Error ? error.message : String(error),
116
- });
117
- }
118
- materialized ??= await (0, materialize_runtime_skills_1.materializeRuntimeSkillsIntoWorkspace)({
119
- source,
120
- workspace,
121
- root,
122
- logger: context.logger,
123
- });
124
- if (!materialized)
125
- return { workspace, source };
126
- return {
127
- workspace: (0, scoped_workspace_1.createScopedWorkspace)(workspace, root, materialized.env),
128
- source: materialized.source,
129
- };
130
- }
131
- function toToolRegistry(tools) {
132
- const registry = (0, tool_registry_1.createToolRegistry)();
133
- for (const tool of tools) {
134
- registry.set(tool.name, tool);
135
- }
136
- return registry;
137
- }
138
- const BUILDER_WORKFLOW_ACTIONS = [
139
- 'list',
140
- 'get',
141
- 'get-as-code',
142
- ];
143
- const BUILDER_CREDENTIAL_ACTIONS = [
144
- 'list',
145
- 'get',
146
- 'search-types',
147
- 'test',
148
- ];
149
- const BUILDER_SANDBOX_TOOL_NAMES = [
150
- 'nodes',
151
- 'executions',
152
- data_tables_tool_1.DATA_TABLES_TOOL_ID,
153
- 'parse-file',
154
- ask_user_tool_1.ASK_USER_TOOL_ID,
155
- 'research',
156
- ];
157
- const BUILDER_TOOL_MODE_TOOL_NAMES = [
158
- 'build-workflow',
159
- 'nodes',
160
- 'workflows',
161
- data_tables_tool_1.DATA_TABLES_TOOL_ID,
162
- 'parse-file',
163
- ask_user_tool_1.ASK_USER_TOOL_ID,
164
- 'research',
165
- ];
166
- function createBuilderWorkflowsTool(context) {
167
- return (0, workflows_tool_1.createWorkflowsTool)(context, {
168
- allowedActions: BUILDER_WORKFLOW_ACTIONS,
169
- descriptionPrefix: 'Inspect workflows during build',
170
- });
171
- }
172
- function createBuilderCredentialsTool(context) {
173
- return (0, credentials_tool_1.createCredentialsTool)(context, {
174
- allowedActions: BUILDER_CREDENTIAL_ACTIONS,
175
- descriptionPrefix: 'Inspect credentials during build',
176
- descriptionSuffix: 'Setup is handled after workflow verification.',
177
- });
178
- }
179
- function buildWarmBuilderFollowUp(input) {
180
- const parts = [
181
- '<builder-follow-up type="fix">',
182
- `Work item ID: ${input.workItemId}`,
183
- `Workflow ID: ${input.workflowId}`,
184
- 'Continue from the existing sandbox files and your prior builder messages/tool calls. Apply the requested change, then submit the main workflow file.',
185
- '',
186
- exports.DETACHED_BUILDER_REQUIREMENTS,
187
- ];
188
- if (input.conversationContext) {
189
- parts.push('', '<conversation-context>', input.conversationContext, '</conversation-context>');
190
- }
191
- parts.push('', '<requested-change>', input.task, '</requested-change>', '</builder-follow-up>');
192
- return parts.join('\n');
193
- }
194
- async function promoteMainWorkflow(context, logger, workflowId) {
195
- if (!workflowId || !context)
196
- return;
197
- try {
198
- await context.workflowService.clearAiTemporary(workflowId);
199
- }
200
- catch (error) {
201
- logger.warn(`Failed to clear AI-builder temporary marker on main workflow ${workflowId}: ${error instanceof Error ? error.message : String(error)}`);
202
- }
203
- }
204
- function isRecord(value) {
205
- return typeof value === 'object' && value !== null;
206
- }
207
- function recordSuccessfulWorkflowBuilds(tool, onWorkflowId) {
208
- if (!tool?.handler)
209
- return;
210
- const original = tool.handler;
211
- const wrapped = async (input, ctx) => {
212
- const result = await original(input, ctx);
213
- if (isRecord(result) && result.success === true && typeof result.workflowId === 'string') {
214
- onWorkflowId(result.workflowId);
215
- }
216
- return result;
217
- };
218
- Object.assign(tool, { handler: wrapped });
219
- }
220
- function detectTriggerType(_attempt) {
221
- return 'manual_or_testable';
222
- }
223
- function hasMockedCredentials(outcome) {
224
- return ((outcome.mockedCredentialTypes?.length ?? 0) > 0 ||
225
- Object.keys(outcome.mockedCredentialsByNode ?? {}).length > 0);
226
- }
227
- function hasCredentialVerificationData(outcome) {
228
- return (Object.keys(outcome.verificationPinData ?? {}).length > 0 ||
229
- outcome.usesWorkflowPinDataForVerification === true);
230
- }
231
- function hasSuccessfulStructuredVerification(outcome) {
232
- return (outcome.verification?.attempted === true &&
233
- outcome.verification.success &&
234
- !!outcome.verification.executionId);
235
- }
236
- function determineVerificationReadiness(outcome) {
237
- if (hasSuccessfulStructuredVerification(outcome)) {
238
- return { status: 'already_verified' };
239
- }
240
- if (!outcome.submitted) {
241
- return {
242
- status: 'not_verifiable',
243
- reason: 'not-submitted',
244
- guidance: 'The build did not submit a workflow, so there is nothing to verify.',
245
- };
246
- }
247
- if (!outcome.workflowId) {
248
- return {
249
- status: 'not_verifiable',
250
- reason: 'missing-workflow-id',
251
- guidance: 'The build outcome does not include a workflow ID.',
252
- };
253
- }
254
- if (outcome.hasUnresolvedPlaceholders) {
255
- return {
256
- status: 'needs_setup',
257
- reason: 'unresolved-placeholders',
258
- guidance: 'Route the workflow through setup before verification.',
259
- };
260
- }
261
- if (hasMockedCredentials(outcome) && !hasCredentialVerificationData(outcome)) {
262
- return {
263
- status: 'needs_setup',
264
- reason: 'missing-mocked-credential-pin-data',
265
- guidance: 'Route the workflow through setup because mocked credentials cannot be verified.',
266
- };
267
- }
268
- if (outcome.remediation?.category === 'needs_setup') {
269
- return {
270
- status: 'needs_setup',
271
- reason: 'workflow-needs-setup',
272
- guidance: outcome.remediation.guidance,
273
- };
274
- }
275
- if (!outcome.triggerNodes?.some((node) => (0, workflow_json_utils_1.isMockableTriggerNodeType)(node.nodeType))) {
276
- return {
277
- status: 'not_verifiable',
278
- reason: 'non-mockable-trigger',
279
- guidance: 'The workflow does not have a trigger the post-build verifier can exercise.',
280
- };
281
- }
282
- return { status: 'ready' };
283
- }
284
- function determineSetupRequirement(outcome) {
285
- if (!outcome.submitted || !outcome.workflowId) {
286
- return { status: 'not_required' };
287
- }
288
- if (outcome.hasUnresolvedPlaceholders) {
289
- return {
290
- status: 'required',
291
- reason: 'unresolved-placeholders',
292
- guidance: 'Route the workflow through setup so the user can fill unresolved values.',
293
- };
294
- }
295
- if (hasMockedCredentials(outcome)) {
296
- return {
297
- status: 'required',
298
- reason: 'mocked-credentials',
299
- guidance: 'Route the workflow through setup so the user can add real credentials.',
300
- };
301
- }
302
- if (outcome.remediation?.category === 'needs_setup') {
303
- return {
304
- status: 'required',
305
- reason: 'workflow-needs-setup',
306
- guidance: outcome.remediation.guidance,
307
- };
308
- }
309
- return { status: 'not_required' };
310
- }
311
- function withDeterministicRouting(outcome) {
312
- return {
313
- ...outcome,
314
- verificationReadiness: determineVerificationReadiness(outcome),
315
- setupRequirement: determineSetupRequirement(outcome),
316
- };
317
- }
318
- function buildOutcome(workItemId, runId, taskId, attempt, finalText, supportingWorkflowIds = []) {
319
- if (!attempt?.success) {
320
- return withDeterministicRouting({
321
- workItemId,
322
- runId,
323
- taskId,
324
- submitted: false,
325
- triggerType: 'manual_or_testable',
326
- needsUserInput: false,
327
- failureSignature: attempt?.errors?.join('; '),
328
- remediation: attempt?.remediation,
329
- summary: finalText,
330
- });
331
- }
332
- const placeholderRemediation = attempt.hasUnresolvedPlaceholders
333
- ? (0, workflow_loop_1.createRemediation)({
334
- category: 'needs_setup',
335
- shouldEdit: false,
336
- reason: 'mocked_credentials_or_placeholders',
337
- guidance: 'Workflow submitted successfully, but unresolved setup values remain. Stop code edits and route to workflows(action="setup").',
338
- })
339
- : undefined;
340
- return withDeterministicRouting({
341
- workItemId,
342
- runId,
343
- taskId,
344
- workflowId: attempt.workflowId,
345
- submitted: true,
346
- triggerType: detectTriggerType(attempt),
347
- needsUserInput: Boolean(placeholderRemediation),
348
- blockingReason: placeholderRemediation?.guidance,
349
- mockedNodeNames: attempt.mockedNodeNames,
350
- mockedCredentialTypes: attempt.mockedCredentialTypes,
351
- mockedCredentialsByNode: attempt.mockedCredentialsByNode,
352
- triggerNodes: attempt.triggerNodes,
353
- verificationPinData: attempt.verificationPinData,
354
- usesWorkflowPinDataForVerification: attempt.usesWorkflowPinDataForVerification,
355
- supportingWorkflowIds: supportingWorkflowIds.length > 0 ? supportingWorkflowIds : undefined,
356
- hasUnresolvedPlaceholders: attempt.hasUnresolvedPlaceholders,
357
- remediation: placeholderRemediation ?? attempt.remediation,
358
- summary: finalText,
359
- });
360
- }
361
- function mergeLatestVerificationIntoOutcome(outcome, latestOutcome) {
362
- if (!latestOutcome?.verification)
363
- return outcome;
364
- if (latestOutcome.workItemId !== outcome.workItemId)
365
- return outcome;
366
- if (latestOutcome.taskId !== outcome.taskId)
367
- return outcome;
368
- if (outcome.workflowId &&
369
- latestOutcome.workflowId &&
370
- latestOutcome.workflowId !== outcome.workflowId) {
371
- return outcome;
372
- }
373
- return withDeterministicRouting({
374
- ...outcome,
375
- verification: latestOutcome.verification,
376
- });
377
- }
378
- function withTerminalLoopState(outcome, state) {
379
- const remediation = state?.lastRemediation;
380
- if (!outcome.submitted || !remediation || remediation.shouldEdit) {
381
- return outcome;
382
- }
383
- return withDeterministicRouting({
384
- ...outcome,
385
- workflowId: outcome.workflowId ?? state.workflowId,
386
- needsUserInput: remediation.category === 'needs_setup',
387
- blockingReason: remediation.guidance,
388
- remediation,
389
- });
390
- }
391
- async function finalBuildOutcome(context, workItemId, outcome) {
392
- const latestOutcome = await getLatestBuildOutcome(context, workItemId);
393
- const loopState = await context.workflowTaskService?.getWorkflowLoopState(workItemId);
394
- return withTerminalLoopState(mergeLatestVerificationIntoOutcome(outcome, latestOutcome), loopState);
395
- }
396
- async function finalizeBuildResult(context, workItemId, result) {
397
- return {
398
- text: result.text,
399
- outcome: await finalBuildOutcome(context, workItemId, result.outcome),
400
- };
401
- }
402
- async function reportAndFinalizeBuildResult(context, workItemId, result) {
403
- await context.workflowTaskService?.reportBuildOutcome(result.outcome);
404
- return await finalizeBuildResult(context, workItemId, result);
405
- }
406
- async function buildOutcomeWithLatestVerification(context, workItemId, taskId, attempt, finalText, supportingWorkflowIds = []) {
407
- const outcome = buildOutcome(workItemId, context.runId, taskId, attempt, finalText, supportingWorkflowIds);
408
- return await finalBuildOutcome(context, workItemId, outcome);
409
- }
410
- exports.DETACHED_BUILDER_REQUIREMENTS = `## Detached Task Contract
411
-
412
- You are running as a detached background task. Do not stop after a successful submit — verify the workflow works.
413
-
414
- ### Completion criteria
415
-
416
- Your job is done when ONE of these is true:
417
- - the workflow is verified (ran successfully)
418
- - you are blocked after one repair attempt per unique failure
419
-
420
- Do NOT stop after a successful submit without verifying. Every trigger type is testable:
421
- manual / schedule via \`executions(action="run")\`; event-based triggers (form, webhook,
422
- chat, mcp, linear, github, slack, etc.) via \`verify-built-workflow\` with an \`inputData\`
423
- payload. The pin-data adapter injects it as the trigger node's output.
424
-
425
- ### Submit discipline
426
-
427
- **Every file edit MUST be followed by submit-workflow before you do anything else.**
428
- The system tracks file hashes. If you edit the code and then call \`executions(action="run")\`, \`verify-built-workflow\`, or finish without re-submitting, your work is discarded. The sequence is always: edit → submit → then verify/run.
429
-
430
- ### Verification
431
-
432
- - If submit-workflow returned mocked credentials, call \`verify-built-workflow\` with the workItemId and workflowId from this task.
433
- - Otherwise pick based on trigger type:
434
- - **Manual / Schedule** — \`executions(action="run")\`.
435
- - **Form Trigger** — pass \`inputData\` as a flat field map, e.g. \`{name: "Alice", email: "a@b.c"}\`. Do NOT wrap in \`formFields\` — production Form Trigger emits fields directly on \`$json\`, and the adapter rejects wrapped payloads.
436
- - **Webhook** — \`verify-built-workflow\` with \`inputData\` as the body payload, e.g. \`{event: "signup", userId: "..."}\`. Adapter wraps it under \`body\`; downstream expressions use \`$json.body.<field>\`.
437
- - **Chat Trigger** — \`verify-built-workflow\` with \`{chatInput: "user message"}\`.
438
- - **Other event triggers (Linear, GitHub, Slack, MCP, etc.)** — \`verify-built-workflow\` with \`inputData\` matching the trigger's expected payload shape.
439
- - If verify-built-workflow returns remediation with \`shouldEdit: false\`, stop editing and follow its guidance.
440
- - If verification fails with \`shouldEdit: true\`, make one batched code repair and re-submit. Never exceed the remaining repair budget in the remediation metadata.
441
- - If verification fails otherwise, call \`executions(action="debug")\`, fix the code, re-submit, and retry once.
442
- - If the same failure signature repeats, stop and explain the block.
443
-
444
- ### Resource discovery
445
-
446
- Before writing code that uses external services, **resolve real resource IDs**:
447
- - Call \`nodes(action="explore-resources")\` for any parameter with searchListMethod (calendars, spreadsheets, channels, models, etc.)
448
- - Do NOT use "primary", "default", or any assumed identifier — look up the actual value
449
- - Call \`nodes(action="suggested")\` early if the workflow fits a known category (web_app, form_input, data_persistence, etc.) — the pattern hints prevent common mistakes
450
- - Check @builderHint annotations in node type definitions for critical configuration guidance
451
-
452
- ### Publishing
453
-
454
- Do NOT call \`workflows(action="publish")\` for the main workflow. Publishing is the user's decision after testing. Your job ends at a successful submit. The only exception is sub-workflows in the compositional pattern — those must be published so the parent workflow can reference them.
455
- `;
456
- function hashContent(content) {
457
- return (0, node_crypto_1.createHash)('sha256')
458
- .update(content ?? '', 'utf8')
459
- .digest('hex');
460
- }
461
- function createMainWorkflowSnapshot(content) {
462
- if (content === null) {
463
- return { exists: false };
464
- }
465
- return {
466
- exists: true,
467
- sourceHash: hashContent(content),
468
- };
469
- }
470
- function shouldFinalSubmitMainWorkflow(input) {
471
- return (input.current.exists &&
472
- (!input.initial.exists || input.initial.sourceHash !== input.current.sourceHash));
473
- }
474
- function buildNotSubmittedOutcome(workItemId, runId, taskId, finalText, failureSignature = WORKFLOW_NOT_SUBMITTED_FAILURE_SIGNATURE) {
475
- return withDeterministicRouting({
476
- workItemId,
477
- runId,
478
- taskId,
479
- submitted: false,
480
- triggerType: 'manual_or_testable',
481
- needsUserInput: false,
482
- failureSignature,
483
- summary: finalText,
484
- });
485
- }
486
- function deterministicSuffix(seed, label, length) {
487
- return (0, node_crypto_1.createHash)('sha256')
488
- .update(label)
489
- .update('\0')
490
- .update(seed)
491
- .digest('hex')
492
- .slice(0, length);
493
- }
494
- function shouldUseDeterministicBuilderIds(context) {
495
- return process.env.E2E_TESTS === 'true' && context.tracing?.replayMode !== 'off';
496
- }
497
- function createDeterministicBuilderIds(input) {
498
- const seed = JSON.stringify({
499
- task: input.task,
500
- workflowId: input.workflowId ?? '',
501
- plannedTaskId: input.plannedTaskId ?? '',
502
- conversationContext: input.conversationContext ?? '',
503
- });
504
- return {
505
- subAgentId: `agent-builder-${deterministicSuffix(seed, 'agent', 6)}`,
506
- taskId: `build-${deterministicSuffix(seed, 'task', 8)}`,
507
- workItemId: `wi_${deterministicSuffix(seed, 'work-item', 8)}`,
508
- };
509
- }
510
- function latestSuccessfulMainSubmit(submitAttempts, mainWorkflowPath) {
511
- for (let i = submitAttempts.length - 1; i >= 0; i--) {
512
- const attempt = submitAttempts[i];
513
- if (attempt.filePath === mainWorkflowPath && attempt.success && attempt.workflowId) {
514
- return attempt;
515
- }
516
- }
517
- return undefined;
518
- }
519
- function latestMainSubmit(submitAttempts, mainWorkflowPath) {
520
- for (let i = submitAttempts.length - 1; i >= 0; i--) {
521
- const attempt = submitAttempts[i];
522
- if (attempt.filePath === mainWorkflowPath) {
523
- return attempt;
524
- }
525
- }
526
- return undefined;
527
- }
528
- function supportingWorkflowIdsFromSubmitAttempts(submitAttempts, mainWorkflowPath, mainWorkflowId, referencedWorkflowIds = []) {
529
- const seen = new Set();
530
- const referencedWorkflowIdSet = new Set(referencedWorkflowIds);
531
- const supportingWorkflowIds = [];
532
- for (const attempt of submitAttempts) {
533
- if (!attempt.success || !attempt.workflowId)
534
- continue;
535
- if (attempt.filePath === mainWorkflowPath)
536
- continue;
537
- if (attempt.workflowId === mainWorkflowId)
538
- continue;
539
- if (!referencedWorkflowIdSet.has(attempt.workflowId))
540
- continue;
541
- if (seen.has(attempt.workflowId))
542
- continue;
543
- seen.add(attempt.workflowId);
544
- supportingWorkflowIds.push(attempt.workflowId);
545
- }
546
- return supportingWorkflowIds;
547
- }
548
- function resultFromPostStreamError(input) {
549
- const latestAttempt = latestMainSubmit(input.submitAttempts, input.mainWorkflowPath);
550
- if (!latestAttempt)
551
- return undefined;
552
- const attempt = latestAttempt.success
553
- ? latestAttempt
554
- : shouldRecoverSavedWorkflowAfterFailedSubmit(latestAttempt)
555
- ? latestSuccessfulMainSubmit(input.submitAttempts, input.mainWorkflowPath)
556
- : undefined;
557
- if (!attempt)
558
- return undefined;
559
- const errorText = input.error instanceof Error ? input.error.message : String(input.error);
560
- const text = `Workflow ${attempt.workflowId} submitted successfully. A later step failed: ${errorText}`;
561
- return {
562
- text,
563
- outcome: buildOutcome(input.workItemId, input.runId, input.taskId, attempt, text, supportingWorkflowIdsFromSubmitAttempts(input.submitAttempts, input.mainWorkflowPath, attempt.workflowId, attempt.referencedWorkflowIds)),
564
- };
565
- }
566
- function resultFromTerminalRemediation(input) {
567
- const latestAttempt = latestMainSubmit(input.submitAttempts, input.mainWorkflowPath);
568
- const attempt = latestAttempt &&
569
- !latestAttempt.success &&
570
- shouldRecoverSavedWorkflowAfterFailedSubmit(latestAttempt)
571
- ? (latestSuccessfulMainSubmit(input.submitAttempts, input.mainWorkflowPath) ?? latestAttempt)
572
- : latestAttempt;
573
- const text = input.remediation.guidance;
574
- const outcome = buildOutcome(input.workItemId, input.runId, input.taskId, attempt, text, supportingWorkflowIdsFromSubmitAttempts(input.submitAttempts, input.mainWorkflowPath, attempt?.workflowId, attempt?.referencedWorkflowIds));
575
- return {
576
- text,
577
- outcome: withDeterministicRouting({
578
- ...outcome,
579
- needsUserInput: outcome.needsUserInput || input.remediation.category === 'needs_setup',
580
- blockingReason: input.remediation.guidance,
581
- remediation: input.remediation,
582
- }),
583
- };
584
- }
585
- async function getWorkflowNodeSummaries(context, workflowId) {
586
- if (!context || !workflowId)
587
- return undefined;
588
- try {
589
- const json = await context.workflowService.getAsWorkflowJSON(workflowId);
590
- const summaries = [];
591
- for (const node of json.nodes ?? []) {
592
- if (!node.name || !node.type)
593
- continue;
594
- summaries.push({ name: node.name, type: node.type });
595
- }
596
- return summaries;
597
- }
598
- catch {
599
- return undefined;
600
- }
601
- }
602
- async function getLatestBuildOutcome(context, workItemId) {
603
- try {
604
- return await context.workflowTaskService?.getBuildOutcome(workItemId);
605
- }
606
- catch {
607
- return undefined;
608
- }
609
- }
610
- async function compactSuccessfulBuilderMemory(input) {
611
- if (!input.shouldUseBuilderMemory)
612
- return;
613
- try {
614
- const [nodeSummaries, latestOutcome] = await Promise.all([
615
- getWorkflowNodeSummaries(input.domainContext, input.workflowId),
616
- getLatestBuildOutcome(input.context, input.workItemId),
617
- ]);
618
- await (0, builder_memory_compaction_1.compactBuilderMemoryThread)({
619
- context: input.context,
620
- binding: input.binding,
621
- workflowId: input.workflowId,
622
- workItemId: input.workItemId,
623
- sourceFilePath: input.mainWorkflowPath,
624
- nodeSummaries,
625
- triggerNodes: input.mainWorkflowAttempt.triggerNodes,
626
- mockedNodeNames: input.mainWorkflowAttempt.mockedNodeNames,
627
- mockedCredentialTypes: input.mainWorkflowAttempt.mockedCredentialTypes,
628
- mockedCredentialsByNode: input.mainWorkflowAttempt.mockedCredentialsByNode,
629
- verification: latestOutcome?.verification,
630
- lastRequestedChange: input.lastRequestedChange,
631
- finalBuilderResult: input.finalText,
632
- });
633
- }
634
- catch {
635
- }
636
- }
637
- async function finalizeSuccessfulMainWorkflowSubmit(input) {
638
- await promoteMainWorkflow(input.domainContext, input.context.logger, input.mainWorkflowAttempt.workflowId);
639
- await compactSuccessfulBuilderMemory({
640
- context: input.context,
641
- binding: input.binding,
642
- domainContext: input.domainContext,
643
- workflowId: input.mainWorkflowAttempt.workflowId,
644
- workItemId: input.workItemId,
645
- mainWorkflowPath: input.mainWorkflowPath,
646
- mainWorkflowAttempt: input.mainWorkflowAttempt,
647
- lastRequestedChange: input.lastRequestedChange,
648
- finalText: input.finalText,
649
- shouldUseBuilderMemory: input.shouldUseBuilderMemory,
650
- });
651
- const outcome = await buildOutcomeWithLatestVerification(input.context, input.workItemId, input.taskId, input.mainWorkflowAttempt, input.finalText, supportingWorkflowIdsFromSubmitAttempts(input.submitAttemptHistory, input.mainWorkflowPath, input.mainWorkflowAttempt.workflowId, input.mainWorkflowAttempt.referencedWorkflowIds));
652
- return {
653
- text: input.finalText,
654
- outcome,
655
- };
656
- }
657
- function resultFromLaterFailedMainSubmit(input) {
658
- if (!shouldRecoverSavedWorkflowAfterFailedSubmit(input.failedAttempt))
659
- return undefined;
660
- const preservedAttempt = latestSuccessfulMainSubmit(input.submitAttempts, input.mainWorkflowPath);
661
- if (!preservedAttempt)
662
- return undefined;
663
- const errorText = input.failedAttempt.errors?.join(' ') ?? 'Unknown submit-workflow failure.';
664
- const text = `Workflow ${preservedAttempt.workflowId} was already submitted successfully. ` +
665
- `A later submit failed: ${errorText}`;
666
- return {
667
- text,
668
- outcome: buildOutcome(input.workItemId, input.runId, input.taskId, preservedAttempt, text, supportingWorkflowIdsFromSubmitAttempts(input.submitAttempts, input.mainWorkflowPath, preservedAttempt.workflowId, preservedAttempt.referencedWorkflowIds)),
669
- };
670
- }
671
- function isFreshAttemptForHash(attempt, sourceHash) {
672
- return attempt?.sourceHash === sourceHash;
673
- }
674
- function attemptFromAutoResubmit(input) {
675
- if (isFreshAttemptForHash(input.latestAttempt, input.sourceHash)) {
676
- return input.latestAttempt;
677
- }
678
- if (input.resubmit.success)
679
- return undefined;
680
- return {
681
- filePath: input.filePath,
682
- sourceHash: input.sourceHash,
683
- success: false,
684
- errors: input.resubmit.errors,
685
- remediation: input.resubmit.remediation,
686
- };
687
- }
688
- function shouldRecoverSavedWorkflowAfterFailedSubmit(attempt) {
689
- return attempt.remediation?.shouldEdit === false;
690
- }
691
- function formatSubmitWorkflowErrors(output, fallback) {
692
- const errors = output.errors?.join(' ') ?? '';
693
- return errors.length > 0 ? errors : fallback;
694
- }
695
- async function settleMissingMainWorkflowSubmit(input) {
696
- const currentSnapshot = createMainWorkflowSnapshot(input.currentMainWorkflow);
697
- const shouldFinalSubmit = shouldFinalSubmitMainWorkflow({
698
- initial: input.initialMainWorkflowSnapshot,
699
- current: currentSnapshot,
700
- });
701
- input.context.trackTelemetry?.('Builder finished without submit', {
702
- thread_id: input.context.threadId,
703
- run_id: input.runId,
704
- work_item_id: input.workItemId,
705
- ...(input.workflowId ? { workflow_id: input.workflowId } : {}),
706
- has_main_workflow_file: currentSnapshot.exists,
707
- main_workflow_changed: shouldFinalSubmit,
708
- final_settlement: shouldFinalSubmit
709
- ? 'final_submit'
710
- : input.currentMainWorkflow === null
711
- ? 'missing_file'
712
- : 'unchanged_file',
713
- });
714
- if (!shouldFinalSubmit) {
715
- const text = input.currentMainWorkflow === null
716
- ? 'Error: workflow builder finished without creating or submitting /src/workflow.ts.'
717
- : 'Error: workflow builder finished without submitting /src/workflow.ts; the file was unchanged from the start of the run.';
718
- return await reportAndFinalizeBuildResult(input.context, input.workItemId, {
719
- text,
720
- outcome: buildNotSubmittedOutcome(input.workItemId, input.runId, input.taskId, text),
721
- });
722
- }
723
- if (!input.submitTool?.handler) {
724
- const text = 'Error: workflow builder wrote /src/workflow.ts, but submit-workflow was unavailable for final settlement.';
725
- return await reportAndFinalizeBuildResult(input.context, input.workItemId, {
726
- text,
727
- outcome: buildNotSubmittedOutcome(input.workItemId, input.runId, input.taskId, text, WORKFLOW_FINAL_SUBMIT_FAILED_FAILURE_SIGNATURE),
728
- });
729
- }
730
- const attemptsBeforeFinalSubmit = input.submitAttemptHistory.length;
731
- let finalSubmit;
732
- try {
733
- const submitInput = { filePath: input.mainWorkflowPath };
734
- if (input.workflowId) {
735
- submitInput.workflowId = input.workflowId;
736
- }
737
- finalSubmit = (await input.submitTool.handler(submitInput, {}));
738
- }
739
- catch (error) {
740
- const message = error instanceof Error ? error.message : String(error);
741
- const recordedAttempt = input.submitAttempts.get(input.mainWorkflowPath);
742
- if (isFreshAttemptForHash(recordedAttempt, input.currentMainWorkflowHash)) {
743
- if (recordedAttempt.success) {
744
- return await input.onSuccessfulSubmit(recordedAttempt);
745
- }
746
- if (shouldRecoverSavedWorkflowAfterFailedSubmit(recordedAttempt)) {
747
- const recovered = resultFromLaterFailedMainSubmit({
748
- failedAttempt: recordedAttempt,
749
- submitAttempts: input.submitAttemptHistory,
750
- mainWorkflowPath: input.mainWorkflowPath,
751
- workItemId: input.workItemId,
752
- runId: input.runId,
753
- taskId: input.taskId,
754
- });
755
- if (recovered) {
756
- return await input.onRecoveredSubmit(recovered);
757
- }
758
- }
759
- const recordedErrors = recordedAttempt.errors?.join(' ') ?? message;
760
- const text = `Error: final submit of /src/workflow.ts failed. ${recordedErrors}`;
761
- return await finalizeBuildResult(input.context, input.workItemId, {
762
- text,
763
- outcome: buildOutcome(input.workItemId, input.runId, input.taskId, recordedAttempt, text),
764
- });
765
- }
766
- const text = `Error: final submit of /src/workflow.ts failed before recording an attempt. ${message}`;
767
- const result = {
768
- text,
769
- outcome: buildNotSubmittedOutcome(input.workItemId, input.runId, input.taskId, text, WORKFLOW_FINAL_SUBMIT_FAILED_FAILURE_SIGNATURE),
770
- };
771
- if (input.submitAttemptHistory.length === attemptsBeforeFinalSubmit) {
772
- return await reportAndFinalizeBuildResult(input.context, input.workItemId, result);
773
- }
774
- return await finalizeBuildResult(input.context, input.workItemId, result);
775
- }
776
- const refreshedAttempt = attemptFromAutoResubmit({
777
- latestAttempt: input.submitAttempts.get(input.mainWorkflowPath),
778
- resubmit: finalSubmit,
779
- filePath: input.mainWorkflowPath,
780
- sourceHash: input.currentMainWorkflowHash,
781
- });
782
- if (finalSubmit.success && refreshedAttempt?.success) {
783
- return await input.onSuccessfulSubmit(refreshedAttempt);
784
- }
785
- if (refreshedAttempt &&
786
- !refreshedAttempt.success &&
787
- shouldRecoverSavedWorkflowAfterFailedSubmit(refreshedAttempt)) {
788
- const recovered = resultFromLaterFailedMainSubmit({
789
- failedAttempt: refreshedAttempt,
790
- submitAttempts: input.submitAttemptHistory,
791
- mainWorkflowPath: input.mainWorkflowPath,
792
- workItemId: input.workItemId,
793
- runId: input.runId,
794
- taskId: input.taskId,
795
- });
796
- if (recovered) {
797
- return await input.onRecoveredSubmit(recovered);
798
- }
799
- }
800
- const finalSubmitErrors = refreshedAttempt?.errors?.join(' ') ??
801
- formatSubmitWorkflowErrors(finalSubmit, 'Final submit did not record a main workflow attempt.');
802
- const text = `Error: final submit of /src/workflow.ts failed. ${finalSubmitErrors}`;
803
- const result = {
804
- text,
805
- outcome: refreshedAttempt
806
- ? buildOutcome(input.workItemId, input.runId, input.taskId, refreshedAttempt, text)
807
- : buildNotSubmittedOutcome(input.workItemId, input.runId, input.taskId, text, WORKFLOW_FINAL_SUBMIT_FAILED_FAILURE_SIGNATURE),
808
- };
809
- const reportedMainAttempt = input.submitAttempts.get(input.mainWorkflowPath);
810
- if (!refreshedAttempt || refreshedAttempt !== reportedMainAttempt) {
811
- return await reportAndFinalizeBuildResult(input.context, input.workItemId, result);
812
- }
813
- return await finalizeBuildResult(input.context, input.workItemId, result);
814
- }
815
- async function startBuildWorkflowAgentTask(context, input) {
816
- if (!context.spawnBackgroundTask) {
817
- return {
818
- result: 'Error: background task support not available.',
819
- taskId: '',
820
- agentId: '',
821
- };
822
- }
823
- const spawnBackgroundTask = context.spawnBackgroundTask;
824
- const sharedWorkspace = context.workspace;
825
- const domainContext = context.domainContext;
826
- const useSandbox = !!sharedWorkspace && !!domainContext;
827
- let builderTools;
828
- let prompt = build_workflow_agent_prompt_1.BUILDER_AGENT_PROMPT;
829
- let credMap;
830
- if (useSandbox) {
831
- credMap = await (0, resolve_credentials_1.buildCredentialMap)(domainContext.credentialService);
832
- const builderWorkflowsTool = createBuilderWorkflowsTool(domainContext);
833
- const builderCredentialsTool = createBuilderCredentialsTool(domainContext);
834
- builderTools = (0, tool_registry_1.createToolRegistry)();
835
- for (const name of BUILDER_SANDBOX_TOOL_NAMES) {
836
- const tool = context.domainTools.get(name);
837
- if (tool) {
838
- builderTools.set(name, tool);
839
- }
840
- }
841
- builderTools.set('workflows', builderWorkflowsTool);
842
- builderTools.set(credentials_tool_1.CREDENTIALS_TOOL_ID, builderCredentialsTool);
843
- if (context.workflowTaskService && context.domainContext) {
844
- builderTools.set('verify-built-workflow', (0, verify_built_workflow_tool_1.createVerifyBuiltWorkflowTool)(context));
845
- }
846
- }
847
- else {
848
- builderTools = (0, tool_registry_1.createToolRegistry)();
849
- for (const name of BUILDER_TOOL_MODE_TOOL_NAMES) {
850
- const tool = context.domainTools.get(name);
851
- if (tool) {
852
- builderTools.set(name, tool);
853
- }
854
- }
855
- if (domainContext) {
856
- builderTools.set('workflows', createBuilderWorkflowsTool(domainContext));
857
- builderTools.set(credentials_tool_1.CREDENTIALS_TOOL_ID, createBuilderCredentialsTool(domainContext));
858
- }
859
- if (!builderTools.has('build-workflow')) {
860
- return { result: 'Error: build-workflow tool not available.', taskId: '', agentId: '' };
861
- }
862
- }
863
- const deterministicIds = shouldUseDeterministicBuilderIds(context)
864
- ? createDeterministicBuilderIds(input)
865
- : undefined;
866
- const subAgentId = input.agentId ?? deterministicIds?.subAgentId ?? `agent-builder-${(0, nanoid_1.nanoid)(6)}`;
867
- const taskId = input.taskId ?? deterministicIds?.taskId ?? `build-${(0, nanoid_1.nanoid)(8)}`;
868
- const baseWorkItemId = input.workItemId ??
869
- deterministicIds?.workItemId ??
870
- (input.workflowId ? `${context.runId}:default` : `wi_${(0, nanoid_1.nanoid)(8)}`);
871
- const { workflowId } = input;
872
- const workItemId = baseWorkItemId;
873
- const relativeMainWorkflowPath = builderWorkflowWorkspaceLayout('', workItemId).relativeMainWorkflowPath;
874
- const builderThreadId = (0, node_crypto_1.randomUUID)();
875
- const builderResourceId = (0, agent_persistence_1.createSubAgentResourceId)(context.threadId, 'workflow-builder');
876
- const builderMemoryBinding = {
877
- resource: builderResourceId,
878
- thread: builderThreadId,
879
- };
880
- let additionalContext = '';
881
- if (useSandbox && workflowId) {
882
- additionalContext = `[CONTEXT: Modifying existing workflow ${workflowId}. The current code is pre-loaded in ${relativeMainWorkflowPath} — read it first, then edit. Use workflowId "${workflowId}" when calling submit-workflow.]\n\n[WORK ITEM ID: ${workItemId}]`;
883
- }
884
- else if (useSandbox) {
885
- additionalContext = `[WORK ITEM ID: ${workItemId}]`;
886
- }
887
- else if (workflowId) {
888
- additionalContext = `[CONTEXT: Modifying existing workflow ${workflowId}. Use workflowId "${workflowId}" when calling build-workflow.]`;
889
- }
890
- const runningTaskSummaries = context.getRunningTaskSummaries?.();
891
- const briefing = await (0, sub_agent_briefing_1.buildSubAgentBriefing)({
892
- task: input.task,
893
- conversationContext: input.conversationContext,
894
- additionalContext: additionalContext || undefined,
895
- requirements: useSandbox ? exports.DETACHED_BUILDER_REQUIREMENTS : undefined,
896
- iteration: context.iterationLog
897
- ? {
898
- log: context.iterationLog,
899
- threadId: context.threadId,
900
- taskKey: `build:${workflowId ?? 'new'}`,
901
- }
902
- : undefined,
903
- runningTasks: runningTaskSummaries,
904
- });
905
- const detachedTraceFactory = (0, tracing_utils_1.createDetachedSubAgentTraceFactory)(context, {
906
- agentId: subAgentId,
907
- role: 'workflow-builder',
908
- kind: 'builder',
909
- taskId,
910
- plannedTaskId: input.plannedTaskId,
911
- workItemId,
912
- inputs: {
913
- task: input.task,
914
- workflowId: input.workflowId,
915
- conversationContext: input.conversationContext,
916
- },
917
- });
918
- const createTraceContext = async () => await detachedTraceFactory();
919
- const spawnOutcome = spawnBackgroundTask({
920
- taskId,
921
- threadId: context.threadId,
922
- agentId: subAgentId,
923
- role: 'workflow-builder',
924
- createTraceContext,
925
- plannedTaskId: input.plannedTaskId,
926
- workItemId,
927
- dedupeKey: {
928
- role: 'workflow-builder',
929
- plannedTaskId: input.plannedTaskId,
930
- workflowId: input.workflowId,
931
- },
932
- parentCheckpointId: context.isCheckpointFollowUp === true ? context.checkpointTaskId : undefined,
933
- run: async (signal, drainCorrections, waitForCorrection, { traceContext }) => await (0, tracing_utils_1.withTraceContextActor)(traceContext, async () => {
934
- const submitAttempts = new Map();
935
- const submitAttemptHistory = [];
936
- if (useSandbox && sharedWorkspace && domainContext) {
937
- let workspace = sharedWorkspace;
938
- const root = await (0, sandbox_setup_1.getWorkspaceRoot)(workspace);
939
- const materializedRuntimeSkills = await materializeBuilderRuntimeSkills(context, workspace, root);
940
- workspace = materializedRuntimeSkills.workspace;
941
- const runtimeSkills = materializedRuntimeSkills.source;
942
- const builderLayout = builderWorkflowWorkspaceLayout(root, workItemId);
943
- let telemetrySession;
944
- let unsubscribeTelemetry;
945
- try {
946
- telemetrySession = (0, template_telemetry_1.createTemplateTelemetrySession)({
947
- context,
948
- threadId: context.threadId,
949
- runId: context.runId,
950
- workItemId,
951
- userRequestExcerpt: input.task,
952
- templatesVersion: domainContext.templatesService?.getVersion() ?? null,
953
- });
954
- (0, template_telemetry_1.attachTemplateTelemetrySession)(workspace, telemetrySession);
955
- const templateToolObserver = (0, template_telemetry_1.createTypedToolObserver)(telemetrySession);
956
- unsubscribeTelemetry = context.eventBus.subscribe(context.threadId, (stored) => {
957
- if (stored.event.agentId !== subAgentId)
958
- return;
959
- templateToolObserver(stored.event);
960
- });
961
- prompt = (0, build_workflow_agent_prompt_1.createSandboxBuilderAgentPrompt)(root, {
962
- mainWorkflowPath: builderLayout.mainWorkflowPath,
963
- sourceDir: builderLayout.sourceDir,
964
- chunksDir: builderLayout.chunksDir,
965
- tsconfigPath: builderLayout.tsconfigPath,
966
- });
967
- await writeBuilderWorkspaceFile(workspace, builderLayout.tsconfigPath, renderBuilderTaskTsconfig());
968
- if (workflowId) {
969
- try {
970
- const json = await domainContext.workflowService.getAsWorkflowJSON(workflowId);
971
- const rawCode = (0, workflow_sdk_1.generateWorkflowCode)(json);
972
- const code = `${extract_code_1.SDK_IMPORT_STATEMENT}\n\n${rawCode}`;
973
- await writeBuilderWorkspaceFile(workspace, builderLayout.mainWorkflowPath, code);
974
- }
975
- catch {
976
- }
977
- }
978
- else {
979
- await writeBuilderWorkspaceFile(workspace, builderLayout.mainWorkflowPath, `${extract_code_1.SDK_IMPORT_STATEMENT}\n\n`);
980
- }
981
- const mainWorkflowPath = builderLayout.mainWorkflowPath;
982
- const initialMainWorkflowSnapshot = createMainWorkflowSnapshot(await (0, sandbox_fs_1.readFileViaSandbox)(workspace, mainWorkflowPath));
983
- builderTools.set('submit-workflow', (0, submit_workflow_identity_1.createIdentityEnforcedSubmitWorkflowTool)({
984
- context: domainContext,
985
- workspace,
986
- credentialMap: credMap,
987
- root,
988
- defaultFilePath: mainWorkflowPath,
989
- currentRunId: context.runId,
990
- getWorkflowLoopState: async () => await context.workflowTaskService?.getWorkflowLoopState(workItemId),
991
- onGuardFired: (event) => {
992
- context.trackTelemetry?.('Builder remediation guard fired', {
993
- thread_id: context.threadId,
994
- run_id: context.runId,
995
- work_item_id: workItemId,
996
- workflow_id: event.workflowId,
997
- category: event.category,
998
- attempt_count: event.attemptCount,
999
- reason: event.reason,
1000
- });
1001
- },
1002
- onAttempt: async (attempt) => {
1003
- submitAttempts.set(attempt.filePath, attempt);
1004
- submitAttemptHistory.push(attempt);
1005
- if (attempt.filePath !== mainWorkflowPath) {
1006
- return;
1007
- }
1008
- if (!context.workflowTaskService) {
1009
- return;
1010
- }
1011
- await context.workflowTaskService.reportBuildOutcome(buildOutcome(workItemId, context.runId, taskId, attempt, attempt.success
1012
- ? 'Workflow submitted and ready for verification.'
1013
- : (attempt.errors?.join(' ') ?? 'Workflow submission failed.')));
1014
- },
1015
- }));
1016
- const tracedBuilderTools = (0, tracing_utils_1.traceSubAgentTools)(context, builderTools, 'workflow-builder');
1017
- const runtimeWorkspaceTools = toToolRegistry(workspace.getTools());
1018
- const builderMemory = getBuilderSessionMemory(context, true);
1019
- const shouldUseBuilderMemory = Boolean(builderMemory);
1020
- const subAgent = new agents_1.Agent('Workflow Builder Agent')
1021
- .model(context.modelId)
1022
- .instructions(prompt, {
1023
- providerOptions: {
1024
- anthropic: { cacheControl: { type: 'ephemeral' } },
1025
- },
1026
- })
1027
- .tool((0, tool_registry_1.toolRegistryValues)(tracedBuilderTools))
1028
- .checkpoint(context.checkpointStore ?? 'memory');
1029
- (0, runtime_workspace_1.attachRuntimeWorkspaceCapabilities)(subAgent, { workspace, runtimeSkills });
1030
- if (builderMemory) {
1031
- subAgent.memory(builderMemory);
1032
- }
1033
- const telemetry = traceContext?.getTelemetry?.({
1034
- agentRole: 'workflow-builder',
1035
- functionId: 'instance-ai.subagent.workflow-builder',
1036
- executionMode: 'background_subagent',
1037
- metadata: { agent_id: subAgentId, task_id: taskId },
1038
- });
1039
- if (telemetry) {
1040
- subAgent.telemetry(telemetry);
1041
- }
1042
- (0, langsmith_tracing_1.mergeTraceRunInputs)(traceContext?.actorRun, (0, langsmith_tracing_1.buildAgentTraceInputs)({
1043
- systemPrompt: prompt,
1044
- tools: tracedBuilderTools,
1045
- runtimeTools: runtimeWorkspaceTools,
1046
- runtimeSkills: runtimeSkills?.registry,
1047
- modelId: context.modelId,
1048
- }));
1049
- let finalText;
1050
- try {
1051
- const persistence = await (0, agent_persistence_1.createSubAgentPersistence)(context, {
1052
- agentKind: 'workflow-builder',
1053
- threadId: builderThreadId,
1054
- resourceId: builderResourceId,
1055
- });
1056
- const resumeOptions = {
1057
- providerOptions: {
1058
- anthropic: { cacheControl: { type: 'ephemeral' } },
1059
- },
1060
- };
1061
- const stream = await subAgent.stream(briefing, {
1062
- maxIterations: max_steps_1.MAX_STEPS.BUILDER,
1063
- abortSignal: signal,
1064
- persistence,
1065
- providerOptions: {
1066
- anthropic: { cacheControl: { type: 'ephemeral' } },
1067
- },
1068
- });
1069
- const hitlResult = await (0, consume_with_hitl_1.consumeStreamWithHitl)({
1070
- agent: subAgent,
1071
- stream,
1072
- runId: context.runId,
1073
- agentId: subAgentId,
1074
- eventBus: context.eventBus,
1075
- logger: context.logger,
1076
- threadId: context.threadId,
1077
- abortSignal: signal,
1078
- waitForConfirmation: context.waitForConfirmation,
1079
- drainCorrections,
1080
- waitForCorrection,
1081
- maxIterations: max_steps_1.MAX_STEPS.BUILDER,
1082
- resumeOptions,
1083
- persistence,
1084
- });
1085
- finalText = await (0, consume_with_hitl_1.requireCompletedHitlText)(hitlResult, 'Workflow builder sub-agent');
1086
- }
1087
- catch (error) {
1088
- const recovered = resultFromPostStreamError({
1089
- error,
1090
- submitAttempts: submitAttemptHistory,
1091
- mainWorkflowPath,
1092
- workItemId,
1093
- runId: context.runId,
1094
- taskId,
1095
- });
1096
- if (recovered) {
1097
- await promoteMainWorkflow(domainContext, context.logger, recovered.outcome.workflowId);
1098
- return await finalizeBuildResult(context, workItemId, recovered);
1099
- }
1100
- throw error;
1101
- }
1102
- const mainWorkflowAttempt = submitAttempts.get(mainWorkflowPath);
1103
- const currentMainWorkflow = await (0, sandbox_fs_1.readFileViaSandbox)(workspace, mainWorkflowPath);
1104
- const currentMainWorkflowHash = hashContent(currentMainWorkflow);
1105
- if (!mainWorkflowAttempt) {
1106
- return await settleMissingMainWorkflowSubmit({
1107
- context,
1108
- workItemId,
1109
- runId: context.runId,
1110
- taskId,
1111
- workflowId,
1112
- mainWorkflowPath,
1113
- initialMainWorkflowSnapshot,
1114
- currentMainWorkflow,
1115
- currentMainWorkflowHash,
1116
- submitTool: tracedBuilderTools.get('submit-workflow'),
1117
- submitAttempts,
1118
- submitAttemptHistory,
1119
- finalText,
1120
- onSuccessfulSubmit: async (attempt) => await finalizeSuccessfulMainWorkflowSubmit({
1121
- context,
1122
- binding: builderMemoryBinding,
1123
- domainContext,
1124
- workItemId,
1125
- taskId,
1126
- mainWorkflowPath,
1127
- mainWorkflowAttempt: attempt,
1128
- submitAttemptHistory,
1129
- lastRequestedChange: input.task,
1130
- finalText,
1131
- shouldUseBuilderMemory,
1132
- }),
1133
- onRecoveredSubmit: async (recovered) => {
1134
- await promoteMainWorkflow(domainContext, context.logger, recovered.outcome.workflowId);
1135
- return await finalizeBuildResult(context, workItemId, recovered);
1136
- },
1137
- });
1138
- }
1139
- if (!mainWorkflowAttempt.success) {
1140
- const recovered = resultFromLaterFailedMainSubmit({
1141
- failedAttempt: mainWorkflowAttempt,
1142
- submitAttempts: submitAttemptHistory,
1143
- mainWorkflowPath,
1144
- workItemId,
1145
- runId: context.runId,
1146
- taskId,
1147
- });
1148
- if (recovered) {
1149
- await promoteMainWorkflow(domainContext, context.logger, recovered.outcome.workflowId);
1150
- return await finalizeBuildResult(context, workItemId, recovered);
1151
- }
1152
- const errorText = mainWorkflowAttempt.errors?.join(' ') ?? 'Unknown submit-workflow failure.';
1153
- const text = `Error: workflow builder stopped after a failed submit-workflow for ${mainWorkflowPath}. ${errorText}`;
1154
- return {
1155
- text,
1156
- outcome: buildOutcome(workItemId, context.runId, taskId, mainWorkflowAttempt, text),
1157
- };
1158
- }
1159
- if (mainWorkflowAttempt.sourceHash !== currentMainWorkflowHash) {
1160
- const submitTool = tracedBuilderTools.get('submit-workflow');
1161
- if (submitTool?.handler) {
1162
- const resubmit = (await submitTool.handler({
1163
- filePath: mainWorkflowPath,
1164
- workflowId: mainWorkflowAttempt.workflowId,
1165
- }, {}));
1166
- const refreshedAttempt = attemptFromAutoResubmit({
1167
- latestAttempt: submitAttempts.get(mainWorkflowPath),
1168
- resubmit,
1169
- filePath: mainWorkflowPath,
1170
- sourceHash: currentMainWorkflowHash,
1171
- });
1172
- if (resubmit.success && refreshedAttempt?.success) {
1173
- await promoteMainWorkflow(domainContext, context.logger, refreshedAttempt.workflowId);
1174
- await compactSuccessfulBuilderMemory({
1175
- context,
1176
- binding: builderMemoryBinding,
1177
- domainContext,
1178
- workflowId: refreshedAttempt.workflowId,
1179
- workItemId,
1180
- mainWorkflowPath,
1181
- mainWorkflowAttempt: refreshedAttempt,
1182
- lastRequestedChange: input.task,
1183
- finalText,
1184
- shouldUseBuilderMemory,
1185
- });
1186
- const outcome = await buildOutcomeWithLatestVerification(context, workItemId, taskId, refreshedAttempt, finalText);
1187
- return {
1188
- text: finalText,
1189
- outcome,
1190
- };
1191
- }
1192
- const resubmitErrors = refreshedAttempt?.errors?.join(' ') ??
1193
- formatSubmitWorkflowErrors(resubmit, 'Auto-re-submit failed.');
1194
- if (refreshedAttempt &&
1195
- !refreshedAttempt.success &&
1196
- shouldRecoverSavedWorkflowAfterFailedSubmit(refreshedAttempt)) {
1197
- const recovered = resultFromLaterFailedMainSubmit({
1198
- failedAttempt: refreshedAttempt,
1199
- submitAttempts: submitAttemptHistory,
1200
- mainWorkflowPath,
1201
- workItemId,
1202
- runId: context.runId,
1203
- taskId,
1204
- });
1205
- if (recovered) {
1206
- await promoteMainWorkflow(domainContext, context.logger, recovered.outcome.workflowId);
1207
- return await finalizeBuildResult(context, workItemId, recovered);
1208
- }
1209
- }
1210
- const text = `Error: auto-re-submit of edited ${mainWorkflowPath} failed. ${resubmitErrors}`;
1211
- return {
1212
- text,
1213
- outcome: buildOutcome(workItemId, context.runId, taskId, refreshedAttempt ?? undefined, text),
1214
- };
1215
- }
1216
- }
1217
- await promoteMainWorkflow(domainContext, context.logger, mainWorkflowAttempt.workflowId);
1218
- await compactSuccessfulBuilderMemory({
1219
- context,
1220
- binding: builderMemoryBinding,
1221
- domainContext,
1222
- workflowId: mainWorkflowAttempt.workflowId,
1223
- workItemId,
1224
- mainWorkflowPath,
1225
- mainWorkflowAttempt,
1226
- lastRequestedChange: input.task,
1227
- finalText,
1228
- shouldUseBuilderMemory,
1229
- });
1230
- const outcome = await buildOutcomeWithLatestVerification(context, workItemId, taskId, mainWorkflowAttempt, finalText);
1231
- return {
1232
- text: finalText,
1233
- outcome,
1234
- };
1235
- }
1236
- finally {
1237
- unsubscribeTelemetry?.();
1238
- if (telemetrySession) {
1239
- try {
1240
- telemetrySession.flush();
1241
- (0, template_telemetry_1.detachTemplateTelemetrySession)(workspace);
1242
- }
1243
- catch (error) {
1244
- context.logger.warn('build-workflow-agent: failed to flush template telemetry', {
1245
- error: error instanceof Error ? error.message : String(error),
1246
- });
1247
- }
1248
- }
1249
- }
1250
- }
1251
- let fallbackMainWorkflowId;
1252
- recordSuccessfulWorkflowBuilds(builderTools.get('build-workflow'), (workflowId) => {
1253
- fallbackMainWorkflowId = workflowId;
1254
- });
1255
- const tracedBuilderTools = (0, tracing_utils_1.traceSubAgentTools)(context, builderTools, 'workflow-builder');
1256
- const runtimeSkills = context.runtimeSkills;
1257
- const subAgent = new agents_1.Agent('Workflow Builder Agent')
1258
- .model(context.modelId)
1259
- .instructions(prompt, {
1260
- providerOptions: {
1261
- anthropic: { cacheControl: { type: 'ephemeral' } },
1262
- },
1263
- })
1264
- .tool((0, tool_registry_1.toolRegistryValues)(tracedBuilderTools))
1265
- .checkpoint(context.checkpointStore ?? 'memory');
1266
- (0, runtime_workspace_1.attachRuntimeWorkspaceCapabilities)(subAgent, { runtimeSkills });
1267
- const telemetry = traceContext?.getTelemetry?.({
1268
- agentRole: 'workflow-builder',
1269
- functionId: 'instance-ai.subagent.workflow-builder',
1270
- executionMode: 'background_subagent',
1271
- metadata: { agent_id: subAgentId, task_id: taskId },
1272
- });
1273
- if (telemetry) {
1274
- subAgent.telemetry(telemetry);
1275
- }
1276
- (0, langsmith_tracing_1.mergeTraceRunInputs)(traceContext?.actorRun, (0, langsmith_tracing_1.buildAgentTraceInputs)({
1277
- systemPrompt: prompt,
1278
- tools: tracedBuilderTools,
1279
- runtimeSkills: runtimeSkills?.registry,
1280
- modelId: context.modelId,
1281
- }));
1282
- const resumeOptions = {
1283
- providerOptions: {
1284
- anthropic: { cacheControl: { type: 'ephemeral' } },
1285
- },
1286
- };
1287
- const persistence = await (0, agent_persistence_1.createSubAgentPersistence)(context, {
1288
- agentKind: 'workflow-builder',
1289
- threadId: builderThreadId,
1290
- resourceId: builderResourceId,
1291
- });
1292
- const stream = await subAgent.stream(briefing, {
1293
- maxIterations: max_steps_1.MAX_STEPS.BUILDER,
1294
- abortSignal: signal,
1295
- persistence,
1296
- providerOptions: {
1297
- anthropic: { cacheControl: { type: 'ephemeral' } },
1298
- },
1299
- });
1300
- const hitlResult = await (0, consume_with_hitl_1.consumeStreamWithHitl)({
1301
- agent: subAgent,
1302
- stream,
1303
- runId: context.runId,
1304
- agentId: subAgentId,
1305
- eventBus: context.eventBus,
1306
- logger: context.logger,
1307
- threadId: context.threadId,
1308
- abortSignal: signal,
1309
- waitForConfirmation: context.waitForConfirmation,
1310
- drainCorrections,
1311
- waitForCorrection,
1312
- maxIterations: max_steps_1.MAX_STEPS.BUILDER,
1313
- resumeOptions,
1314
- persistence,
1315
- });
1316
- const toolFinalText = await (0, consume_with_hitl_1.requireCompletedHitlText)(hitlResult, 'Workflow builder sub-agent');
1317
- await promoteMainWorkflow(domainContext, context.logger, fallbackMainWorkflowId);
1318
- return { text: toolFinalText };
1319
- }),
1320
- });
1321
- if (spawnOutcome.status === 'duplicate') {
1322
- return {
1323
- result: `Workflow build already in progress (task: ${spawnOutcome.existing.taskId}). Acknowledge and wait for the planned-task-follow-up — do not dispatch again.`,
1324
- taskId: spawnOutcome.existing.taskId,
1325
- agentId: spawnOutcome.existing.agentId,
1326
- };
1327
- }
1328
- if (spawnOutcome.status === 'limit-reached') {
1329
- return {
1330
- result: 'Could not start build: concurrent background-task limit reached. Wait for an existing task to finish and try again.',
1331
- taskId: '',
1332
- agentId: '',
1333
- };
1334
- }
1335
- context.eventBus.publish(context.threadId, {
1336
- type: 'agent-spawned',
1337
- runId: context.runId,
1338
- agentId: subAgentId,
1339
- payload: {
1340
- parentId: context.orchestratorAgentId,
1341
- role: 'workflow-builder',
1342
- tools: (0, tool_registry_1.toolRegistryKeys)(builderTools),
1343
- taskId,
1344
- kind: 'builder',
1345
- title: 'Building workflow',
1346
- subtitle: (0, display_utils_1.truncateLabel)(input.task),
1347
- goal: input.task,
1348
- targetResource: input.workflowId
1349
- ? { type: 'workflow', id: input.workflowId }
1350
- : { type: 'workflow' },
1351
- },
1352
- });
1353
- return {
1354
- result: `Workflow build started (task: ${taskId}). Reply with one short sentence — e.g. name what's being built. Do NOT summarize the plan or list details.`,
1355
- taskId,
1356
- agentId: subAgentId,
1357
- };
1358
- }
1359
- exports.buildWorkflowAgentInputSchema = zod_1.z.object({
1360
- task: zod_1.z
1361
- .string()
1362
- .describe('What to build and any context: user requirements, available credential names/types.'),
1363
- workflowId: zod_1.z
1364
- .string()
1365
- .optional()
1366
- .describe('Existing workflow ID to modify. When provided, the agent starts with the current workflow code pre-loaded.'),
1367
- conversationContext: zod_1.z
1368
- .string()
1369
- .optional()
1370
- .describe('Brief summary of the conversation so far — what was discussed, decisions made, and information gathered (e.g., which credentials are available). The builder uses this to avoid repeating information the user already knows.'),
1371
- workItemId: zod_1.z
1372
- .string()
1373
- .optional()
1374
- .describe('Workflow-loop work item ID. Required for repair builds so remediation budgets continue on the same work item.'),
1375
- bypassPlan: zod_1.z
1376
- .boolean()
1377
- .optional()
1378
- .describe('Set to true for any edit to an existing workflow — adding/removing/rewiring a node, changing an expression, swapping a credential, changing a schedule, fixing a Code node. Requires an existing `workflowId` and a one-sentence `reason`. The orchestrator verifies the result afterwards via `verify-built-workflow` when the trigger is mockable. ' +
1379
- 'A runtime guard rejects direct calls without `bypassPlan: true` outside replan/checkpoint follow-ups: new workflow builds, multi-workflow work, and data-table schema changes must go through `plan` so the build gets its orchestrator-run checkpoint.'),
1380
- reason: zod_1.z
1381
- .string()
1382
- .optional()
1383
- .describe('One sentence explaining why the planner is being bypassed (e.g. "swap Slack channel on workflow X", "fix Code node shape issue"). Required when bypassPlan is true.'),
1384
- });
1385
- const buildWorkflowAgentSuspendSchema = zod_1.z.object({
1386
- requestId: zod_1.z.string(),
1387
- message: zod_1.z.string(),
1388
- severity: zod_1.z.literal('warning'),
1389
- });
1390
- const buildWorkflowAgentResumeSchema = zod_1.z.object({
1391
- approved: zod_1.z.boolean(),
1392
- });
1393
- function isPostPlanFollowUp(context) {
1394
- return context.isReplanFollowUp === true || context.isCheckpointFollowUp === true;
1395
- }
1396
- function isBuildViaPlanGuardEnabled() {
1397
- const raw = process.env.N8N_INSTANCE_AI_ENFORCE_BUILD_VIA_PLAN;
1398
- if (raw === undefined)
1399
- return true;
1400
- return raw.toLowerCase() !== 'false' && raw !== '0';
1401
- }
1402
- const PLAN_GUARD_REJECTION_LIMIT = 3;
1403
- async function resolveWorkflowNameForEditConfirmation(context, workflowId) {
1404
- try {
1405
- const workflow = await context.domainContext?.workflowService.get(workflowId);
1406
- const workflowName = workflow?.name?.trim();
1407
- return workflowName && workflowName.length > 0 ? workflowName : workflowId;
1408
- }
1409
- catch {
1410
- return workflowId;
1411
- }
1412
- }
1413
- function createBuildWorkflowAgentTool(context) {
1414
- let planGuardRejectionCount = 0;
1415
- const rejectPlanGuardCall = (result) => {
1416
- planGuardRejectionCount++;
1417
- if (planGuardRejectionCount >= PLAN_GUARD_REJECTION_LIMIT) {
1418
- context.logger.warn('build-workflow-with-agent plan-guard rejection limit reached — aborting run', {
1419
- threadId: context.threadId,
1420
- rejectionCount: planGuardRejectionCount,
1421
- });
1422
- throw new n8n_workflow_1.UserError('Stopped: the agent looped on `build-workflow-with-agent` rejections without correcting them. Try again or rephrase the request.');
1423
- }
1424
- return { result, taskId: '' };
1425
- };
1426
- return new agents_1.Tool('build-workflow-with-agent')
1427
- .description('Build or modify an n8n workflow using a specialized builder agent. ' +
1428
- 'The agent handles node discovery, schema lookups, code generation, and validation internally. ' +
1429
- 'For edits to an existing workflow, call directly with `bypassPlan: true`, the existing `workflowId`, and a one-sentence `reason` — the orchestrator runs a lightweight verify afterwards. ' +
1430
- 'For new workflows, multi-workflow builds, or data-table schema changes, go through `plan` — ' +
1431
- 'a runtime guard rejects direct calls without `bypassPlan: true` outside replan/checkpoint follow-ups, because those paths need the orchestrator-run checkpoint for end-to-end verification.')
1432
- .input(exports.buildWorkflowAgentInputSchema)
1433
- .output(zod_1.z.object({
1434
- result: zod_1.z.string(),
1435
- taskId: zod_1.z.string(),
1436
- }))
1437
- .suspend(buildWorkflowAgentSuspendSchema)
1438
- .resume(buildWorkflowAgentResumeSchema)
1439
- .handler(async (input, ctx) => {
1440
- const isPostPlanFollowUpRun = isPostPlanFollowUp(context);
1441
- if (isBuildViaPlanGuardEnabled() && !isPostPlanFollowUpRun) {
1442
- if (!input.bypassPlan) {
1443
- context.logger.warn('build-workflow-with-agent called outside plan/replan context — rejecting', {
1444
- threadId: context.threadId,
1445
- hasWorkflowId: Boolean(input.workflowId),
1446
- });
1447
- return rejectPlanGuardCall('STOP. Direct builder calls require `bypassPlan: true` + an existing ' +
1448
- '`workflowId` + a one-sentence `reason`. Use that combination for any edit to ' +
1449
- 'an existing workflow. For new workflows, multi-workflow builds, or data-table ' +
1450
- 'schema changes, call `plan` with a `build-workflow` task instead — the planner ' +
1451
- 'discovers credentials, data tables, and best practices, and schedules an ' +
1452
- 'orchestrator-run verification checkpoint.');
1453
- }
1454
- if (!input.workflowId) {
1455
- return rejectPlanGuardCall('STOP. `bypassPlan: true` is for edits to an EXISTING workflow and requires a ' +
1456
- '`workflowId`. New workflow builds must go through `plan` so an orchestrator-run ' +
1457
- 'verification checkpoint is scheduled. Call `plan` with a `build-workflow` task ' +
1458
- 'instead.');
1459
- }
1460
- if (!input.reason || input.reason.trim().length === 0) {
1461
- return rejectPlanGuardCall('STOP. `bypassPlan: true` requires a one-sentence `reason` describing the edit ' +
1462
- '(e.g. "swap Slack channel", "fix Code node shape issue").');
1463
- }
1464
- context.logger.warn('build-workflow-with-agent bypassing plan with bypassPlan=true', {
1465
- threadId: context.threadId,
1466
- workflowId: input.workflowId,
1467
- reason: input.reason,
1468
- });
1469
- }
1470
- planGuardRejectionCount = 0;
1471
- if (input.workflowId && !isPostPlanFollowUpRun && context.domainContext) {
1472
- const updateWorkflowPermission = context.domainContext.permissions?.updateWorkflow ?? 'require_approval';
1473
- if (updateWorkflowPermission === 'blocked') {
1474
- return { result: 'Action blocked by admin', taskId: '' };
1475
- }
1476
- const isOwnInFlightWorkflow = context.domainContext.aiCreatedWorkflowIds?.has(input.workflowId) ?? false;
1477
- if (!isOwnInFlightWorkflow) {
1478
- const resumeData = ctx.resumeData;
1479
- const needsApproval = updateWorkflowPermission !== 'always_allow';
1480
- if (needsApproval && (resumeData === undefined || resumeData === null)) {
1481
- const workflowName = await resolveWorkflowNameForEditConfirmation(context, input.workflowId);
1482
- return await ctx.suspend({
1483
- requestId: (0, nanoid_1.nanoid)(),
1484
- message: `Edit ${workflowName} (ID: ${input.workflowId})`,
1485
- severity: 'warning',
1486
- });
1487
- }
1488
- if (resumeData !== undefined && resumeData !== null && !resumeData.approved) {
1489
- return { result: 'User declined the workflow edit.', taskId: '' };
1490
- }
1491
- }
1492
- }
1493
- const result = await startBuildWorkflowAgentTask(context, input);
1494
- return { result: result.result, taskId: result.taskId };
1495
- })
1496
- .build();
1497
- }
1498
- //# sourceMappingURL=build-workflow-agent.tool.js.map