@pixelbyte-software/pixcode 1.42.1 → 1.42.2

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 (20) hide show
  1. package/dist/assets/{index-C97kIvXz.js → index-CMeiCqQf.js} +182 -182
  2. package/dist/index.html +1 -1
  3. package/dist-server/server/modules/orchestration/workflows/workflow-fallback-policy.js +114 -0
  4. package/dist-server/server/modules/orchestration/workflows/workflow-fallback-policy.js.map +1 -0
  5. package/dist-server/server/modules/orchestration/workflows/workflow-replay.js +177 -0
  6. package/dist-server/server/modules/orchestration/workflows/workflow-replay.js.map +1 -0
  7. package/dist-server/server/modules/orchestration/workflows/workflow-runner.js +47 -7
  8. package/dist-server/server/modules/orchestration/workflows/workflow-runner.js.map +1 -1
  9. package/dist-server/server/modules/orchestration/workflows/workflow-trace.js +74 -0
  10. package/dist-server/server/modules/orchestration/workflows/workflow-trace.js.map +1 -1
  11. package/dist-server/server/modules/orchestration/workflows/workflow.routes.js +88 -0
  12. package/dist-server/server/modules/orchestration/workflows/workflow.routes.js.map +1 -1
  13. package/package.json +1 -1
  14. package/scripts/smoke/workflow-fallback-replay.mjs +56 -0
  15. package/server/modules/orchestration/workflows/workflow-fallback-policy.ts +161 -0
  16. package/server/modules/orchestration/workflows/workflow-replay.ts +254 -0
  17. package/server/modules/orchestration/workflows/workflow-runner.ts +105 -6
  18. package/server/modules/orchestration/workflows/workflow-trace.ts +76 -0
  19. package/server/modules/orchestration/workflows/workflow.routes.ts +107 -0
  20. package/server/modules/orchestration/workflows/workflow.types.ts +5 -0
package/dist/index.html CHANGED
@@ -35,7 +35,7 @@
35
35
 
36
36
  <!-- Prevent zoom on iOS -->
37
37
  <meta name="format-detection" content="telephone=no" />
38
- <script type="module" crossorigin src="/assets/index-C97kIvXz.js"></script>
38
+ <script type="module" crossorigin src="/assets/index-CMeiCqQf.js"></script>
39
39
  <link rel="modulepreload" crossorigin href="/assets/vendor-react-D7WwDXvu.js">
40
40
  <link rel="modulepreload" crossorigin href="/assets/vendor-codemirror-CzYAOTxS.js">
41
41
  <link rel="modulepreload" crossorigin href="/assets/vendor-xterm-CJZjLICi.js">
