Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions packages/workflow-executor/src/errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,17 @@ export class AiInvokeTimeoutError extends WorkflowExecutorError {
}
}

// Wraps any AI-call failure (timeout, outage, malformed/missing tool call, out-of-range pick) so
// handlers degrade to the Manual path. Caught internally — never HTTP-mapped; not exported from index.
export class AiAssistUnavailableError extends WorkflowExecutorError {
readonly reason: unknown;

constructor(reason: unknown) {
super('AI assistance unavailable');
this.reason = reason;
}
}

export class NoMcpToolsError extends WorkflowExecutorError {
constructor(requestedMcpServerId: string) {
super(
Expand Down

Large diffs are not rendered by default.

5 changes: 4 additions & 1 deletion packages/workflow-executor/src/http/step-serializer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,12 @@ export default function serializeStepForWire(step: StepExecutionData): unknown {
return { ...step, selectedRecordRef: serializeRecordRef(step.selectedRecordRef) };

case 'load-related-record': {
// Omit selectedRecordRef when absent — serializing undefined throws.
const result: Record<string, unknown> = {
...step,
selectedRecordRef: serializeRecordRef(step.selectedRecordRef),
...(step.selectedRecordRef && {
selectedRecordRef: serializeRecordRef(step.selectedRecordRef),
}),
};

if (step.pendingData) {
Expand Down
6 changes: 5 additions & 1 deletion packages/workflow-executor/src/types/step-execution-data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -176,14 +176,18 @@ export interface LoadRelatedRecordPendingData {
availableRecordIds: LoadRelatedRecordCandidate[];
// Absent when the relation has no linked record(s): the list is empty and there's nothing to suggest.
suggestedRecord?: LoadRelatedRecordCandidate;
// The AI actively judged no candidate relevant (incl. Full AI degrading to confirmation) → the front
// pre-checks "No X to load". Distinct from a plain absent suggestedRecord (Manual: the user picks).
suggestNoRecord?: boolean;
}

export interface LoadRelatedRecordStepExecutionData
extends BaseStepExecutionData,
WithUserConfirmation<LoadRelatedRecordConfirmation> {
type: 'load-related-record';
pendingData?: LoadRelatedRecordPendingData;
selectedRecordRef: RecordRef;
// Set on every await/load path (and preserved through the user-initiated "continue without" skip).
selectedRecordRef?: RecordRef;
Comment thread
hercemer42 marked this conversation as resolved.
executionParams?: RelationRef;
executionResult?: { relation: RelationRef; record: RecordRef } | { skipped: true };
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,10 +98,10 @@ export type TriggerActionStepDefinition = z.infer<typeof TriggerActionStepDefini
export const LoadRelatedRecordStepDefinitionSchema = z.object({
...sharedFields,
type: z.literal(StepType.LoadRelatedRecord),
// No `.catch`: it would silently coerce `manual` to AutomatedWithConfirmation (AI prefill back on).
executionType: z
.enum([AutomatedWithConfirmation, FullyAutomated])
.default(AutomatedWithConfirmation)
.catch(AutomatedWithConfirmation),
.enum([Manual, AutomatedWithConfirmation, FullyAutomated])
Comment thread
hercemer42 marked this conversation as resolved.
.default(AutomatedWithConfirmation),
Comment thread
hercemer42 marked this conversation as resolved.
preRecordedArgs: z
.object({
/**
Expand Down
Loading
Loading