@forestadmin/workflow-executor 1.0.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.
- package/LICENSE +674 -0
- package/README.md +141 -0
- package/dist/adapters/activity-log-drainer.d.ts +6 -0
- package/dist/adapters/activity-log-drainer.js +21 -0
- package/dist/adapters/agent-client-agent-port.d.ts +27 -0
- package/dist/adapters/agent-client-agent-port.js +211 -0
- package/dist/adapters/ai-client-adapter.d.ts +11 -0
- package/dist/adapters/ai-client-adapter.js +38 -0
- package/dist/adapters/always-error-ai-model-port.d.ts +8 -0
- package/dist/adapters/always-error-ai-model-port.js +23 -0
- package/dist/adapters/console-logger.d.ts +7 -0
- package/dist/adapters/console-logger.js +15 -0
- package/dist/adapters/forest-server-workflow-port.d.ts +25 -0
- package/dist/adapters/forest-server-workflow-port.js +163 -0
- package/dist/adapters/forestadmin-client-activity-log-port-factory.d.ts +12 -0
- package/dist/adapters/forestadmin-client-activity-log-port-factory.js +22 -0
- package/dist/adapters/forestadmin-client-activity-log-port.d.ts +15 -0
- package/dist/adapters/forestadmin-client-activity-log-port.js +78 -0
- package/dist/adapters/pretty-logger.d.ts +9 -0
- package/dist/adapters/pretty-logger.js +37 -0
- package/dist/adapters/record-id-serializer.d.ts +4 -0
- package/dist/adapters/record-id-serializer.js +20 -0
- package/dist/adapters/run-to-available-step-mapper.d.ts +4 -0
- package/dist/adapters/run-to-available-step-mapper.js +137 -0
- package/dist/adapters/server-ai-adapter.d.ts +16 -0
- package/dist/adapters/server-ai-adapter.js +60 -0
- package/dist/adapters/server-types.d.ts +181 -0
- package/dist/adapters/server-types.js +35 -0
- package/dist/adapters/step-definition-mapper.d.ts +4 -0
- package/dist/adapters/step-definition-mapper.js +68 -0
- package/dist/adapters/step-outcome-to-update-step-mapper.d.ts +4 -0
- package/dist/adapters/step-outcome-to-update-step-mapper.js +34 -0
- package/dist/adapters/with-retry.d.ts +6 -0
- package/dist/adapters/with-retry.js +40 -0
- package/dist/build-workflow-executor.d.ts +35 -0
- package/dist/build-workflow-executor.js +175 -0
- package/dist/cli-core.d.ts +26 -0
- package/dist/cli-core.js +228 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.js +17 -0
- package/dist/defaults.d.ts +9 -0
- package/dist/defaults.js +12 -0
- package/dist/errors.d.ts +153 -0
- package/dist/errors.js +327 -0
- package/dist/executors/activity-log.d.ts +14 -0
- package/dist/executors/activity-log.js +33 -0
- package/dist/executors/agent-with-log.d.ts +33 -0
- package/dist/executors/agent-with-log.js +76 -0
- package/dist/executors/base-step-executor.d.ts +40 -0
- package/dist/executors/base-step-executor.js +267 -0
- package/dist/executors/condition-step-executor.d.ts +15 -0
- package/dist/executors/condition-step-executor.js +108 -0
- package/dist/executors/guidance-step-executor.d.ts +12 -0
- package/dist/executors/guidance-step-executor.js +39 -0
- package/dist/executors/load-related-record-step-executor.d.ts +38 -0
- package/dist/executors/load-related-record-step-executor.js +478 -0
- package/dist/executors/mcp-step-executor.d.ts +22 -0
- package/dist/executors/mcp-step-executor.js +188 -0
- package/dist/executors/read-record-step-executor.d.ts +10 -0
- package/dist/executors/read-record-step-executor.js +100 -0
- package/dist/executors/record-step-executor.d.ts +19 -0
- package/dist/executors/record-step-executor.js +108 -0
- package/dist/executors/step-executor-factory.d.ts +24 -0
- package/dist/executors/step-executor-factory.js +99 -0
- package/dist/executors/summary/step-execution-formatters.d.ts +8 -0
- package/dist/executors/summary/step-execution-formatters.js +49 -0
- package/dist/executors/summary/step-summary-builder.d.ts +7 -0
- package/dist/executors/summary/step-summary-builder.js +52 -0
- package/dist/executors/trigger-record-action-step-executor.d.ts +17 -0
- package/dist/executors/trigger-record-action-step-executor.js +169 -0
- package/dist/executors/update-record-step-executor.d.ts +13 -0
- package/dist/executors/update-record-step-executor.js +245 -0
- package/dist/http/executor-http-server.d.ts +25 -0
- package/dist/http/executor-http-server.js +170 -0
- package/dist/http/pending-data-validators.d.ts +25 -0
- package/dist/http/pending-data-validators.js +79 -0
- package/dist/http/step-serializer.d.ts +3 -0
- package/dist/http/step-serializer.js +47 -0
- package/dist/in-flight-run-registry.d.ts +9 -0
- package/dist/in-flight-run-registry.js +30 -0
- package/dist/index.d.ts +38 -0
- package/dist/index.js +88 -0
- package/dist/ports/activity-log-port.d.ts +24 -0
- package/dist/ports/activity-log-port.js +3 -0
- package/dist/ports/agent-port.d.ts +54 -0
- package/dist/ports/agent-port.js +3 -0
- package/dist/ports/ai-model-port.d.ts +7 -0
- package/dist/ports/ai-model-port.js +3 -0
- package/dist/ports/logger-port.d.ts +6 -0
- package/dist/ports/logger-port.js +3 -0
- package/dist/ports/run-store.d.ts +9 -0
- package/dist/ports/run-store.js +3 -0
- package/dist/ports/workflow-port.d.ts +30 -0
- package/dist/ports/workflow-port.js +3 -0
- package/dist/remote-tool-fetcher.d.ts +19 -0
- package/dist/remote-tool-fetcher.js +56 -0
- package/dist/runner.d.ts +50 -0
- package/dist/runner.js +317 -0
- package/dist/schema-cache.d.ts +11 -0
- package/dist/schema-cache.js +37 -0
- package/dist/schema-resolver.d.ts +11 -0
- package/dist/schema-resolver.js +24 -0
- package/dist/stores/build-run-store.d.ts +5 -0
- package/dist/stores/build-run-store.js +28 -0
- package/dist/stores/database-store.d.ts +17 -0
- package/dist/stores/database-store.js +119 -0
- package/dist/stores/in-memory-store.d.ts +11 -0
- package/dist/stores/in-memory-store.js +48 -0
- package/dist/types/execution-context.d.ts +37 -0
- package/dist/types/execution-context.js +3 -0
- package/dist/types/step-execution-data.d.ts +137 -0
- package/dist/types/step-execution-data.js +3 -0
- package/dist/types/validated/collection.d.ts +126 -0
- package/dist/types/validated/collection.js +96 -0
- package/dist/types/validated/execution.d.ts +362 -0
- package/dist/types/validated/execution.js +43 -0
- package/dist/types/validated/step-definition.d.ts +243 -0
- package/dist/types/validated/step-definition.js +128 -0
- package/dist/types/validated/step-outcome.d.ts +108 -0
- package/dist/types/validated/step-outcome.js +66 -0
- package/dist/validate-secrets.d.ts +5 -0
- package/dist/validate-secrets.js +14 -0
- package/package.json +50 -0
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const ai_proxy_1 = require("@forestadmin/ai-proxy");
|
|
7
|
+
const errors_1 = require("../errors");
|
|
8
|
+
const pending_data_validators_1 = __importDefault(require("../http/pending-data-validators"));
|
|
9
|
+
const step_summary_builder_1 = __importDefault(require("./summary/step-summary-builder"));
|
|
10
|
+
class BaseStepExecutor {
|
|
11
|
+
constructor(context) {
|
|
12
|
+
this.context = context;
|
|
13
|
+
}
|
|
14
|
+
async execute() {
|
|
15
|
+
const { baseRecordRef } = this.context;
|
|
16
|
+
this.context.logger.info('Step execution started', {
|
|
17
|
+
...this.logCtx,
|
|
18
|
+
collection: baseRecordRef.collectionName,
|
|
19
|
+
});
|
|
20
|
+
try {
|
|
21
|
+
// Idempotency guard — mutating executors override this. Runs before doExecute so a cache
|
|
22
|
+
// hit or uncertain-state error short-circuits before any side effect.
|
|
23
|
+
const cached = await this.checkIdempotency();
|
|
24
|
+
if (cached) {
|
|
25
|
+
this.context.logger.info('Step execution completed (replayed from cache)', {
|
|
26
|
+
...this.logCtx,
|
|
27
|
+
status: cached.stepOutcome.status,
|
|
28
|
+
});
|
|
29
|
+
return cached;
|
|
30
|
+
}
|
|
31
|
+
const result = await this.runWithTimeout();
|
|
32
|
+
this.context.logger.info('Step execution completed', {
|
|
33
|
+
...this.logCtx,
|
|
34
|
+
status: result.stepOutcome.status,
|
|
35
|
+
});
|
|
36
|
+
return result;
|
|
37
|
+
}
|
|
38
|
+
catch (error) {
|
|
39
|
+
if (error instanceof errors_1.StepTimeoutError) {
|
|
40
|
+
this.context.logger.error(error.message, {
|
|
41
|
+
...this.logCtx,
|
|
42
|
+
timeoutMs: this.context.stepTimeoutMs,
|
|
43
|
+
});
|
|
44
|
+
return this.buildOutcomeResult({ status: 'error', error: error.userMessage });
|
|
45
|
+
}
|
|
46
|
+
if (error instanceof errors_1.WorkflowExecutorError) {
|
|
47
|
+
this.context.logger.error(error.message, {
|
|
48
|
+
...this.logCtx,
|
|
49
|
+
cause: (0, errors_1.extractErrorMessage)(error.cause),
|
|
50
|
+
stack: error.cause instanceof Error ? error.cause.stack : undefined,
|
|
51
|
+
});
|
|
52
|
+
return this.buildOutcomeResult({ status: 'error', error: error.userMessage });
|
|
53
|
+
}
|
|
54
|
+
const { cause: errorCause } = error;
|
|
55
|
+
this.context.logger.error('Unexpected error during step execution', {
|
|
56
|
+
...this.logCtx,
|
|
57
|
+
error: (0, errors_1.extractErrorMessage)(error),
|
|
58
|
+
cause: (0, errors_1.extractErrorMessage)(errorCause),
|
|
59
|
+
stack: error instanceof Error ? error.stack : undefined,
|
|
60
|
+
});
|
|
61
|
+
return this.buildOutcomeResult({
|
|
62
|
+
status: 'error',
|
|
63
|
+
error: 'Unexpected error during step execution',
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
checkIdempotency() {
|
|
68
|
+
return Promise.resolve(null);
|
|
69
|
+
}
|
|
70
|
+
// Promise.race doesn't abort the losing branch — it keeps running in the background. The .catch()
|
|
71
|
+
// on execPromise must be attached BEFORE the race so a late rejection doesn't trigger
|
|
72
|
+
// UnhandledPromiseRejection. Late resolutions are silently discarded.
|
|
73
|
+
async runWithTimeout() {
|
|
74
|
+
const timeoutMs = this.context.stepTimeoutMs;
|
|
75
|
+
if (!timeoutMs || timeoutMs <= 0)
|
|
76
|
+
return this.doExecute();
|
|
77
|
+
let timer;
|
|
78
|
+
let hasTimeoutFired = false;
|
|
79
|
+
const execPromise = this.doExecute();
|
|
80
|
+
execPromise.catch(err => {
|
|
81
|
+
if (!hasTimeoutFired)
|
|
82
|
+
return;
|
|
83
|
+
this.context.logger.warn('Step work rejected after timeout — result discarded', {
|
|
84
|
+
...this.logCtx,
|
|
85
|
+
error: (0, errors_1.extractErrorMessage)(err),
|
|
86
|
+
});
|
|
87
|
+
});
|
|
88
|
+
try {
|
|
89
|
+
return await Promise.race([
|
|
90
|
+
execPromise,
|
|
91
|
+
new Promise((_, reject) => {
|
|
92
|
+
timer = setTimeout(() => {
|
|
93
|
+
hasTimeoutFired = true;
|
|
94
|
+
reject(new errors_1.StepTimeoutError(timeoutMs));
|
|
95
|
+
}, timeoutMs);
|
|
96
|
+
}),
|
|
97
|
+
]);
|
|
98
|
+
}
|
|
99
|
+
finally {
|
|
100
|
+
if (timer)
|
|
101
|
+
clearTimeout(timer);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
async findPendingExecution(type) {
|
|
105
|
+
const stepExecutions = await this.context.runStore.getStepExecutions(this.context.runId);
|
|
106
|
+
return stepExecutions.find((e) => e.type === type && e.stepIndex === this.context.stepIndex);
|
|
107
|
+
}
|
|
108
|
+
async patchAndReloadPendingData(pendingData) {
|
|
109
|
+
const { type } = this.context.stepDefinition;
|
|
110
|
+
const execution = await this.findPendingExecution(type);
|
|
111
|
+
if (!execution)
|
|
112
|
+
return undefined;
|
|
113
|
+
if (pendingData === undefined)
|
|
114
|
+
return execution;
|
|
115
|
+
const schema = pending_data_validators_1.default[execution.type];
|
|
116
|
+
if (!schema) {
|
|
117
|
+
throw new errors_1.StepStateError(`No pending-data validator registered for step type "${execution.type}"`);
|
|
118
|
+
}
|
|
119
|
+
const parsed = schema.safeParse(pendingData);
|
|
120
|
+
if (!parsed.success) {
|
|
121
|
+
throw new errors_1.StepStateError(`Invalid pending data: ${parsed.error.issues.map(i => i.message).join(', ')}`);
|
|
122
|
+
}
|
|
123
|
+
const userConfirmation = parsed.data;
|
|
124
|
+
const updated = {
|
|
125
|
+
...execution,
|
|
126
|
+
userConfirmation,
|
|
127
|
+
};
|
|
128
|
+
await this.context.runStore.saveStepExecution(this.context.runId, updated);
|
|
129
|
+
return updated;
|
|
130
|
+
}
|
|
131
|
+
// userConfirmed branches: undefined → re-emit awaiting-input (POST not yet called);
|
|
132
|
+
// false → save as skipped + success outcome; true → resolveAndExecute.
|
|
133
|
+
async handleConfirmationFlow(execution, resolveAndExecute) {
|
|
134
|
+
if (!execution.pendingData) {
|
|
135
|
+
throw new errors_1.StepStateError(`Step at index ${this.context.stepIndex} has no pending data`);
|
|
136
|
+
}
|
|
137
|
+
const { userConfirmed } = execution.userConfirmation ?? {};
|
|
138
|
+
if (userConfirmed === undefined) {
|
|
139
|
+
return this.buildOutcomeResult({ status: 'awaiting-input' });
|
|
140
|
+
}
|
|
141
|
+
if (!userConfirmed) {
|
|
142
|
+
await this.context.runStore.saveStepExecution(this.context.runId, {
|
|
143
|
+
...execution,
|
|
144
|
+
executionResult: { skipped: true },
|
|
145
|
+
});
|
|
146
|
+
return this.buildOutcomeResult({ status: 'success' });
|
|
147
|
+
}
|
|
148
|
+
return resolveAndExecute(execution);
|
|
149
|
+
}
|
|
150
|
+
buildContextMessage() {
|
|
151
|
+
const { user, stepDefinition } = this.context;
|
|
152
|
+
const now = new Date();
|
|
153
|
+
const lines = [
|
|
154
|
+
`Step executed by: ${user.firstName} ${user.lastName} (${user.email}, id: ${user.id})`,
|
|
155
|
+
`Role: ${user.role} | Team: ${user.team}`,
|
|
156
|
+
`Current date and time: ${now.toISOString()} (UTC)`,
|
|
157
|
+
];
|
|
158
|
+
// Fall back to the step title only when there is no prompt — the prompt, when present, is the
|
|
159
|
+
// authoritative intent (surfaced by each executor), so the title would just be noise.
|
|
160
|
+
if (!stepDefinition.prompt?.trim() && stepDefinition.title) {
|
|
161
|
+
lines.push(`Step title: "${stepDefinition.title}"`);
|
|
162
|
+
}
|
|
163
|
+
return new ai_proxy_1.SystemMessage(lines.join('\n'));
|
|
164
|
+
}
|
|
165
|
+
async buildPreviousStepsMessages() {
|
|
166
|
+
if (!this.context.previousSteps.length)
|
|
167
|
+
return [];
|
|
168
|
+
const allStepExecutions = await this.context.runStore.getStepExecutions(this.context.runId);
|
|
169
|
+
const summary = this.context.previousSteps
|
|
170
|
+
.map(step => {
|
|
171
|
+
const execution = this.resolveStepExecution(step, allStepExecutions);
|
|
172
|
+
return step_summary_builder_1.default.build(step.stepDefinition, step.stepOutcome, execution);
|
|
173
|
+
})
|
|
174
|
+
.join('\n\n');
|
|
175
|
+
return [new ai_proxy_1.SystemMessage(summary)];
|
|
176
|
+
}
|
|
177
|
+
// A step the executor ran has its execution at its own stepIndex. A revision clone never ran,
|
|
178
|
+
// so it inherits the record of the step it copied (originalStepIndex). Own-index-first is what
|
|
179
|
+
// stops a re-executed step (which has its own entry) from resurfacing the superseded
|
|
180
|
+
// original's record.
|
|
181
|
+
resolveStepExecution(step, executions) {
|
|
182
|
+
const own = executions.find(e => e.stepIndex === step.stepOutcome.stepIndex);
|
|
183
|
+
if (own)
|
|
184
|
+
return own;
|
|
185
|
+
// An errored clone persists nothing, so inheriting the copied record would resurface the
|
|
186
|
+
// superseded original's — only fall back when the clone didn't run-and-fail.
|
|
187
|
+
if (step.originalStepIndex !== undefined && step.stepOutcome.status !== 'error') {
|
|
188
|
+
return executions.find(e => e.stepIndex === step.originalStepIndex);
|
|
189
|
+
}
|
|
190
|
+
return undefined;
|
|
191
|
+
}
|
|
192
|
+
static mergeLeadingSystemMessages(messages) {
|
|
193
|
+
let i = 0;
|
|
194
|
+
while (i < messages.length && messages[i] instanceof ai_proxy_1.SystemMessage)
|
|
195
|
+
i += 1;
|
|
196
|
+
if (i <= 1)
|
|
197
|
+
return messages;
|
|
198
|
+
const merged = new ai_proxy_1.SystemMessage(messages
|
|
199
|
+
.slice(0, i)
|
|
200
|
+
.map(m => (typeof m.content === 'string' ? m.content : JSON.stringify(m.content)))
|
|
201
|
+
.filter(Boolean)
|
|
202
|
+
.join('\n\n'));
|
|
203
|
+
return [merged, ...messages.slice(i)];
|
|
204
|
+
}
|
|
205
|
+
static assertNoMidArraySystemMessages(messages) {
|
|
206
|
+
let seenNonSystem = false;
|
|
207
|
+
for (let i = 0; i < messages.length; i += 1) {
|
|
208
|
+
if (!(messages[i] instanceof ai_proxy_1.SystemMessage)) {
|
|
209
|
+
seenNonSystem = true;
|
|
210
|
+
}
|
|
211
|
+
else if (seenNonSystem) {
|
|
212
|
+
throw new errors_1.InvalidAiRequestError(`SystemMessage at position ${i} appears after a non-system message — move all system context to the front of the messages array.`);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
async invokeWithTools(messages, tools) {
|
|
217
|
+
BaseStepExecutor.assertNoMidArraySystemMessages(messages);
|
|
218
|
+
const modelWithTools = this.context.model.bindTools(tools, { tool_choice: 'any' });
|
|
219
|
+
const preparedMessages = BaseStepExecutor.mergeLeadingSystemMessages(messages);
|
|
220
|
+
const aiTimeoutMs = this.context.aiInvokeTimeoutMs;
|
|
221
|
+
const timeoutMs = aiTimeoutMs && aiTimeoutMs > 0 ? aiTimeoutMs : undefined;
|
|
222
|
+
const signal = timeoutMs ? AbortSignal.timeout(timeoutMs) : undefined;
|
|
223
|
+
let response;
|
|
224
|
+
try {
|
|
225
|
+
// `signal: undefined` is equivalent to passing no options — LangChain leaves the call un-timed.
|
|
226
|
+
response = await modelWithTools.invoke(preparedMessages, { signal });
|
|
227
|
+
}
|
|
228
|
+
catch (err) {
|
|
229
|
+
// Detect the timeout via our own signal, not the thrown error's name: providers wrap an
|
|
230
|
+
// aborted request differently (AbortError, TimeoutError, APIUserAbortError, …).
|
|
231
|
+
if (timeoutMs !== undefined && signal?.aborted)
|
|
232
|
+
throw new errors_1.AiInvokeTimeoutError(timeoutMs);
|
|
233
|
+
throw err;
|
|
234
|
+
}
|
|
235
|
+
const toolCall = response.tool_calls?.[0];
|
|
236
|
+
if (toolCall !== undefined) {
|
|
237
|
+
if (toolCall.args !== undefined && toolCall.args !== null) {
|
|
238
|
+
return { toolName: toolCall.name, args: toolCall.args };
|
|
239
|
+
}
|
|
240
|
+
throw new errors_1.MalformedToolCallError(toolCall.name ?? 'unknown', 'args field is missing or null');
|
|
241
|
+
}
|
|
242
|
+
const invalidCall = response.invalid_tool_calls?.[0];
|
|
243
|
+
if (invalidCall) {
|
|
244
|
+
throw new errors_1.MalformedToolCallError(invalidCall.name ?? 'unknown', invalidCall.error ?? 'no details available');
|
|
245
|
+
}
|
|
246
|
+
throw new errors_1.MissingToolCallError();
|
|
247
|
+
}
|
|
248
|
+
async invokeWithTool(messages, tool) {
|
|
249
|
+
return (await this.invokeWithTools(messages, [tool])).args;
|
|
250
|
+
}
|
|
251
|
+
// Overridden by executors that carry type-specific log identifiers (e.g. McpStepExecutor).
|
|
252
|
+
getExtraLogContext() {
|
|
253
|
+
return {};
|
|
254
|
+
}
|
|
255
|
+
get logCtx() {
|
|
256
|
+
const { runId, stepId, stepIndex, stepDefinition } = this.context;
|
|
257
|
+
return {
|
|
258
|
+
runId,
|
|
259
|
+
stepId,
|
|
260
|
+
stepIndex,
|
|
261
|
+
stepType: stepDefinition.type,
|
|
262
|
+
...this.getExtraLogContext(),
|
|
263
|
+
};
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
exports.default = BaseStepExecutor;
|
|
267
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYmFzZS1zdGVwLWV4ZWN1dG9yLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2V4ZWN1dG9ycy9iYXNlLXN0ZXAtZXhlY3V0b3IudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7QUFlQSxvREFBc0Q7QUFFdEQsc0NBU21CO0FBQ25CLDhGQUErRDtBQUMvRCwwRkFBZ0U7QUFFaEUsTUFBOEIsZ0JBQWdCO0lBSzVDLFlBQVksT0FBZ0M7UUFDMUMsSUFBSSxDQUFDLE9BQU8sR0FBRyxPQUFPLENBQUM7SUFDekIsQ0FBQztJQUVELEtBQUssQ0FBQyxPQUFPO1FBQ1gsTUFBTSxFQUFFLGFBQWEsRUFBRSxHQUFHLElBQUksQ0FBQyxPQUFPLENBQUM7UUFFdkMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLHdCQUF3QixFQUFFO1lBQ2pELEdBQUcsSUFBSSxDQUFDLE1BQU07WUFDZCxVQUFVLEVBQUUsYUFBYSxDQUFDLGNBQWM7U0FDekMsQ0FBQyxDQUFDO1FBRUgsSUFBSSxDQUFDO1lBQ0gseUZBQXlGO1lBQ3pGLHNFQUFzRTtZQUN0RSxNQUFNLE1BQU0sR0FBRyxNQUFNLElBQUksQ0FBQyxnQkFBZ0IsRUFBRSxDQUFDO1lBRTdDLElBQUksTUFBTSxFQUFFLENBQUM7Z0JBQ1gsSUFBSSxDQUFDLE9BQU8sQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLGdEQUFnRCxFQUFFO29CQUN6RSxHQUFHLElBQUksQ0FBQyxNQUFNO29CQUNkLE1BQU0sRUFBRSxNQUFNLENBQUMsV0FBVyxDQUFDLE1BQU07aUJBQ2xDLENBQUMsQ0FBQztnQkFFSCxPQUFPLE1BQU0sQ0FBQztZQUNoQixDQUFDO1lBRUQsTUFBTSxNQUFNLEdBQUcsTUFBTSxJQUFJLENBQUMsY0FBYyxFQUFFLENBQUM7WUFFM0MsSUFBSSxDQUFDLE9BQU8sQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLDBCQUEwQixFQUFFO2dCQUNuRCxHQUFHLElBQUksQ0FB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
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { StepExecutionResult } from '../types/execution-context';
|
|
2
|
+
import type { ConditionStepDefinition } from '../types/validated/step-definition';
|
|
3
|
+
import type { ConditionStepOutcome } from '../types/validated/step-outcome';
|
|
4
|
+
import BaseStepExecutor from './base-step-executor';
|
|
5
|
+
export default class ConditionStepExecutor extends BaseStepExecutor<ConditionStepDefinition> {
|
|
6
|
+
protected buildOutcomeResult(outcome: {
|
|
7
|
+
status: ConditionStepOutcome['status'];
|
|
8
|
+
error?: string;
|
|
9
|
+
selectedOption?: string;
|
|
10
|
+
}): StepExecutionResult;
|
|
11
|
+
protected doExecute(): Promise<StepExecutionResult>;
|
|
12
|
+
private readUserChoice;
|
|
13
|
+
private askAi;
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=condition-step-executor.d.ts.map
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const ai_proxy_1 = require("@forestadmin/ai-proxy");
|
|
7
|
+
const zod_1 = require("zod");
|
|
8
|
+
const errors_1 = require("../errors");
|
|
9
|
+
const base_step_executor_1 = __importDefault(require("./base-step-executor"));
|
|
10
|
+
const pending_data_validators_1 = __importDefault(require("../http/pending-data-validators"));
|
|
11
|
+
const step_definition_1 = require("../types/validated/step-definition");
|
|
12
|
+
const GATEWAY_SYSTEM_PROMPT = `You are an AI agent selecting the correct option for a workflow gateway decision.
|
|
13
|
+
|
|
14
|
+
**Task**: Analyze the question and available options, then select the option that DIRECTLY answers the question. Options must be literal answers, not interpretations.
|
|
15
|
+
|
|
16
|
+
**Critical Rule**: Options must semantically match possible answers to the question.
|
|
17
|
+
- Question "Does X contain Y?" expects options like "yes"/"no", NOT colors or unrelated values
|
|
18
|
+
- Question "What is the status?" expects options like "active"/"inactive", NOT arbitrary words
|
|
19
|
+
- If options don't match expected answer types, select null
|
|
20
|
+
|
|
21
|
+
**NEVER invent mappings** between options and answers (e.g., never assume "purple"="no" or "red"="yes")
|
|
22
|
+
|
|
23
|
+
**When to select null**:
|
|
24
|
+
- Options are semantically unrelated to the question type (colors for yes/no questions)
|
|
25
|
+
- None of the options literally match the expected answer
|
|
26
|
+
- The question is ambiguous or lacks necessary context
|
|
27
|
+
- You are less than 80% confident in any option
|
|
28
|
+
|
|
29
|
+
**Reasoning format**:
|
|
30
|
+
- State which option you selected and why
|
|
31
|
+
- If selecting null: explain why options don't match the question
|
|
32
|
+
- Do not refer to yourself as "I" in the response, use a passive formulation instead.`;
|
|
33
|
+
class ConditionStepExecutor extends base_step_executor_1.default {
|
|
34
|
+
buildOutcomeResult(outcome) {
|
|
35
|
+
return {
|
|
36
|
+
stepOutcome: {
|
|
37
|
+
type: 'condition',
|
|
38
|
+
stepId: this.context.stepId,
|
|
39
|
+
stepIndex: this.context.stepIndex,
|
|
40
|
+
...outcome,
|
|
41
|
+
},
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
async doExecute() {
|
|
45
|
+
const { stepDefinition: step, incomingPendingData } = this.context;
|
|
46
|
+
// Manual mode: the user picks the option from the frontend. Wait for their input
|
|
47
|
+
// without ever calling the AI.
|
|
48
|
+
const isManual = step.executionType === step_definition_1.StepExecutionMode.Manual;
|
|
49
|
+
if (isManual && incomingPendingData === undefined) {
|
|
50
|
+
return this.buildOutcomeResult({ status: 'awaiting-input' });
|
|
51
|
+
}
|
|
52
|
+
const { selectedOption, reasoning } = incomingPendingData !== undefined
|
|
53
|
+
? this.readUserChoice(step, incomingPendingData)
|
|
54
|
+
: await this.askAi(step);
|
|
55
|
+
await this.context.runStore.saveStepExecution(this.context.runId, {
|
|
56
|
+
type: 'condition',
|
|
57
|
+
stepIndex: this.context.stepIndex,
|
|
58
|
+
executionParams: { answer: selectedOption, reasoning },
|
|
59
|
+
executionResult: selectedOption ? { answer: selectedOption } : undefined,
|
|
60
|
+
});
|
|
61
|
+
if (!selectedOption) {
|
|
62
|
+
return this.buildOutcomeResult({
|
|
63
|
+
status: 'error',
|
|
64
|
+
error: "The AI couldn't decide. Try rephrasing the step's prompt.",
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
return this.buildOutcomeResult({ status: 'success', selectedOption });
|
|
68
|
+
}
|
|
69
|
+
readUserChoice(step, incomingPendingData) {
|
|
70
|
+
const parsed = pending_data_validators_1.default.condition.safeParse(incomingPendingData);
|
|
71
|
+
if (!parsed.success) {
|
|
72
|
+
throw new errors_1.StepStateError(`Invalid condition input: ${parsed.error.issues.map(i => i.message).join(', ')}`);
|
|
73
|
+
}
|
|
74
|
+
const { selectedOption } = parsed.data;
|
|
75
|
+
if (!step.options.includes(selectedOption)) {
|
|
76
|
+
const allowed = step.options.join(', ');
|
|
77
|
+
throw new errors_1.StepStateError(`Option "${selectedOption}" is not a valid choice (expected one of: ${allowed})`);
|
|
78
|
+
}
|
|
79
|
+
return { selectedOption, reasoning: 'Selected by user' };
|
|
80
|
+
}
|
|
81
|
+
async askAi(step) {
|
|
82
|
+
const tool = new ai_proxy_1.DynamicStructuredTool({
|
|
83
|
+
name: 'choose-gateway-option',
|
|
84
|
+
description: 'Select the option that answers the question. ' +
|
|
85
|
+
'Use null if no option matches or you are uncertain. ' +
|
|
86
|
+
'Explain your reasoning.',
|
|
87
|
+
schema: zod_1.z.object({
|
|
88
|
+
reasoning: zod_1.z.string().describe('The reasoning behind the choice'),
|
|
89
|
+
question: zod_1.z.string().describe('The question to answer by choosing an option'),
|
|
90
|
+
option: zod_1.z
|
|
91
|
+
.enum(step.options)
|
|
92
|
+
.nullable()
|
|
93
|
+
.describe('The chosen option, or null if no option clearly answers the question.'),
|
|
94
|
+
}),
|
|
95
|
+
func: undefined,
|
|
96
|
+
});
|
|
97
|
+
const messages = [
|
|
98
|
+
this.buildContextMessage(),
|
|
99
|
+
...(await this.buildPreviousStepsMessages()),
|
|
100
|
+
new ai_proxy_1.SystemMessage(GATEWAY_SYSTEM_PROMPT),
|
|
101
|
+
new ai_proxy_1.HumanMessage(`**Question**: ${step.prompt ?? 'Choose the most appropriate option.'}`),
|
|
102
|
+
];
|
|
103
|
+
const args = await this.invokeWithTool(messages, tool);
|
|
104
|
+
return { selectedOption: args.option, reasoning: args.reasoning };
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
exports.default = ConditionStepExecutor;
|
|
108
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29uZGl0aW9uLXN0ZXAtZXhlY3V0b3IuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvZXhlY3V0b3JzL2NvbmRpdGlvbi1zdGVwLWV4ZWN1dG9yLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7O0FBSUEsb0RBQTJGO0FBQzNGLDZCQUF3QjtBQUV4QixzQ0FBMkM7QUFDM0MsOEVBQW9EO0FBQ3BELDhGQUErRDtBQUMvRCx3RUFBdUU7QUFhdkUsTUFBTSxxQkFBcUIsR0FBRzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7c0ZBb0J3RCxDQUFDO0FBRXZGLE1BQXFCLHFCQUFzQixTQUFRLDRCQUF5QztJQUNoRixrQkFBa0IsQ0FBQyxPQUk1QjtRQUNDLE9BQU87WUFDTCxXQUFXLEVBQUU7Z0JBQ1gsSUFBSSxFQUFFLFdBQVc7Z0JBQ2pCLE1BQU0sRUFBRSxJQUFJLENBQUMsT0FBTyxDQUFDLE1BQU07Z0JBQzNCLFNBQVMsRUFBRSxJQUFJLENBQUMsT0FBTyxDQUFDLFNBQVM7Z0JBQ2pDLEdBQUcsT0FBTzthQUNYO1NBQ0YsQ0FBQztJQUNKLENBQUM7SUFFUyxLQUFLLENBQUMsU0FBUztRQUN2QixNQUFNLEVBQUUsY0FBYyxFQUFFLElBQUksRUFBRSxtQkFBbUIsRUFBRSxHQUFHLElBQUksQ0FBQyxPQUFPLENBQUM7UUFFbkUsaUZBQWlGO1FBQ2pGLCtCQUErQjtRQUMvQixNQUFNLFFBQVEsR0FBRyxJQUFJLENBQUMsYUFBYSxLQUFLLG1DQUFpQixDQUFDLE1BQU0sQ0FBQztRQUVqRSxJQUFJLFFBQVEsSUFBSSxtQkFBbUIsS0FBSyxTQUFTLEVBQUUsQ0FBQztZQUNsRCxPQUFPLElBQUksQ0FBQyxrQkFBa0IsQ0FBQyxFQUFFLE1BQU0sRUFBRSxnQkFBZ0IsRUFBRSxDQUFDLENBQUM7UUFDL0QsQ0FBQztRQUVELE1BQU0sRUFBRSxjQUFjLEVBQUUsU0FBUyxFQUFFLEdBQ2pDLG1CQUFtQixLQUFLLFNBQVM7WUFDL0IsQ0FBQyxDQUFDLElB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
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { StepExecutionResult } from '../types/execution-context';
|
|
2
|
+
import type { GuidanceStepDefinition } from '../types/validated/step-definition';
|
|
3
|
+
import type { RecordStepStatus } from '../types/validated/step-outcome';
|
|
4
|
+
import BaseStepExecutor from './base-step-executor';
|
|
5
|
+
export default class GuidanceStepExecutor extends BaseStepExecutor<GuidanceStepDefinition> {
|
|
6
|
+
protected doExecute(): Promise<StepExecutionResult>;
|
|
7
|
+
protected buildOutcomeResult(outcome: {
|
|
8
|
+
status: RecordStepStatus;
|
|
9
|
+
error?: string;
|
|
10
|
+
}): StepExecutionResult;
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=guidance-step-executor.d.ts.map
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const errors_1 = require("../errors");
|
|
7
|
+
const base_step_executor_1 = __importDefault(require("./base-step-executor"));
|
|
8
|
+
const pending_data_validators_1 = __importDefault(require("../http/pending-data-validators"));
|
|
9
|
+
class GuidanceStepExecutor extends base_step_executor_1.default {
|
|
10
|
+
async doExecute() {
|
|
11
|
+
const { incomingPendingData } = this.context;
|
|
12
|
+
if (!incomingPendingData) {
|
|
13
|
+
return this.buildOutcomeResult({ status: 'awaiting-input' });
|
|
14
|
+
}
|
|
15
|
+
const parsed = pending_data_validators_1.default.guidance.safeParse(incomingPendingData);
|
|
16
|
+
if (!parsed.success) {
|
|
17
|
+
throw new errors_1.StepStateError(`Invalid guidance input: ${parsed.error.issues.map(i => i.message).join(', ')}`);
|
|
18
|
+
}
|
|
19
|
+
const { userInput } = parsed.data;
|
|
20
|
+
await this.context.runStore.saveStepExecution(this.context.runId, {
|
|
21
|
+
type: 'guidance',
|
|
22
|
+
stepIndex: this.context.stepIndex,
|
|
23
|
+
executionResult: { userInput: userInput ?? '' },
|
|
24
|
+
});
|
|
25
|
+
return this.buildOutcomeResult({ status: 'success' });
|
|
26
|
+
}
|
|
27
|
+
buildOutcomeResult(outcome) {
|
|
28
|
+
return {
|
|
29
|
+
stepOutcome: {
|
|
30
|
+
type: 'guidance',
|
|
31
|
+
stepId: this.context.stepId,
|
|
32
|
+
stepIndex: this.context.stepIndex,
|
|
33
|
+
...outcome,
|
|
34
|
+
},
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
exports.default = GuidanceStepExecutor;
|
|
39
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZ3VpZGFuY2Utc3RlcC1leGVjdXRvci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9leGVjdXRvcnMvZ3VpZGFuY2Utc3RlcC1leGVjdXRvci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7OztBQUlBLHNDQUEyQztBQUMzQyw4RUFBb0Q7QUFDcEQsOEZBQStEO0FBRS9ELE1BQXFCLG9CQUFxQixTQUFRLDRCQUF3QztJQUM5RSxLQUFLLENBQUMsU0FBUztRQUN2QixNQUFNLEVBQUUsbUJBQW1CLEVBQUUsR0FBRyxJQUFJLENBQUMsT0FBTyxDQUFDO1FBRTdDLElBQUksQ0FBQyxtQkFBbUIsRUFBRSxDQUFDO1lBQ3pCLE9BQU8sSUFBSSxDQUFDLGtCQUFrQixDQUFDLEVBQUUsTUFBTSxFQUFFLGdCQUFnQixFQUFFLENBQUMsQ0FBQztRQUMvRCxDQUFDO1FBRUQsTUFBTSxNQUFNLEdBQUcsaUNBQWdCLENBQUMsUUFBUSxDQUFDLFNBQVMsQ0FBQyxtQkFBbUIsQ0FBQyxDQUFDO1FBRXhFLElBQUksQ0FBQyxNQUFNLENBQUMsT0FBTyxFQUFFLENBQUM7WUFDcEIsTUFBTSxJQUFJLHVCQUFjLENBQ3RCLDJCQUEyQixNQUFNLENBQUMsS0FBSyxDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsT0FBTyxDQUFDLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxFQUFFLENBQ2hGLENBQUM7UUFDSixDQUFDO1FBRUQsTUFBTSxFQUFFLFNBQVMsRUFBRSxHQUFHLE1BQU0sQ0FBQyxJQUE4QixDQUFDO1FBRTVELE1BQU0sSUFBSSxDQUFDLE9BQU8sQ0FBQyxRQUFRLENBQUMsaUJBQWlCLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxLQUFLLEVBQUU7WUFDaEUsSUFBSSxFQUFFLFVBQVU7WUFDaEIsU0FBUyxFQUFFLElBQUksQ0FBQyxPQUFPLENBQUMsU0FBUztZQUNqQyxlQUFlLEVBQUUsRUFBRSxTQUFTLEVBQUUsU0FBUyxJQUFJLEVBQUUsRUFBRTtTQUNoRCxDQUFDLENBQUM7UUFFSCxPQUFPLElBQUksQ0FBQyxrQkFBa0IsQ0FBQyxFQUFFLE1BQU0sRUFBRSxTQUFTLEVBQUUsQ0FBQyxDQUFDO0lBQ3hELENBQUM7SUFFUyxrQkFBa0IsQ0FBQyxPQUc1QjtRQUNDLE9BQU87WUFDTCxXQUFXLEVBQUU7Z0JBQ1gsSUFBSSxFQUFFLFVBQVU7Z0JBQ2hCLE1BQU0sRUFBRSxJQUFJLENBQUMsT0FBTyxDQUFDLE1BQU07Z0JBQzNCLFNBQVMsRUFBRSxJQUFJLENBQUMsT0FBTyxDQUFDLFNBQVM7Z0JBQ2pDLEdBQUcsT0FBTzthQUNYO1NBQ0YsQ0FBQztJQUNKLENBQUM7Q0FDRjtBQXhDRCx1Q0F3Q0MifQ==
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { StepExecutionResult } from '../types/execution-context';
|
|
2
|
+
import type { LoadRelatedRecordStepDefinition } from '../types/validated/step-definition';
|
|
3
|
+
import RecordStepExecutor from './record-step-executor';
|
|
4
|
+
export default class LoadRelatedRecordStepExecutor extends RecordStepExecutor<LoadRelatedRecordStepDefinition> {
|
|
5
|
+
protected doExecute(): Promise<StepExecutionResult>;
|
|
6
|
+
private refreshCandidatesForField;
|
|
7
|
+
private handleFirstCall;
|
|
8
|
+
private resolveTarget;
|
|
9
|
+
private targetFromCandidate;
|
|
10
|
+
private requireRecordAtStepIndex;
|
|
11
|
+
private buildRelationCandidates;
|
|
12
|
+
private buildTarget;
|
|
13
|
+
private saveAndAwaitInput;
|
|
14
|
+
private collectCandidateIds;
|
|
15
|
+
private extractReferenceFieldValue;
|
|
16
|
+
/** Branch B: fully automated. xToOne loads the linked record; HasMany ranks candidates via AI; BelongsToMany takes the first. */
|
|
17
|
+
private resolveAndLoadAutomatic;
|
|
18
|
+
private fetchRecordForRelation;
|
|
19
|
+
private fetchXToOneRecordRef;
|
|
20
|
+
private fetchXToOneCandidate;
|
|
21
|
+
private resolveFromSelection;
|
|
22
|
+
private selectBestFromRelatedData;
|
|
23
|
+
/** HasMany + fully automated execution: fetch top 50, then AI calls to select the best record. */
|
|
24
|
+
private selectBestRelatedRecord;
|
|
25
|
+
private fetchFirstCandidate;
|
|
26
|
+
private fetchCandidates;
|
|
27
|
+
private fetchRelatedData;
|
|
28
|
+
/** Persists the loaded record ref and returns a success outcome. */
|
|
29
|
+
private persistAndReturn;
|
|
30
|
+
private relationOptionLabel;
|
|
31
|
+
private selectRelationToFollow;
|
|
32
|
+
/** AI call 1 for HasMany: selects the most relevant fields to compare candidates. */
|
|
33
|
+
private selectRelevantFields;
|
|
34
|
+
/** AI call 2 for HasMany: selects the best record by index from the candidate list. */
|
|
35
|
+
private selectBestRecordIndex;
|
|
36
|
+
private toRecordRef;
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=load-related-record-step-executor.d.ts.map
|