@@ -0,0 +1,114 @@
1
+ export const PIXCODE_FALLBACK_POLICY_PROTOCOL = 'pixcode.fallback-policy.v1';
2
+ const DEFAULT_TRIGGERS = [
3
+ 'provider_failure',
4
+ 'timeout',
5
+ 'tool_failure',
6
+ 'invalid_output',
7
+ ];
8
+ export const DEFAULT_WORKFLOW_FALLBACK_POLICY = {
9
+ protocol: PIXCODE_FALLBACK_POLICY_PROTOCOL,
10
+ enabled: true,
11
+ triggers: DEFAULT_TRIGGERS,
12
+ maxFallbacksPerRun: 3,
13
+ requireDifferentAgent: true,
14
+ };
15
+ function readRecord(value) {
16
+ return value && typeof value === 'object' ? value : undefined;
17
+ }
18
+ function readBoolean(value) {
19
+ return typeof value === 'boolean' ? value : undefined;
20
+ }
21
+ function readNumber(value) {
22
+ return typeof value === 'number' && Number.isFinite(value) ? value : undefined;
23
+ }
24
+ function isWorkflowFallbackTrigger(value) {
25
+ return value === 'provider_failure'
26
+ || value === 'timeout'
27
+ || value === 'tool_failure'
28
+ || value === 'invalid_output';
29
+ }
30
+ function readFallbackTriggers(value) {
31
+ if (!Array.isArray(value))
32
+ return undefined;
33
+ const triggers = value.filter(isWorkflowFallbackTrigger);
34
+ return triggers.length > 0 ? [...new Set(triggers)] : undefined;
35
+ }
36
+ export function readWorkflowFallbackPolicy(metadata) {
37
+ const settings = readRecord(metadata?.settings) ?? {};
38
+ const configured = readRecord(settings.fallbackPolicy) ?? {};
39
+ const maxFallbacksPerRun = readNumber(configured.maxFallbacksPerRun);
40
+ return {
41
+ protocol: PIXCODE_FALLBACK_POLICY_PROTOCOL,
42
+ enabled: readBoolean(configured.enabled) ?? DEFAULT_WORKFLOW_FALLBACK_POLICY.enabled,
43
+ triggers: readFallbackTriggers(configured.triggers) ?? DEFAULT_WORKFLOW_FALLBACK_POLICY.triggers,
44
+ maxFallbacksPerRun: maxFallbacksPerRun === undefined
45
+ ? DEFAULT_WORKFLOW_FALLBACK_POLICY.maxFallbacksPerRun
46
+ : Math.max(0, Math.min(8, Math.round(maxFallbacksPerRun))),
47
+ requireDifferentAgent: readBoolean(configured.requireDifferentAgent)
48
+ ?? DEFAULT_WORKFLOW_FALLBACK_POLICY.requireDifferentAgent,
49
+ };
50
+ }
51
+ export function classifyWorkflowFailure(reason, explicitTrigger) {
52
+ if (explicitTrigger)
53
+ return explicitTrigger;
54
+ const text = reason.toLocaleLowerCase('en');
55
+ if (/timed out|timeout|deadline/u.test(text))
56
+ return 'timeout';
57
+ if (/invalid (handoff|output|artifact|json|schema)|parse|protocol/u.test(text))
58
+ return 'invalid_output';
59
+ if (/tool|command|shell|exit code|permission|file write|write failed|network|fetch|curl|wget|gh |npm |git /u
60
+ .test(text)) {
61
+ return 'tool_failure';
62
+ }
63
+ return 'provider_failure';
64
+ }
65
+ function fallbackEventCount(run) {
66
+ return Array.isArray(run.metadata?.fallbackEvents) ? run.metadata.fallbackEvents.length : 0;
67
+ }
68
+ export function resolveWorkflowFallbackDecision({ run, node, reason, trigger, fallbackAgentInstanceId, }) {
69
+ const fallbackTrigger = classifyWorkflowFailure(reason, trigger);
70
+ const policy = readWorkflowFallbackPolicy(run.metadata);
71
+ if (!policy.enabled) {
72
+ return {
73
+ shouldFallback: false,
74
+ trigger: fallbackTrigger,
75
+ reason,
76
+ policy,
77
+ skippedReason: 'Fallback policy is disabled.',
78
+ };
79
+ }
80
+ if (!policy.triggers.includes(fallbackTrigger)) {
81
+ return {
82
+ shouldFallback: false,
83
+ trigger: fallbackTrigger,
84
+ reason,
85
+ policy,
86
+ skippedReason: `Fallback trigger ${fallbackTrigger} is not enabled.`,
87
+ };
88
+ }
89
+ if (fallbackEventCount(run) >= policy.maxFallbacksPerRun) {
90
+ return {
91
+ shouldFallback: false,
92
+ trigger: fallbackTrigger,
93
+ reason,
94
+ policy,
95
+ skippedReason: `Fallback limit ${policy.maxFallbacksPerRun} reached.`,
96
+ };
97
+ }
98
+ if (policy.requireDifferentAgent && fallbackAgentInstanceId && fallbackAgentInstanceId === node.agentInstanceId) {
99
+ return {
100
+ shouldFallback: false,
101
+ trigger: fallbackTrigger,
102
+ reason,
103
+ policy,
104
+ skippedReason: 'Fallback agent must be different from the failed agent.',
105
+ };
106
+ }
107
+ return {
108
+ shouldFallback: true,
109
+ trigger: fallbackTrigger,
110
+ reason,
111
+ policy,
112
+ };
113
+ }
114
+ //# sourceMappingURL=workflow-fallback-policy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workflow-fallback-policy.js","sourceRoot":"","sources":["../../../../../server/modules/orchestration/workflows/workflow-fallback-policy.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,177 @@
1
+ import { redactTraceText } from '../../../modules/orchestration/workflows/workflow-trace.js';
2
+ export const PIXCODE_REPLAY_PROTOCOL = 'pixcode.workflow-replay.v1';
3
+ function safeNodeId(value) {
4
+ return value.replace(/[^a-zA-Z0-9_]+/g, '_').slice(0, 48) || 'node';
5
+ }
6
+ function readRecord(value) {
7
+ return value && typeof value === 'object' ? value : undefined;
8
+ }
9
+ function visibleNodes(run) {
10
+ return run.nodeRuns.filter((node) => !node.internal);
11
+ }
12
+ function defaultReplayNode(run) {
13
+ return visibleNodes(run).find((node) => node.status === 'failed')
14
+ ?? [...visibleNodes(run)].reverse().find((node) => node.status !== 'skipped')
15
+ ?? visibleNodes(run)[0];
16
+ }
17
+ function selectReplayNodes(run, scope, fromNodeId) {
18
+ const nodes = visibleNodes(run);
19
+ if (scope === 'run')
20
+ return nodes;
21
+ const requested = fromNodeId
22
+ ? nodes.find((node) => node.nodeId === fromNodeId)
23
+ : defaultReplayNode(run);
24
+ return requested ? [requested] : [];
25
+ }
26
+ function compact(value, run, maxLength = 1_200) {
27
+ return redactTraceText(value, run, maxLength);
28
+ }
29
+ function nodeTraceSummary(run, node) {
30
+ const artifactTypes = (node.artifacts ?? []).map((artifact) => artifact.type).filter(Boolean);
31
+ return [
32
+ `Step: ${node.agentLabel || node.nodeId}`,
33
+ `Node id: ${node.nodeId}`,
34
+ `Status: ${node.status}`,
35
+ node.stage ? `Stage: ${node.stage}` : undefined,
36
+ node.adapterId ? `Adapter: ${node.adapterId}` : undefined,
37
+ node.model ? `Model: ${node.model}` : undefined,
38
+ node.error ? `Error: ${compact(node.error, run, 800)}` : undefined,
39
+ artifactTypes.length > 0 ? `Artifacts: ${artifactTypes.join(', ')}` : undefined,
40
+ node.outputText ? `Output excerpt:\n${compact(node.outputText, run)}` : undefined,
41
+ ].filter(Boolean).join('\n');
42
+ }
43
+ function replayTraceSummary(run, nodes) {
44
+ return nodes.map((node) => nodeTraceSummary(run, node)).join('\n\n---\n\n');
45
+ }
46
+ function pushOperation(operations, kind, nodeId, summary) {
47
+ if (operations.some((operation) => operation.kind === kind && operation.nodeId === nodeId && operation.summary === summary)) {
48
+ return;
49
+ }
50
+ operations.push({ kind, nodeId, summary });
51
+ }
52
+ function detectReplayOperations(run, nodes) {
53
+ const operations = [];
54
+ for (const node of nodes) {
55
+ for (const artifact of node.artifacts ?? []) {
56
+ if (artifact.type === 'file-diff') {
57
+ pushOperation(operations, 'file-write', node.nodeId, 'Prior step produced a file diff artifact.');
58
+ }
59
+ if (artifact.type === 'command-output') {
60
+ pushOperation(operations, 'shell', node.nodeId, 'Prior step produced command output.');
61
+ }
62
+ const text = [artifact.text, artifact.data ? JSON.stringify(artifact.data) : undefined]
63
+ .filter(Boolean)
64
+ .join('\n')
65
+ .toLocaleLowerCase('en');
66
+ if (/https?:\/\/|curl |wget |gh |npm publish|npm install|git push|ssh /u.test(text)) {
67
+ pushOperation(operations, 'network', node.nodeId, 'Prior artifact references a network-capable operation.');
68
+ }
69
+ }
70
+ const text = [node.outputText, node.error, node.promptPreview].filter(Boolean).join('\n').toLocaleLowerCase('en');
71
+ if (/apply_patch|write file|file write|modified files|changed files/u.test(text)) {
72
+ pushOperation(operations, 'file-write', node.nodeId, 'Prior step text references file-write activity.');
73
+ }
74
+ if (/shell|command|terminal|npm run|node |python |php |go test|cargo |make |exit code/u.test(text)) {
75
+ pushOperation(operations, 'shell', node.nodeId, 'Prior step text references shell execution.');
76
+ }
77
+ if (/https?:\/\/|curl |wget |gh |npm publish|npm install|git push|ssh |network/u.test(text)) {
78
+ pushOperation(operations, 'network', node.nodeId, 'Prior step text references a network-capable operation.');
79
+ }
80
+ }
81
+ return operations;
82
+ }
83
+ function replayNodeFromRunNode(node, index, previousReplayNodeId, traceSummary, limitations, requiresApproval) {
84
+ const replayNodeId = `replay_${index + 1}_${safeNodeId(node.nodeId)}`;
85
+ return {
86
+ id: replayNodeId,
87
+ adapterId: node.adapterId || 'claude-code',
88
+ agentInstanceId: node.agentInstanceId,
89
+ agentLabel: node.agentLabel ? `${node.agentLabel} Replay` : 'Replay agent',
90
+ assignment: node.assignment ? `Replay: ${node.assignment}` : `Replay source node ${node.nodeId}`,
91
+ stage: node.stage ? `replay_${node.stage}` : 'replay',
92
+ model: node.model,
93
+ permissionMode: node.permissionMode === 'bypassPermissions' ? 'default' : node.permissionMode,
94
+ timeoutMs: node.timeoutMs,
95
+ inputs: previousReplayNodeId ? [previousReplayNodeId] : [],
96
+ output: 'both',
97
+ onFail: 'abort',
98
+ prompt: [
99
+ 'This is a Pixcode workflow replay run.',
100
+ `Replay protocol: ${PIXCODE_REPLAY_PROTOCOL}`,
101
+ `Source node: ${node.nodeId}`,
102
+ requiresApproval
103
+ ? 'Replay safety review found prior shell, network, or file-write activity. Do not repeat any such action unless the current CLI permission flow asks for and receives user approval.'
104
+ : 'Replay safety review did not find prior shell, network, or file-write artifacts, but still avoid destructive actions unless they are required and approved.',
105
+ 'Use the trace summary to continue from the failure or inspect the run. Do not expose secrets, local-only paths, raw tool protocol, or irrelevant logs.',
106
+ `Known limitations:\n- ${limitations.join('\n- ')}`,
107
+ `Trace summary:\n${traceSummary}`,
108
+ `Original step prompt:\n${node.promptPreview || '(No source prompt was stored.)'}`,
109
+ ].join('\n\n'),
110
+ };
111
+ }
112
+ export function buildWorkflowReplayPlan(run, options = {}) {
113
+ const scope = options.scope ?? 'node';
114
+ const nodes = selectReplayNodes(run, scope, options.fromNodeId);
115
+ if (nodes.length === 0) {
116
+ throw new Error('No replayable workflow steps were found.');
117
+ }
118
+ const limitations = [
119
+ 'Replay uses stored run traces, prompt previews, messages, and artifacts; it cannot reproduce hidden provider state.',
120
+ 'Replay reconstructs selected steps as a new workflow run instead of mutating the source run.',
121
+ 'Shell, network, and file-write actions stay under the current CLI permission flow and require explicit replay approval when detected.',
122
+ ];
123
+ const destructiveOperations = detectReplayOperations(run, nodes);
124
+ const requiresApproval = destructiveOperations.length > 0;
125
+ const traceSummary = replayTraceSummary(run, nodes);
126
+ const replayNodes = nodes.reduce((accumulator, node, index) => {
127
+ const previousReplayNodeId = accumulator[accumulator.length - 1]?.id;
128
+ accumulator.push(replayNodeFromRunNode(node, index, scope === 'run' ? previousReplayNodeId : undefined, traceSummary, limitations, requiresApproval));
129
+ return accumulator;
130
+ }, []);
131
+ const settings = readRecord(run.metadata?.settings) ?? {};
132
+ const replayMetadata = {
133
+ protocol: PIXCODE_REPLAY_PROTOCOL,
134
+ sourceRunId: run.id,
135
+ sourceWorkflowId: run.workflowId,
136
+ scope,
137
+ fromNodeId: options.fromNodeId,
138
+ selectedNodeIds: nodes.map((node) => node.nodeId),
139
+ requiresApproval,
140
+ destructiveOperations,
141
+ limitations,
142
+ createdAt: Date.now(),
143
+ };
144
+ return {
145
+ protocol: PIXCODE_REPLAY_PROTOCOL,
146
+ sourceRunId: run.id,
147
+ sourceWorkflowId: run.workflowId,
148
+ scope,
149
+ fromNodeId: options.fromNodeId,
150
+ selectedNodeIds: nodes.map((node) => node.nodeId),
151
+ requiresApproval,
152
+ approvalReasons: destructiveOperations.map((operation) => `${operation.kind}${operation.nodeId ? ` in ${operation.nodeId}` : ''}: ${operation.summary}`),
153
+ destructiveOperations,
154
+ limitations,
155
+ input: [
156
+ `Replay ${scope === 'run' ? 'full workflow run' : 'workflow step'} from source run ${run.id}.`,
157
+ run.input ? `Original request:\n${compact(run.input, run, 2_000)}` : undefined,
158
+ ].filter(Boolean).join('\n\n'),
159
+ workflow: {
160
+ id: `${run.workflowId}_replay`,
161
+ name: `Replay ${run.workflowId}`,
162
+ description: 'Replay generated from stored Pixcode workflow trace data.',
163
+ trigger: 'manual',
164
+ nodes: replayNodes,
165
+ },
166
+ metadata: {
167
+ ...run.metadata,
168
+ workflowName: `Replay: ${String(run.metadata?.workflowName ?? run.workflowId)}`,
169
+ replay: replayMetadata,
170
+ settings: {
171
+ ...settings,
172
+ replayMode: true,
173
+ },
174
+ },
175
+ };
176
+ }
177
+ //# sourceMappingURL=workflow-replay.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workflow-replay.js","sourceRoot":"","sources":["../../../../../server/modules/orchestration/workflows/workflow-replay.ts"],"names":[],"mappings":"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"}
@@ -1,6 +1,7 @@
1
1
  import crypto from 'node:crypto';
