@pixelbyte-software/pixcode 1.41.5 → 1.42.1
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/dist/assets/{index-BmK4VcVP.js → index-C97kIvXz.js} +4 -4
- package/dist/index.html +1 -1
- package/dist-server/server/modules/orchestration/workflows/context-packet.js +89 -0
- package/dist-server/server/modules/orchestration/workflows/context-packet.js.map +1 -0
- package/dist-server/server/modules/orchestration/workflows/handoff-artifact.js +123 -0
- package/dist-server/server/modules/orchestration/workflows/handoff-artifact.js.map +1 -0
- package/dist-server/server/modules/orchestration/workflows/workflow-runner.js +79 -18
- package/dist-server/server/modules/orchestration/workflows/workflow-runner.js.map +1 -1
- package/dist-server/server/modules/orchestration/workflows/workflow-trace.js +25 -0
- package/dist-server/server/modules/orchestration/workflows/workflow-trace.js.map +1 -1
- package/package.json +1 -1
- package/scripts/smoke/context-packet.mjs +43 -0
- package/scripts/smoke/handoff-artifact-protocol.mjs +50 -0
- package/server/modules/orchestration/a2a/types.ts +1 -0
- package/server/modules/orchestration/workflows/context-packet.ts +186 -0
- package/server/modules/orchestration/workflows/handoff-artifact.ts +175 -0
- package/server/modules/orchestration/workflows/workflow-runner.ts +92 -18
- package/server/modules/orchestration/workflows/workflow-trace.ts +24 -0
- 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-
|
|
38
|
+
<script type="module" crossorigin src="/assets/index-C97kIvXz.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,89 @@
|
|
|
1
|
+
export const PIXCODE_CONTEXT_PROTOCOL = 'pixcode.context.v1';
|
|
2
|
+
export const MAX_CONTEXT_PACKET_TEXT_CHARS = 16_000;
|
|
3
|
+
function compactContextText(text) {
|
|
4
|
+
const originalChars = text.length;
|
|
5
|
+
if (originalChars <= MAX_CONTEXT_PACKET_TEXT_CHARS) {
|
|
6
|
+
return {
|
|
7
|
+
text,
|
|
8
|
+
originalChars,
|
|
9
|
+
compactedChars: originalChars,
|
|
10
|
+
omittedChars: 0,
|
|
11
|
+
wasCompacted: false,
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
const edge = Math.floor(MAX_CONTEXT_PACKET_TEXT_CHARS / 2);
|
|
15
|
+
const omittedChars = originalChars - MAX_CONTEXT_PACKET_TEXT_CHARS;
|
|
16
|
+
const compacted = [
|
|
17
|
+
text.slice(0, edge),
|
|
18
|
+
`\n\n[...${omittedChars} characters omitted from upstream context packet...]\n\n`,
|
|
19
|
+
text.slice(-edge),
|
|
20
|
+
].join('');
|
|
21
|
+
return {
|
|
22
|
+
text: compacted,
|
|
23
|
+
originalChars,
|
|
24
|
+
compactedChars: compacted.length,
|
|
25
|
+
omittedChars,
|
|
26
|
+
wasCompacted: true,
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
export function buildWorkflowContextPacket({ run, node, workspaceTarget, inputContext, inputNodeIds, }) {
|
|
30
|
+
const compacted = compactContextText(inputContext);
|
|
31
|
+
return {
|
|
32
|
+
protocol: PIXCODE_CONTEXT_PROTOCOL,
|
|
33
|
+
originalUserRequest: run.input?.trim() || '(No original user request was provided.)',
|
|
34
|
+
project: {
|
|
35
|
+
kind: workspaceTarget.kind,
|
|
36
|
+
label: workspaceTarget.label,
|
|
37
|
+
selectedProjectName: workspaceTarget.selectedProjectName,
|
|
38
|
+
},
|
|
39
|
+
task: {
|
|
40
|
+
workflowId: run.workflowId,
|
|
41
|
+
workflowRunId: run.id,
|
|
42
|
+
nodeId: node.id,
|
|
43
|
+
stage: node.stage,
|
|
44
|
+
assignment: node.assignment,
|
|
45
|
+
stepInstructions: node.prompt,
|
|
46
|
+
},
|
|
47
|
+
constraints: {
|
|
48
|
+
adapterId: node.adapterId,
|
|
49
|
+
agentLabel: node.agentLabel,
|
|
50
|
+
model: node.model,
|
|
51
|
+
permissionMode: node.permissionMode,
|
|
52
|
+
isolation: node.isolation,
|
|
53
|
+
toolsSettings: node.toolsSettings,
|
|
54
|
+
},
|
|
55
|
+
upstreamArtifacts: compacted.text
|
|
56
|
+
? [{
|
|
57
|
+
type: 'upstream-context',
|
|
58
|
+
text: compacted.text,
|
|
59
|
+
sourceNodeIds: inputNodeIds,
|
|
60
|
+
}]
|
|
61
|
+
: [],
|
|
62
|
+
runState: {
|
|
63
|
+
status: run.status,
|
|
64
|
+
startedAt: run.startedAt,
|
|
65
|
+
nodeCount: run.nodeRuns.length,
|
|
66
|
+
completedNodeIds: run.nodeRuns
|
|
67
|
+
.filter((nodeRun) => nodeRun.status === 'completed')
|
|
68
|
+
.map((nodeRun) => nodeRun.nodeId),
|
|
69
|
+
runningNodeIds: run.nodeRuns
|
|
70
|
+
.filter((nodeRun) => nodeRun.status === 'running')
|
|
71
|
+
.map((nodeRun) => nodeRun.nodeId),
|
|
72
|
+
},
|
|
73
|
+
compaction: {
|
|
74
|
+
maxChars: MAX_CONTEXT_PACKET_TEXT_CHARS,
|
|
75
|
+
originalChars: compacted.originalChars,
|
|
76
|
+
compactedChars: compacted.compactedChars,
|
|
77
|
+
omittedChars: compacted.omittedChars,
|
|
78
|
+
wasCompacted: compacted.wasCompacted,
|
|
79
|
+
},
|
|
80
|
+
createdAt: new Date().toISOString(),
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
export function formatContextPacketForPrompt(packet) {
|
|
84
|
+
return [
|
|
85
|
+
`Pixcode standardized init context packet (${PIXCODE_CONTEXT_PROTOCOL}):`,
|
|
86
|
+
JSON.stringify(packet, null, 2),
|
|
87
|
+
].join('\n');
|
|
88
|
+
}
|
|
89
|
+
//# sourceMappingURL=context-packet.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context-packet.js","sourceRoot":"","sources":["../../../../../server/modules/orchestration/workflows/context-packet.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
export const PIXCODE_HANDOFF_PROTOCOL = 'pixcode.handoff.v1';
|
|
2
|
+
const VALID_TASK_STATUSES = new Set([
|
|
3
|
+
'ready',
|
|
4
|
+
'completed',
|
|
5
|
+
'blocked',
|
|
6
|
+
'failed',
|
|
7
|
+
'needs-review',
|
|
8
|
+
]);
|
|
9
|
+
function extractJsonCandidate(text) {
|
|
10
|
+
const fenced = text.match(/```(?:json)?\s*([\s\S]*?)```/i)?.[1]?.trim();
|
|
11
|
+
if (fenced)
|
|
12
|
+
return fenced;
|
|
13
|
+
const start = text.indexOf('{');
|
|
14
|
+
const end = text.lastIndexOf('}');
|
|
15
|
+
if (start === -1 || end === -1 || end <= start)
|
|
16
|
+
return null;
|
|
17
|
+
return text.slice(start, end + 1);
|
|
18
|
+
}
|
|
19
|
+
function readRequiredString(record, key) {
|
|
20
|
+
const value = record[key];
|
|
21
|
+
if (typeof value !== 'string' || !value.trim())
|
|
22
|
+
return null;
|
|
23
|
+
return value.trim();
|
|
24
|
+
}
|
|
25
|
+
function sanitizeChangedFile(filePath) {
|
|
26
|
+
const normalized = filePath.trim().replaceAll('\\', '/');
|
|
27
|
+
if (!normalized)
|
|
28
|
+
return '';
|
|
29
|
+
if (!normalized.startsWith('/') && !/^[a-zA-Z]:\//.test(normalized))
|
|
30
|
+
return normalized;
|
|
31
|
+
return normalized.split('/').filter(Boolean).slice(-4).join('/');
|
|
32
|
+
}
|
|
33
|
+
function readStringArray(record, key) {
|
|
34
|
+
const value = record[key];
|
|
35
|
+
if (!Array.isArray(value))
|
|
36
|
+
return null;
|
|
37
|
+
return value
|
|
38
|
+
.filter((item) => typeof item === 'string')
|
|
39
|
+
.map((item) => key === 'changedFiles' ? sanitizeChangedFile(item) : item.trim())
|
|
40
|
+
.filter(Boolean)
|
|
41
|
+
.slice(0, 40);
|
|
42
|
+
}
|
|
43
|
+
export function parseHandoffArtifact(text, metadata = {}) {
|
|
44
|
+
const candidate = extractJsonCandidate(text);
|
|
45
|
+
if (!candidate) {
|
|
46
|
+
return { ok: false, error: 'Invalid handoff artifact: expected one JSON object.' };
|
|
47
|
+
}
|
|
48
|
+
let parsed;
|
|
49
|
+
try {
|
|
50
|
+
parsed = JSON.parse(candidate);
|
|
51
|
+
}
|
|
52
|
+
catch (error) {
|
|
53
|
+
return {
|
|
54
|
+
ok: false,
|
|
55
|
+
error: `Invalid handoff artifact: JSON parse failed (${error instanceof Error ? error.message : String(error)}).`,
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
|
|
59
|
+
return { ok: false, error: 'Invalid handoff artifact: payload must be an object.' };
|
|
60
|
+
}
|
|
61
|
+
const record = parsed;
|
|
62
|
+
if (record.protocol !== PIXCODE_HANDOFF_PROTOCOL) {
|
|
63
|
+
return { ok: false, error: `Invalid handoff artifact: protocol must be ${PIXCODE_HANDOFF_PROTOCOL}.` };
|
|
64
|
+
}
|
|
65
|
+
const taskStatus = record.taskStatus;
|
|
66
|
+
if (typeof taskStatus !== 'string' || !VALID_TASK_STATUSES.has(taskStatus)) {
|
|
67
|
+
return { ok: false, error: 'Invalid handoff artifact: taskStatus is missing or unsupported.' };
|
|
68
|
+
}
|
|
69
|
+
const contextSummary = readRequiredString(record, 'contextSummary');
|
|
70
|
+
const taskResult = readRequiredString(record, 'taskResult');
|
|
71
|
+
const changedFiles = readStringArray(record, 'changedFiles');
|
|
72
|
+
const blockers = readStringArray(record, 'blockers');
|
|
73
|
+
const risks = readStringArray(record, 'risks');
|
|
74
|
+
const nextAction = readRequiredString(record, 'nextAction');
|
|
75
|
+
const nextInstructions = readRequiredString(record, 'nextInstructions');
|
|
76
|
+
if (!contextSummary || !taskResult || !changedFiles || !blockers || !risks || !nextAction || !nextInstructions) {
|
|
77
|
+
return {
|
|
78
|
+
ok: false,
|
|
79
|
+
error: 'Invalid handoff artifact: required fields are protocol, taskStatus, contextSummary, taskResult, changedFiles, blockers, risks, nextAction, and nextInstructions.',
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
return {
|
|
83
|
+
ok: true,
|
|
84
|
+
artifact: {
|
|
85
|
+
protocol: PIXCODE_HANDOFF_PROTOCOL,
|
|
86
|
+
taskStatus: taskStatus,
|
|
87
|
+
contextSummary,
|
|
88
|
+
taskResult,
|
|
89
|
+
changedFiles,
|
|
90
|
+
blockers,
|
|
91
|
+
risks,
|
|
92
|
+
nextAction,
|
|
93
|
+
nextInstructions,
|
|
94
|
+
producedBy: {
|
|
95
|
+
workflowRunId: metadata.workflowRunId,
|
|
96
|
+
nodeId: metadata.nodeId,
|
|
97
|
+
agentLabel: metadata.agentLabel,
|
|
98
|
+
stage: metadata.stage,
|
|
99
|
+
},
|
|
100
|
+
createdAt: new Date().toISOString(),
|
|
101
|
+
},
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
export function formatHandoffArtifactForContext(artifact) {
|
|
105
|
+
return [
|
|
106
|
+
`Pixcode handoff artifact (${PIXCODE_HANDOFF_PROTOCOL})`,
|
|
107
|
+
JSON.stringify(artifact, null, 2),
|
|
108
|
+
].join('\n');
|
|
109
|
+
}
|
|
110
|
+
export function handoffArtifactToWorkflowArtifact(artifact) {
|
|
111
|
+
return {
|
|
112
|
+
type: 'handoff-artifact',
|
|
113
|
+
data: artifact,
|
|
114
|
+
metadata: {
|
|
115
|
+
protocol: artifact.protocol,
|
|
116
|
+
taskStatus: artifact.taskStatus,
|
|
117
|
+
changedFileCount: artifact.changedFiles.length,
|
|
118
|
+
blockerCount: artifact.blockers.length,
|
|
119
|
+
nextAction: artifact.nextAction,
|
|
120
|
+
},
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
//# sourceMappingURL=handoff-artifact.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"handoff-artifact.js","sourceRoot":"","sources":["../../../../../server/modules/orchestration/workflows/handoff-artifact.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import crypto from 'node:crypto';
|
|
2
|
+
import { PIXCODE_HANDOFF_PROTOCOL, formatHandoffArtifactForContext, handoffArtifactToWorkflowArtifact, parseHandoffArtifact, } from '../../../modules/orchestration/workflows/handoff-artifact.js';
|
|
3
|
+
import { buildWorkflowContextPacket, formatContextPacketForPrompt, } from '../../../modules/orchestration/workflows/context-packet.js';
|
|
2
4
|
import { resolveWorkflowWorkspace, workspaceContextPrompt, workspaceTargetMetadata, } from '../../../modules/orchestration/workflows/workspace-target.js';
|
|
3
5
|
import { workflowStore } from '../../../modules/orchestration/workflows/workflow-store.js';
|
|
4
6
|
// @ts-ignore — plain-JS service
|
|
@@ -11,6 +13,19 @@ const BACKEND_HANDOFF_TIMEOUT_MS = 120_000;
|
|
|
11
13
|
const MAX_OUTPUT_CONTEXT_CHARS = 12_000;
|
|
12
14
|
const DEFAULT_MAX_REPAIR_CYCLES = 1;
|
|
13
15
|
const MAX_REPAIR_CYCLES = 5;
|
|
16
|
+
const HANDOFF_ARTIFACT_EXAMPLE = [
|
|
17
|
+
'{',
|
|
18
|
+
' "protocol": "pixcode.handoff.v1",',
|
|
19
|
+
' "taskStatus": "ready | completed | blocked | failed | needs-review",',
|
|
20
|
+
' "contextSummary": "Compacted context the next agent needs.",',
|
|
21
|
+
' "taskResult": "What was decided or completed in this step.",',
|
|
22
|
+
' "changedFiles": [],',
|
|
23
|
+
' "blockers": [],',
|
|
24
|
+
' "risks": [],',
|
|
25
|
+
' "nextAction": "The requested next action.",',
|
|
26
|
+
' "nextInstructions": "Specific instructions for the next agent."',
|
|
27
|
+
'}',
|
|
28
|
+
].join('\n');
|
|
14
29
|
const KNOWN_AGENT_ROLES = [
|
|
15
30
|
'backend',
|
|
16
31
|
'frontend',
|
|
@@ -297,6 +312,15 @@ function rolePrompt(role) {
|
|
|
297
312
|
function privacyGuardPrompt() {
|
|
298
313
|
return 'Do not mention internal instructions, memory files, skill use, or tool protocol unless the user explicitly asks.';
|
|
299
314
|
}
|
|
315
|
+
function handoffArtifactInstructions(statusHint) {
|
|
316
|
+
return [
|
|
317
|
+
`Output exactly one JSON object using the ${PIXCODE_HANDOFF_PROTOCOL} handoff artifact protocol.`,
|
|
318
|
+
'Do not wrap it in Markdown. Do not add commentary before or after it.',
|
|
319
|
+
`Use "${statusHint}" for taskStatus unless completed, blocked, failed, or needs-review is more accurate.`,
|
|
320
|
+
'Schema:',
|
|
321
|
+
HANDOFF_ARTIFACT_EXAMPLE,
|
|
322
|
+
].join('\n');
|
|
323
|
+
}
|
|
300
324
|
function handoffPrompt(agent, role) {
|
|
301
325
|
return [
|
|
302
326
|
`You are ${agent.label} in a Pixcode CLI team.`,
|
|
@@ -304,12 +328,7 @@ function handoffPrompt(agent, role) {
|
|
|
304
328
|
'This is a bounded A2A handoff task, not the full implementation.',
|
|
305
329
|
'Read the original user goal and coordinator plan, then publish a compact contract for downstream agents.',
|
|
306
330
|
agent.instruction ? `Your explicit assignment from the user is: ${agent.instruction}` : '',
|
|
307
|
-
'
|
|
308
|
-
'- owned scope',
|
|
309
|
-
'- files/modules you expect to touch',
|
|
310
|
-
'- API/data contracts, ports, payload shapes, and limitations',
|
|
311
|
-
'- dependencies/blockers for the next agents',
|
|
312
|
-
'- concrete next action for your full implementation task',
|
|
331
|
+
handoffArtifactInstructions('ready'),
|
|
313
332
|
'Do not install dependencies, edit files, run long commands, or start servers in this handoff task.',
|
|
314
333
|
privacyGuardPrompt(),
|
|
315
334
|
'Stop after the contract. Keep it concise and respond in the same language as the user request.',
|
|
@@ -322,11 +341,7 @@ function handoffInitPrompt(agent, index) {
|
|
|
322
341
|
'Create a compact init packet for the next visible work step.',
|
|
323
342
|
'Use the original user goal and any prior compact handoff packet included above.',
|
|
324
343
|
agent.instruction ? `The explicit assignment for this agent is: ${agent.instruction}` : '',
|
|
325
|
-
'
|
|
326
|
-
'- user goal in one sentence',
|
|
327
|
-
'- prior agent handoff summary, if present',
|
|
328
|
-
'- this agent responsibility',
|
|
329
|
-
'- exact constraints and blockers this agent must respect',
|
|
344
|
+
handoffArtifactInstructions('ready'),
|
|
330
345
|
privacyGuardPrompt(),
|
|
331
346
|
'Do not perform the task yet. Do not mention that this is hidden from the user.',
|
|
332
347
|
'Respond in the same language as the user request.',
|
|
@@ -351,12 +366,7 @@ function handoffCompactPrompt(agent, index) {
|
|
|
351
366
|
`You are compacting ${agent.label}'s strict handoff output for the next Pixcode agent.`,
|
|
352
367
|
`This is internal compact step ${index + 1}.`,
|
|
353
368
|
'Read the prior visible work output included above and create a compact handoff packet.',
|
|
354
|
-
'
|
|
355
|
-
'- Ben ne yaptım / What I did',
|
|
356
|
-
'- Dokunduğum alanlar / Touched areas',
|
|
357
|
-
'- Kanıt, komut veya çıktı / Evidence, commands, outputs',
|
|
358
|
-
'- Sonraki ajan şunu bilsin / What the next agent must know',
|
|
359
|
-
'- Bloker veya risk / Blockers or risks',
|
|
369
|
+
handoffArtifactInstructions('completed'),
|
|
360
370
|
privacyGuardPrompt(),
|
|
361
371
|
'Do not include raw logs unless they are essential. Keep it concise and actionable.',
|
|
362
372
|
'Respond in the same language as the user request.',
|
|
@@ -373,6 +383,16 @@ function compactOutputForContext(text) {
|
|
|
373
383
|
text.slice(-edge),
|
|
374
384
|
].join('');
|
|
375
385
|
}
|
|
386
|
+
function requiresHandoffArtifact(node) {
|
|
387
|
+
return node.stage === 'handoff' || node.stage === 'handoff_init' || node.stage === 'handoff_compact';
|
|
388
|
+
}
|
|
389
|
+
function handoffArtifactSource(result) {
|
|
390
|
+
const structured = result.artifacts.find((artifact) => artifact.type === 'handoff-artifact' && artifact.data);
|
|
391
|
+
if (structured?.data) {
|
|
392
|
+
return JSON.stringify(structured.data);
|
|
393
|
+
}
|
|
394
|
+
return result.text;
|
|
395
|
+
}
|
|
376
396
|
function isExternalDirectoryPermissionError(value) {
|
|
377
397
|
const text = String(value ?? '').toLocaleLowerCase('en');
|
|
378
398
|
return (text.includes('external_directory') ||
|
|
@@ -1298,9 +1318,19 @@ class WorkflowRunner {
|
|
|
1298
1318
|
workflowStore.setRun(run);
|
|
1299
1319
|
const inputContext = node.inputs.map((input) => outputs.get(input)).filter(Boolean).join('\n\n');
|
|
1300
1320
|
const workspaceTarget = resolveWorkflowWorkspace(run.metadata);
|
|
1321
|
+
const contextPacket = buildWorkflowContextPacket({
|
|
1322
|
+
run,
|
|
1323
|
+
node,
|
|
1324
|
+
workspaceTarget,
|
|
1325
|
+
inputContext,
|
|
1326
|
+
inputNodeIds: node.inputs,
|
|
1327
|
+
});
|
|
1328
|
+
nodeRun.contextPacket = contextPacket;
|
|
1329
|
+
workflowStore.setRun(run);
|
|
1301
1330
|
const prompt = [
|
|
1302
1331
|
'Original user request (primary task; answer this directly even if the workspace is empty):',
|
|
1303
1332
|
run.input?.trim() || '(No original user request was provided.)',
|
|
1333
|
+
formatContextPacketForPrompt(contextPacket),
|
|
1304
1334
|
inputContext
|
|
1305
1335
|
? `Upstream workflow context from prior agents:\n${inputContext}`
|
|
1306
1336
|
: '',
|
|
@@ -1446,7 +1476,38 @@ class WorkflowRunner {
|
|
|
1446
1476
|
throw new WorkflowCanceledError();
|
|
1447
1477
|
}
|
|
1448
1478
|
if (result.state === 'completed') {
|
|
1449
|
-
|
|
1479
|
+
let outputForContext = result.text;
|
|
1480
|
+
if (requiresHandoffArtifact(node)) {
|
|
1481
|
+
const handoffParse = parseHandoffArtifact(handoffArtifactSource(result), {
|
|
1482
|
+
workflowRunId: run.id,
|
|
1483
|
+
nodeId: node.id,
|
|
1484
|
+
agentLabel: node.agentLabel,
|
|
1485
|
+
stage: node.stage,
|
|
1486
|
+
});
|
|
1487
|
+
if (!handoffParse.ok) {
|
|
1488
|
+
const visibleHandoffError = handoffParse.error.startsWith('Invalid handoff artifact')
|
|
1489
|
+
? handoffParse.error
|
|
1490
|
+
: `Invalid handoff artifact: ${handoffParse.error}`;
|
|
1491
|
+
nodeRun.status = 'failed';
|
|
1492
|
+
nodeRun.error = visibleHandoffError;
|
|
1493
|
+
workflowStore.setRun(run);
|
|
1494
|
+
if (await this.runFallbackAfterFailure(node, workflow, run, outputs, started, completed, visibleHandoffError)) {
|
|
1495
|
+
return;
|
|
1496
|
+
}
|
|
1497
|
+
if (node.onFail === 'continue') {
|
|
1498
|
+
completed.add(node.id);
|
|
1499
|
+
return;
|
|
1500
|
+
}
|
|
1501
|
+
throw new Error(visibleHandoffError);
|
|
1502
|
+
}
|
|
1503
|
+
nodeRun.handoffArtifact = handoffParse.artifact;
|
|
1504
|
+
nodeRun.artifacts = [
|
|
1505
|
+
...(nodeRun.artifacts ?? []).filter((artifact) => artifact.type !== 'handoff-artifact'),
|
|
1506
|
+
handoffArtifactToWorkflowArtifact(handoffParse.artifact),
|
|
1507
|
+
];
|
|
1508
|
+
outputForContext = formatHandoffArtifactForContext(handoffParse.artifact);
|
|
1509
|
+
}
|
|
1510
|
+
outputs.set(node.id, compactOutputForContext(outputForContext));
|
|
1450
1511
|
completed.add(node.id);
|
|
1451
1512
|
nodeRun.status = 'completed';
|
|
1452
1513
|
workflowStore.setRun(run);
|