2
2
  import { PIXCODE_HANDOFF_PROTOCOL, formatHandoffArtifactForContext, handoffArtifactToWorkflowArtifact, parseHandoffArtifact, } from '../../../modules/orchestration/workflows/handoff-artifact.js';
3
3
  import { buildWorkflowContextPacket, formatContextPacketForPrompt, } from '../../../modules/orchestration/workflows/context-packet.js';
4
+ import { classifyWorkflowFailure, resolveWorkflowFallbackDecision, } from '../../../modules/orchestration/workflows/workflow-fallback-policy.js';
4
5
  import { resolveWorkflowWorkspace, workspaceContextPrompt, workspaceTargetMetadata, } from '../../../modules/orchestration/workflows/workspace-target.js';
5
6
  import { workflowStore } from '../../../modules/orchestration/workflows/workflow-store.js';
6
7
  // @ts-ignore — plain-JS service
@@ -925,6 +926,8 @@ function nodeRunFromNode(node) {
925
926
  timeoutMs: node.timeoutMs,
926
927
  stage: node.stage,
927
928
  internal: node.internal,
929
+ fallbackTrigger: node.fallbackTrigger,
930
+ fallbackSourceNodeId: node.fallbackSourceNodeId,
928
931
  status: 'queued',
929
932
  };
930
933
  }
@@ -1060,7 +1063,7 @@ class WorkflowRunner {
1060
1063
  }
1061
1064
  return readAgentAssignments(run.metadata).find((agent) => agent.instanceId === fallbackAgentInstanceId);
1062
1065
  }
1063
- createFallbackNode(node, fallbackAgent, reason) {
1066
+ createFallbackNode(node, fallbackAgent, reason, fallbackTrigger) {
1064
1067
  const fallbackSuffix = safeNodeId(fallbackAgent.instanceId, 'fallback');
1065
1068
  return {
1066
1069
  ...node,
@@ -1073,9 +1076,12 @@ class WorkflowRunner {
1073
1076
  model: fallbackAgent.model,
1074
1077
  permissionMode: fallbackAgent.permissionMode,
1075
1078
  toolsSettings: fallbackAgent.toolsSettings,
1079
+ fallbackTrigger,
1080
+ fallbackSourceNodeId: node.id,
1076
1081
  prompt: [
1077
1082
  'The previous CLI agent failed on this orchestration step.',
1078
1083
  `Failed step: ${node.agentLabel || node.id}`,
1084
+ `Fallback trigger: ${fallbackTrigger}`,
1079
1085
  `Failure: ${reason}`,
1080
1086
  'Take over the same assignment as the backup CLI. Use the original goal and upstream context.',
1081
1087
  'Do not repeat unrelated work; complete the failed step and report what you did.',
@@ -1084,9 +1090,41 @@ class WorkflowRunner {
1084
1090
  onFail: 'continue',
1085
1091
  };
1086
1092
  }
1087
- async runFallbackAfterFailure(node, workflow, run, outputs, started, completed, reason) {
1093
+ recordFallbackSkipped(run, node, reason, fallbackTrigger, skippedReason) {
1094
+ const fallbackSkippedEvents = Array.isArray(run.metadata?.fallbackSkippedEvents)
1095
+ ? run.metadata.fallbackSkippedEvents
1096
+ : [];
1097
+ run.metadata = {
1098
+ ...run.metadata,
1099
+ fallbackSkippedEvents: [
1100
+ ...fallbackSkippedEvents,
1101
+ {
1102
+ nodeId: node.id,
1103
+ trigger: fallbackTrigger,
1104
+ reason,
1105
+ skippedReason,
1106
+ createdAt: Date.now(),
1107
+ },
1108
+ ],
1109
+ };
1110
+ workflowStore.setRun(run);
1111
+ }
1112
+ async runFallbackAfterFailure(node, workflow, run, outputs, started, completed, reason, trigger) {
1113
+ const fallbackTrigger = classifyWorkflowFailure(reason, trigger);
1088
1114
  const fallbackAgent = this.fallbackAgentFor(run, node);
1089
1115
  if (!fallbackAgent) {
1116
+ this.recordFallbackSkipped(run, node, reason, fallbackTrigger, 'No fallback agent is configured for this run.');
1117
+ return false;
1118
+ }
1119
+ const decision = resolveWorkflowFallbackDecision({
1120
+ run,
1121
+ node,
1122
+ reason,
1123
+ trigger: fallbackTrigger,
1124
+ fallbackAgentInstanceId: fallbackAgent.instanceId,
1125
+ });
1126
+ if (!decision.shouldFallback) {
1127
+ this.recordFallbackSkipped(run, node, reason, decision.trigger, decision.skippedReason ?? 'Fallback policy skipped this failure.');
1090
1128
  return false;
1091
1129
  }
1092
1130
  if (workflow.nodes.length + 1 > 64) {
@@ -1097,7 +1135,7 @@ class WorkflowRunner {
1097
1135
  workflowStore.setRun(run);
1098
1136
  return false;
1099
1137
  }
1100
- let fallbackNode = this.createFallbackNode(node, fallbackAgent, reason);
1138
+ let fallbackNode = this.createFallbackNode(node, fallbackAgent, reason, decision.trigger);
1101
1139
  let collision = 1;
1102
1140
  while (workflow.nodes.some((candidate) => candidate.id === fallbackNode.id)) {
1103
1141
  collision += 1;
@@ -1131,6 +1169,8 @@ class WorkflowRunner {
1131
1169
  nodeId: node.id,
1132
1170
  fallbackNodeId: fallbackNode.id,
1133
1171
  fallbackAgentInstanceId: fallbackAgent.instanceId,
1172
+ trigger: decision.trigger,
1173
+ policy: decision.policy,
1134
1174
  reason,
1135
1175
  startedAt: Date.now(),
1136
1176
  },
@@ -1412,7 +1452,7 @@ class WorkflowRunner {
1412
1452
  workflowStore.setRun(run);
1413
1453
  return;
1414
1454
  }
1415
- if (await this.runFallbackAfterFailure(node, workflow, run, outputs, started, completed, nodeRun.error)) {
1455
+ if (await this.runFallbackAfterFailure(node, workflow, run, outputs, started, completed, nodeRun.error, 'provider_failure')) {
1416
1456
  return;
1417
1457
  }
1418
1458
  if (node.onFail === 'continue') {
@@ -1457,7 +1497,7 @@ class WorkflowRunner {
1457
1497
  workflowStore.setRun(run);
1458
1498
  return;
1459
1499
  }
1460
- if (await this.runFallbackAfterFailure(node, workflow, run, outputs, started, completed, nodeRun.error)) {
1500
+ if (await this.runFallbackAfterFailure(node, workflow, run, outputs, started, completed, nodeRun.error, 'timeout')) {
1461
1501
  return;
1462
1502
  }
1463
1503
  if (node.onFail === 'continue') {
@@ -1491,7 +1531,7 @@ class WorkflowRunner {
1491
1531
  nodeRun.status = 'failed';
1492
1532
  nodeRun.error = visibleHandoffError;
1493
1533
  workflowStore.setRun(run);
1494
- if (await this.runFallbackAfterFailure(node, workflow, run, outputs, started, completed, visibleHandoffError)) {
1534
+ if (await this.runFallbackAfterFailure(node, workflow, run, outputs, started, completed, visibleHandoffError, 'invalid_output')) {
1495
1535
  return;
1496
1536
  }
1497
1537
  if (node.onFail === 'continue') {
@@ -1527,7 +1567,7 @@ class WorkflowRunner {
1527
1567
  workflowStore.setRun(run);
1528
1568
  return;
1529
1569
  }
1530
- if (await this.runFallbackAfterFailure(node, workflow, run, outputs, started, completed, nodeRun.error)) {
1570
+ if (await this.runFallbackAfterFailure(node, workflow, run, outputs, started, completed, nodeRun.error, classifyWorkflowFailure(`${nodeRun.error}\n${nodeRun.outputText ?? ''}`))) {
1531
1571
  return;
1532
1572
  }
1533
1573
  if (node.onFail === 'continue') {