lua-cli 3.32.1 → 3.32.3
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/api-exports.d.ts +414 -103
- package/dist/api-exports.js +2216 -622
- package/dist/api-exports.js.map +1 -1
- package/dist/index.js +5374 -2188
- package/dist/index.js.map +1 -1
- package/dist/voice/test/index.d.ts +54 -54
- package/dist/workflow-builder.d.ts +228 -45
- package/dist/workflow-builder.js +1945 -1025
- package/dist/workflow-builder.js.map +1 -1
- package/docs/CLI_REFERENCE.md +126 -4
- package/docs/README.md +2 -2
- package/docs/api/LuaWorkflow.md +16 -16
- package/docs/api/Workflows.md +10 -0
- package/docs/workflows/approvals.md +24 -6
- package/docs/workflows/correlation-keys.md +1 -0
- package/docs/workflows/goals.md +2 -2
- package/docs/workflows/limits.md +6 -0
- package/docs/workflows/replay-local.md +9 -3
- package/docs/workflows/schedules.md +1 -1
- package/docs/workflows/script-form.md +22 -12
- package/docs/workflows/testing-offline.md +35 -21
- package/docs/workflows/workspaces-and-long-steps.md +36 -2
- package/package.json +5 -4
- package/template/examples/workflows/CLAUDE.md +17 -11
- package/template/examples/workflows/adversarial-verify.workflow.script.js +20 -16
- package/template/examples/workflows/outreach.ts +31 -15
- package/template/examples/workflows/pr-review-round.ts +7 -3
- package/template/examples/workflows/refund-approval.ts +26 -12
- package/template/examples/workflows/ticket-to-pr.ts +43 -36
- package/template/package.json +1 -1
package/dist/workflow-builder.js
CHANGED
|
@@ -4,9 +4,6 @@ var __name = (target, value3) => __defProp(target, "name", { value: value3, conf
|
|
|
4
4
|
// src/types/workflow.ts
|
|
5
5
|
import { zodToJsonSchema } from "zod-to-json-schema";
|
|
6
6
|
|
|
7
|
-
// ../workflow-graph/dist/index.mjs
|
|
8
|
-
import { createHash } from "crypto";
|
|
9
|
-
|
|
10
7
|
// ../shared-types/dist/index.mjs
|
|
11
8
|
import { z } from "zod";
|
|
12
9
|
import { z as z2 } from "zod";
|
|
@@ -659,6 +656,12 @@ function isImplicitModelSelectionSource(source) {
|
|
|
659
656
|
}
|
|
660
657
|
__name(isImplicitModelSelectionSource, "isImplicitModelSelectionSource");
|
|
661
658
|
__name2(isImplicitModelSelectionSource, "isImplicitModelSelectionSource");
|
|
659
|
+
var PLATFORM_FALLBACK_MODEL_SOURCE = "platform-fallback";
|
|
660
|
+
function isPlatformFallbackModelSource(source) {
|
|
661
|
+
return source === PLATFORM_FALLBACK_MODEL_SOURCE;
|
|
662
|
+
}
|
|
663
|
+
__name(isPlatformFallbackModelSource, "isPlatformFallbackModelSource");
|
|
664
|
+
__name2(isPlatformFallbackModelSource, "isPlatformFallbackModelSource");
|
|
662
665
|
function resolveRequireToolApproval(rules) {
|
|
663
666
|
const raw = rules?.requireToolApproval ?? rules?.requireApproval;
|
|
664
667
|
if (raw === void 0 || raw === null) return void 0;
|
|
@@ -1489,6 +1492,87 @@ function hasCapability(profiles, profileId, required) {
|
|
|
1489
1492
|
}
|
|
1490
1493
|
__name(hasCapability, "hasCapability");
|
|
1491
1494
|
__name2(hasCapability, "hasCapability");
|
|
1495
|
+
function workflowJobId(id) {
|
|
1496
|
+
switch (id.kind) {
|
|
1497
|
+
case "start":
|
|
1498
|
+
return `wft_${id.runId}_0`;
|
|
1499
|
+
case "start-redrive":
|
|
1500
|
+
return `wft_${id.runId}_start_r${id.now}`;
|
|
1501
|
+
case "tick":
|
|
1502
|
+
return `wft_${id.runId}_${id.seq}`;
|
|
1503
|
+
case "timer":
|
|
1504
|
+
return `wft_${id.runId}_timer_${id.stepId}_${id.attempt}`;
|
|
1505
|
+
case "timer-remainder":
|
|
1506
|
+
return `wft_${id.runId}_timer_${id.stepId}_${id.attempt}_r${id.now}`;
|
|
1507
|
+
case "timer-deferral":
|
|
1508
|
+
return `wft_${id.runId}_timer_${id.stepId}_${id.attempt}_d${id.now}`;
|
|
1509
|
+
case "timer-sibling":
|
|
1510
|
+
return `wft_${id.runId}_timer_${id.stepId}_${id.attempt}_w${id.now}`;
|
|
1511
|
+
case "retry":
|
|
1512
|
+
return `wft_${id.runId}_retry_${id.stepId}_${id.attempt}`;
|
|
1513
|
+
case "respawn":
|
|
1514
|
+
return `wft_${id.runId}_respawn_${id.stepId}_${id.attempt}_s${id.segment}_r${id.now}`;
|
|
1515
|
+
case "redrive":
|
|
1516
|
+
return `wft_${id.runId}_redrive_${id.stepId}_${id.attempt}_r${id.now}`;
|
|
1517
|
+
case "redispatch":
|
|
1518
|
+
return `wft_${id.runId}_redispatch_${id.stepId}_${id.attempt}_x${id.executionId ?? "none"}_r${id.now}`;
|
|
1519
|
+
case "expiry":
|
|
1520
|
+
return `wft_${id.runId}_expire_${id.stepId}_${id.attempt}_t${id.suspendedAt}${id.hop > 0 ? `_h${id.hop}` : ""}`;
|
|
1521
|
+
case "step-terminal":
|
|
1522
|
+
return `wft_${id.runId}_term_${id.stepId}_${id.attempt}_r${id.now}`;
|
|
1523
|
+
case "handback":
|
|
1524
|
+
return `wft_${id.runId}_handback_${id.stepId}_${id.attempt}_${id.now}`;
|
|
1525
|
+
case "foreach-rate":
|
|
1526
|
+
return `wft_${id.runId}_fe_${id.stepId}_${id.attempt}_${id.bucket}`;
|
|
1527
|
+
case "budget-expiry":
|
|
1528
|
+
return `wft_${id.runId}_expiry_budget_r${id.now}`;
|
|
1529
|
+
case "budget-resume":
|
|
1530
|
+
return `wft_${id.runId}_resume_budget_${id.now}`;
|
|
1531
|
+
case "deadline":
|
|
1532
|
+
return `wft_${id.runId}_deadline_${id.deadlineAt}`;
|
|
1533
|
+
case "deadline-remainder":
|
|
1534
|
+
return `wft_${id.runId}_deadline_${id.deadlineAt}_r${id.now}`;
|
|
1535
|
+
case "readmit":
|
|
1536
|
+
return `wft_${id.runId}_readmit_${id.now}`;
|
|
1537
|
+
case "cancel":
|
|
1538
|
+
return `wft_${id.runId}_cancel`;
|
|
1539
|
+
case "reconcile":
|
|
1540
|
+
return `wft_${id.runId}_reconcile_${id.now}`;
|
|
1541
|
+
case "replay":
|
|
1542
|
+
return `wft_${id.runId}_replay_g${id.leaseGeneration}`;
|
|
1543
|
+
case "migration":
|
|
1544
|
+
return `wfm_${id.migrationId}`;
|
|
1545
|
+
default:
|
|
1546
|
+
return assertNever(id);
|
|
1547
|
+
}
|
|
1548
|
+
}
|
|
1549
|
+
__name(workflowJobId, "workflowJobId");
|
|
1550
|
+
__name2(workflowJobId, "workflowJobId");
|
|
1551
|
+
function assertNever(id) {
|
|
1552
|
+
throw new Error(`workflowJobId: unknown wake kind ${JSON.stringify(id)}`);
|
|
1553
|
+
}
|
|
1554
|
+
__name(assertNever, "assertNever");
|
|
1555
|
+
__name2(assertNever, "assertNever");
|
|
1556
|
+
function agentStepJobId(msg) {
|
|
1557
|
+
return `${msg.runId}_${msg.stepId}_${msg.attempt}_x${msg.executionId}`;
|
|
1558
|
+
}
|
|
1559
|
+
__name(agentStepJobId, "agentStepJobId");
|
|
1560
|
+
__name2(agentStepJobId, "agentStepJobId");
|
|
1561
|
+
function heavyStepJobId(msg) {
|
|
1562
|
+
return `${msg.runId}_${msg.stepId}_${msg.attempt}_x${msg.executionId}`;
|
|
1563
|
+
}
|
|
1564
|
+
__name(heavyStepJobId, "heavyStepJobId");
|
|
1565
|
+
__name2(heavyStepJobId, "heavyStepJobId");
|
|
1566
|
+
function jobSpawnJobId(msg) {
|
|
1567
|
+
return `${msg.runId}_${msg.stepId}_${msg.attempt}_s${msg.segment}_${msg.executionId}`;
|
|
1568
|
+
}
|
|
1569
|
+
__name(jobSpawnJobId, "jobSpawnJobId");
|
|
1570
|
+
__name2(jobSpawnJobId, "jobSpawnJobId");
|
|
1571
|
+
function exportAutoJobId(exportId, suffix) {
|
|
1572
|
+
return suffix ? `${exportId}:${suffix}` : exportId;
|
|
1573
|
+
}
|
|
1574
|
+
__name(exportAutoJobId, "exportAutoJobId");
|
|
1575
|
+
__name2(exportAutoJobId, "exportAutoJobId");
|
|
1492
1576
|
var SYSTEM_USER_PREFIX = "system:";
|
|
1493
1577
|
function isSystemRun(identity) {
|
|
1494
1578
|
return identity.userId.startsWith(SYSTEM_USER_PREFIX);
|
|
@@ -1620,8 +1704,199 @@ function scheduledWorkflowRunIdForTime(jobId, scheduledTime) {
|
|
|
1620
1704
|
__name(scheduledWorkflowRunIdForTime, "scheduledWorkflowRunIdForTime");
|
|
1621
1705
|
__name2(scheduledWorkflowRunIdForTime, "scheduledWorkflowRunIdForTime");
|
|
1622
1706
|
var WORKFLOW_SIGNAL_PAYLOAD_MAX_BYTES = 64 * 1024;
|
|
1707
|
+
var WORKFLOW_RESOLVE_OUTPUT_MAX_BYTES = 256 * 1024;
|
|
1708
|
+
var WORKFLOW_RETRY_BACKOFFS = [
|
|
1709
|
+
"fixed",
|
|
1710
|
+
"exponential"
|
|
1711
|
+
];
|
|
1712
|
+
var WORKFLOW_RETRY_MIN_ATTEMPTS = 1;
|
|
1713
|
+
var WORKFLOW_RETRY_POLICY_KEYS = [
|
|
1714
|
+
"maxAttempts",
|
|
1715
|
+
"backoffSeconds",
|
|
1716
|
+
"backoff",
|
|
1717
|
+
"maxBackoffSeconds"
|
|
1718
|
+
];
|
|
1719
|
+
var WORKFLOW_RETRY_MAX_ATTEMPTS = 20;
|
|
1720
|
+
function workflowRetryMaxAttemptsMessage(got) {
|
|
1721
|
+
const tail = got === void 0 ? "" : ` (got ${JSON.stringify(got)})`;
|
|
1722
|
+
return `\`retry.maxAttempts\` must be an integer ${WORKFLOW_RETRY_MIN_ATTEMPTS}..${WORKFLOW_RETRY_MAX_ATTEMPTS}${tail}`;
|
|
1723
|
+
}
|
|
1724
|
+
__name(workflowRetryMaxAttemptsMessage, "workflowRetryMaxAttemptsMessage");
|
|
1725
|
+
__name2(workflowRetryMaxAttemptsMessage, "workflowRetryMaxAttemptsMessage");
|
|
1726
|
+
function isWithinWorkflowRetryAttempts(value3) {
|
|
1727
|
+
return typeof value3 === "number" && Number.isInteger(value3) && value3 >= WORKFLOW_RETRY_MIN_ATTEMPTS && value3 <= WORKFLOW_RETRY_MAX_ATTEMPTS;
|
|
1728
|
+
}
|
|
1729
|
+
__name(isWithinWorkflowRetryAttempts, "isWithinWorkflowRetryAttempts");
|
|
1730
|
+
__name2(isWithinWorkflowRetryAttempts, "isWithinWorkflowRetryAttempts");
|
|
1731
|
+
var WORKFLOW_RETRY_ENGINE_KEYS = [
|
|
1732
|
+
"budgetBaseAttempt"
|
|
1733
|
+
];
|
|
1734
|
+
function workflowRetryUnknownMembersMessage(keys) {
|
|
1735
|
+
const named = keys.map((k) => {
|
|
1736
|
+
const engine = WORKFLOW_RETRY_ENGINE_KEYS.includes(k);
|
|
1737
|
+
return `\`${k}\`${engine ? " (engine-owned \u2014 stamped by resetAttempts, never authored)" : ""}`;
|
|
1738
|
+
});
|
|
1739
|
+
return `\`retry\` has no member ${named.join(", ")}; members: ${WORKFLOW_RETRY_POLICY_KEYS.join(", ")}`;
|
|
1740
|
+
}
|
|
1741
|
+
__name(workflowRetryUnknownMembersMessage, "workflowRetryUnknownMembersMessage");
|
|
1742
|
+
__name2(workflowRetryUnknownMembersMessage, "workflowRetryUnknownMembersMessage");
|
|
1743
|
+
function unknownWorkflowRetryMembers(retry) {
|
|
1744
|
+
if (!retry || typeof retry !== "object" || Array.isArray(retry)) return [];
|
|
1745
|
+
return Object.keys(retry).filter((k) => !WORKFLOW_RETRY_POLICY_KEYS.includes(k));
|
|
1746
|
+
}
|
|
1747
|
+
__name(unknownWorkflowRetryMembers, "unknownWorkflowRetryMembers");
|
|
1748
|
+
__name2(unknownWorkflowRetryMembers, "unknownWorkflowRetryMembers");
|
|
1749
|
+
function authoredRetryPolicy(retry) {
|
|
1750
|
+
if (!retry || typeof retry !== "object" || Array.isArray(retry)) return void 0;
|
|
1751
|
+
const src = retry;
|
|
1752
|
+
const out = {};
|
|
1753
|
+
for (const k of WORKFLOW_RETRY_POLICY_KEYS) if (src[k] !== void 0) out[k] = src[k];
|
|
1754
|
+
return Object.keys(out).length ? out : void 0;
|
|
1755
|
+
}
|
|
1756
|
+
__name(authoredRetryPolicy, "authoredRetryPolicy");
|
|
1757
|
+
__name2(authoredRetryPolicy, "authoredRetryPolicy");
|
|
1758
|
+
function retryBudgetBaseAttempt(row) {
|
|
1759
|
+
const base = row.retry?.budgetBaseAttempt;
|
|
1760
|
+
return typeof base === "number" && Number.isSafeInteger(base) && base > 0 ? base : 0;
|
|
1761
|
+
}
|
|
1762
|
+
__name(retryBudgetBaseAttempt, "retryBudgetBaseAttempt");
|
|
1763
|
+
__name2(retryBudgetBaseAttempt, "retryBudgetBaseAttempt");
|
|
1764
|
+
function retryBudgetAttempt(row) {
|
|
1765
|
+
return Math.max(0, row.attempt - retryBudgetBaseAttempt(row));
|
|
1766
|
+
}
|
|
1767
|
+
__name(retryBudgetAttempt, "retryBudgetAttempt");
|
|
1768
|
+
__name2(retryBudgetAttempt, "retryBudgetAttempt");
|
|
1769
|
+
function retryBudgetMaxAttempts(row) {
|
|
1770
|
+
const max = row.retry?.maxAttempts;
|
|
1771
|
+
return typeof max === "number" && Number.isFinite(max) && max >= 1 ? max : 1;
|
|
1772
|
+
}
|
|
1773
|
+
__name(retryBudgetMaxAttempts, "retryBudgetMaxAttempts");
|
|
1774
|
+
__name2(retryBudgetMaxAttempts, "retryBudgetMaxAttempts");
|
|
1775
|
+
function retryBudgetRemaining(row) {
|
|
1776
|
+
return retryBudgetAttempt(row) < retryBudgetMaxAttempts(row);
|
|
1777
|
+
}
|
|
1778
|
+
__name(retryBudgetRemaining, "retryBudgetRemaining");
|
|
1779
|
+
__name2(retryBudgetRemaining, "retryBudgetRemaining");
|
|
1780
|
+
function retriesRemaining(row) {
|
|
1781
|
+
return Math.max(0, retryBudgetMaxAttempts(row) - retryBudgetAttempt(row));
|
|
1782
|
+
}
|
|
1783
|
+
__name(retriesRemaining, "retriesRemaining");
|
|
1784
|
+
__name2(retriesRemaining, "retriesRemaining");
|
|
1785
|
+
var WORKFLOW_JOB_RESOURCES = [
|
|
1786
|
+
"small",
|
|
1787
|
+
"medium",
|
|
1788
|
+
"large"
|
|
1789
|
+
];
|
|
1790
|
+
var WORKFLOW_SIDE_EFFECTS = [
|
|
1791
|
+
"none",
|
|
1792
|
+
"external"
|
|
1793
|
+
];
|
|
1794
|
+
var WORKFLOW_JOB_RANGES = Object.freeze({
|
|
1795
|
+
/** Coding-turn cap (`claude -p --max-turns`); absent ⇒ the cluster default (LUA_WF_JOB_MAX_TURNS). */
|
|
1796
|
+
maxTurns: Object.freeze({
|
|
1797
|
+
min: 1,
|
|
1798
|
+
max: 500
|
|
1799
|
+
}),
|
|
1800
|
+
/** Harness messages per attempt (one per content block); absent ⇒ the cluster default (400). */
|
|
1801
|
+
maxMessages: Object.freeze({
|
|
1802
|
+
min: 1,
|
|
1803
|
+
max: 5e3
|
|
1804
|
+
}),
|
|
1805
|
+
/** Input-side tokens per attempt (prompt + cache); absent ⇒ the cluster default (4M — LUA-708, was 30M). */
|
|
1806
|
+
maxInputTokens: Object.freeze({
|
|
1807
|
+
min: 1e6,
|
|
1808
|
+
max: 5e8
|
|
1809
|
+
})
|
|
1810
|
+
});
|
|
1811
|
+
var WORKFLOW_JOB_RANGE_MEMBERS = Object.keys(WORKFLOW_JOB_RANGES);
|
|
1812
|
+
function isWithinWorkflowJobRange(member, value3) {
|
|
1813
|
+
const { min, max } = WORKFLOW_JOB_RANGES[member];
|
|
1814
|
+
return typeof value3 === "number" && Number.isInteger(value3) && value3 >= min && value3 <= max;
|
|
1815
|
+
}
|
|
1816
|
+
__name(isWithinWorkflowJobRange, "isWithinWorkflowJobRange");
|
|
1817
|
+
__name2(isWithinWorkflowJobRange, "isWithinWorkflowJobRange");
|
|
1818
|
+
function workflowJobRangeMessage(member) {
|
|
1819
|
+
const { min, max } = WORKFLOW_JOB_RANGES[member];
|
|
1820
|
+
return `\`${member}\` must be an integer ${min}..${max}`;
|
|
1821
|
+
}
|
|
1822
|
+
__name(workflowJobRangeMessage, "workflowJobRangeMessage");
|
|
1823
|
+
__name2(workflowJobRangeMessage, "workflowJobRangeMessage");
|
|
1824
|
+
var WORKFLOW_SINGLE_STEP_TYPES = [
|
|
1825
|
+
"agent",
|
|
1826
|
+
"tool",
|
|
1827
|
+
"workflow",
|
|
1828
|
+
"step"
|
|
1829
|
+
];
|
|
1830
|
+
var WORKFLOW_HITL_ENTRY_TYPES = [
|
|
1831
|
+
"approval",
|
|
1832
|
+
"waitForSignal"
|
|
1833
|
+
];
|
|
1834
|
+
var WORKFLOW_ARM_ENTRY_TYPES = [
|
|
1835
|
+
...WORKFLOW_SINGLE_STEP_TYPES,
|
|
1836
|
+
...WORKFLOW_HITL_ENTRY_TYPES
|
|
1837
|
+
];
|
|
1838
|
+
var WORKFLOW_HITL_ARM_CONTAINERS = [
|
|
1839
|
+
"parallel",
|
|
1840
|
+
"conditional",
|
|
1841
|
+
"foreach"
|
|
1842
|
+
];
|
|
1843
|
+
function isWorkflowSingleStepType(type) {
|
|
1844
|
+
return typeof type === "string" && WORKFLOW_SINGLE_STEP_TYPES.includes(type);
|
|
1845
|
+
}
|
|
1846
|
+
__name(isWorkflowSingleStepType, "isWorkflowSingleStepType");
|
|
1847
|
+
__name2(isWorkflowSingleStepType, "isWorkflowSingleStepType");
|
|
1848
|
+
function isWorkflowHitlEntryType(type) {
|
|
1849
|
+
return typeof type === "string" && WORKFLOW_HITL_ENTRY_TYPES.includes(type);
|
|
1850
|
+
}
|
|
1851
|
+
__name(isWorkflowHitlEntryType, "isWorkflowHitlEntryType");
|
|
1852
|
+
__name2(isWorkflowHitlEntryType, "isWorkflowHitlEntryType");
|
|
1853
|
+
function isWorkflowArmEntryType(type) {
|
|
1854
|
+
return typeof type === "string" && WORKFLOW_ARM_ENTRY_TYPES.includes(type);
|
|
1855
|
+
}
|
|
1856
|
+
__name(isWorkflowArmEntryType, "isWorkflowArmEntryType");
|
|
1857
|
+
__name2(isWorkflowArmEntryType, "isWorkflowArmEntryType");
|
|
1858
|
+
function workflowContainerRunsHitlArm(container) {
|
|
1859
|
+
return typeof container === "string" && WORKFLOW_HITL_ARM_CONTAINERS.includes(container);
|
|
1860
|
+
}
|
|
1861
|
+
__name(workflowContainerRunsHitlArm, "workflowContainerRunsHitlArm");
|
|
1862
|
+
__name2(workflowContainerRunsHitlArm, "workflowContainerRunsHitlArm");
|
|
1863
|
+
function workflowHitlArmUnsupportedMessage(type, id, container) {
|
|
1864
|
+
const legal = WORKFLOW_HITL_ARM_CONTAINERS.map((c) => `\`${c}\``).join(" / ");
|
|
1865
|
+
return `the engine does not run \`${type}\` inside a \`${container}\` yet (node "${id}") \u2014 place it at the top level, as a ${legal} arm, or inside a child \`workflow\``;
|
|
1866
|
+
}
|
|
1867
|
+
__name(workflowHitlArmUnsupportedMessage, "workflowHitlArmUnsupportedMessage");
|
|
1868
|
+
__name2(workflowHitlArmUnsupportedMessage, "workflowHitlArmUnsupportedMessage");
|
|
1869
|
+
function workflowHitlArmShapeMessage(type, id, shape) {
|
|
1870
|
+
return shape === "mapped-arm" ? `\`${type}\` arm "${id}" takes the previous output as its payload \u2014 it cannot head a [mapping, step] chain; map before the container instead` : `a chunked foreach hands each child a slice of items, not one \u2014 \`${type}\` body "${id}" takes one item; drop \`chunk\``;
|
|
1871
|
+
}
|
|
1872
|
+
__name(workflowHitlArmShapeMessage, "workflowHitlArmShapeMessage");
|
|
1873
|
+
__name2(workflowHitlArmShapeMessage, "workflowHitlArmShapeMessage");
|
|
1874
|
+
var WORKFLOW_GRAPH_ENTRY_STEP_KINDS = Object.freeze({
|
|
1875
|
+
agent: "agent",
|
|
1876
|
+
tool: "tool",
|
|
1877
|
+
workflow: "subrun",
|
|
1878
|
+
step: "code",
|
|
1879
|
+
mapping: "map",
|
|
1880
|
+
sleep: "sleep",
|
|
1881
|
+
sleepUntil: "sleepUntil",
|
|
1882
|
+
parallel: null,
|
|
1883
|
+
conditional: "branch",
|
|
1884
|
+
foreach: "foreach",
|
|
1885
|
+
loop: "loop",
|
|
1886
|
+
approval: "approval",
|
|
1887
|
+
waitForSignal: "signal"
|
|
1888
|
+
});
|
|
1889
|
+
var WORKFLOW_ARM_ENTRY_STEP_KINDS = Object.freeze(Object.fromEntries(WORKFLOW_ARM_ENTRY_TYPES.map((t) => [
|
|
1890
|
+
t,
|
|
1891
|
+
WORKFLOW_GRAPH_ENTRY_STEP_KINDS[t]
|
|
1892
|
+
])));
|
|
1893
|
+
var WORKFLOW_BUDGET_MAX_DURATION_SECONDS = Object.freeze({
|
|
1894
|
+
min: 60,
|
|
1895
|
+
max: 2592e3
|
|
1896
|
+
});
|
|
1623
1897
|
var REDACTED_PLACEHOLDER = "[REDACTED]";
|
|
1624
1898
|
var PROVIDER_MESSAGE_MAX_CHARS = 300;
|
|
1899
|
+
var ERROR_MESSAGE_MAX_CHARS = 2e3;
|
|
1625
1900
|
var SECRET_LITERAL_PATTERNS = [
|
|
1626
1901
|
{
|
|
1627
1902
|
re: /\b(github_pat_)[A-Za-z0-9_]{16,}/g
|
|
@@ -1632,6 +1907,10 @@ var SECRET_LITERAL_PATTERNS = [
|
|
|
1632
1907
|
{
|
|
1633
1908
|
re: /\b(glpat-)[A-Za-z0-9_-]{16,}/g
|
|
1634
1909
|
},
|
|
1910
|
+
// LUA-696 review (3): the npm granular / classic token (`npm_` + 36 alphanumerics).
|
|
1911
|
+
{
|
|
1912
|
+
re: /\b(npm_)[A-Za-z0-9]{36}\b/g
|
|
1913
|
+
},
|
|
1635
1914
|
{
|
|
1636
1915
|
re: /\b(sk-ant-)[A-Za-z0-9_-]{16,}/g
|
|
1637
1916
|
},
|
|
@@ -1668,8 +1947,15 @@ var SECRET_PAIR_PATTERNS = [
|
|
|
1668
1947
|
// `FOO_TOKEN=x`, `secretKey=x`, `password=x`. Groups: the char before the name, the name, the separator
|
|
1669
1948
|
// (with its quotes), the scheme word — all kept; the value goes. A value a literal rule already replaced
|
|
1670
1949
|
// (`x-access-token:[REDACTED]@host`) is left alone so the host after it survives.
|
|
1950
|
+
// LUA-696: the second lookahead keeps a scrubbed `Authorization: Bearer [REDACTED]` as it is — without it the
|
|
1951
|
+
// optional scheme group backtracks to empty and `Bearer` itself becomes the value (`[REDACTED] [REDACTED]`).
|
|
1952
|
+
// The scrub is applied more than once on purpose (the Job site at its copy, the outcome table at the row
|
|
1953
|
+
// write, lua-api on the way out), so it must be idempotent.
|
|
1954
|
+
// LUA-696 review (HIGH): the identifier prefix is BOUNDED (`{1,64}`) — unbounded, `[A-Za-z0-9-]+` made the
|
|
1955
|
+
// scan quadratic on `-`-heavy text (100 KB of `-` took 12.7 s on the lua-core event loop; a worker-tier step
|
|
1956
|
+
// can throw that). No identifier that names a credential is longer; the probe list is unchanged.
|
|
1671
1957
|
{
|
|
1672
|
-
re: new RegExp(`(^|[^A-Za-z0-9])((?:[A-Za-z0-9-]
|
|
1958
|
+
re: new RegExp(`(^|[^A-Za-z0-9])((?:[A-Za-z0-9-]{1,64}[_-])?${SECRET_NAME}|[A-Za-z0-9-]{1,64}_key)(["']?\\s*[:=]\\s*["']?)((?:basic\\s+|bearer\\s+|token\\s+)?)(?!\\[REDACTED\\]|(?:basic|bearer|token)\\s+\\[REDACTED\\])[^\\s"',;)}&]{4,}`, "gi")
|
|
1673
1959
|
},
|
|
1674
1960
|
// `?token=x`, `&key=x`, `&X-Amz-Signature=x`, `&sig=x`
|
|
1675
1961
|
{
|
|
@@ -1696,6 +1982,34 @@ function groupCount(re) {
|
|
|
1696
1982
|
}
|
|
1697
1983
|
__name(groupCount, "groupCount");
|
|
1698
1984
|
__name2(groupCount, "groupCount");
|
|
1985
|
+
var WORKFLOW_SECRET_KEY_RE = /(^|[_\-.\s])(secret|token|password|passwd|pwd|passphrase|api[_-]?key|apikey|access[_-]?key|secret[_-]?key|private[_-]?key|client[_-]?secret|authorization|auth[_-]?token|access[_-]?token|id[_-]?token|refresh[_-]?token|session[_-]?key|credential(s)?)([_\-.\s]|$)|^(secret|token|password|passwd|pwd|passphrase|apikey|authorization|credentials?)$/i;
|
|
1986
|
+
var WORKFLOW_RESERVED_SECRET_KEYS = Object.freeze([
|
|
1987
|
+
"secret",
|
|
1988
|
+
"token",
|
|
1989
|
+
"password",
|
|
1990
|
+
"passwd",
|
|
1991
|
+
"pwd",
|
|
1992
|
+
"passphrase",
|
|
1993
|
+
"api_key",
|
|
1994
|
+
"apikey",
|
|
1995
|
+
"access_key",
|
|
1996
|
+
"secret_key",
|
|
1997
|
+
"private_key",
|
|
1998
|
+
"client_secret",
|
|
1999
|
+
"authorization",
|
|
2000
|
+
"auth_token",
|
|
2001
|
+
"access_token",
|
|
2002
|
+
"id_token",
|
|
2003
|
+
"refresh_token",
|
|
2004
|
+
"session_key",
|
|
2005
|
+
"credential",
|
|
2006
|
+
"credentials"
|
|
2007
|
+
]);
|
|
2008
|
+
function isWorkflowSecretKey(key) {
|
|
2009
|
+
return WORKFLOW_SECRET_KEY_RE.test(key);
|
|
2010
|
+
}
|
|
2011
|
+
__name(isWorkflowSecretKey, "isWorkflowSecretKey");
|
|
2012
|
+
__name2(isWorkflowSecretKey, "isWorkflowSecretKey");
|
|
1699
2013
|
function applyPatterns(text, patterns) {
|
|
1700
2014
|
let out = text;
|
|
1701
2015
|
for (const { re, suffix } of patterns) {
|
|
@@ -1722,8 +2036,19 @@ function scrubSecretText(text) {
|
|
|
1722
2036
|
}
|
|
1723
2037
|
__name(scrubSecretText, "scrubSecretText");
|
|
1724
2038
|
__name2(scrubSecretText, "scrubSecretText");
|
|
2039
|
+
var SCRUB_INPUT_MAX_CHARS = 16 * 1024;
|
|
2040
|
+
var SCRUB_CUT_BACKOFF_CHARS = 256;
|
|
2041
|
+
function boundScrubInput(text, max = SCRUB_INPUT_MAX_CHARS) {
|
|
2042
|
+
if (typeof text !== "string" || text.length <= max) return text;
|
|
2043
|
+
const window = text.slice(Math.max(0, max - SCRUB_CUT_BACKOFF_CHARS), max);
|
|
2044
|
+
const ws = window.search(/\s\S*$/);
|
|
2045
|
+
const cut = ws >= 0 ? max - window.length + ws : max;
|
|
2046
|
+
return `${text.slice(0, cut)}\u2026`;
|
|
2047
|
+
}
|
|
2048
|
+
__name(boundScrubInput, "boundScrubInput");
|
|
2049
|
+
__name2(boundScrubInput, "boundScrubInput");
|
|
1725
2050
|
function scrubSecretLines(lines) {
|
|
1726
|
-
return lines.map((l) => typeof l === "string" ? scrubSecretText(l) : l);
|
|
2051
|
+
return lines.map((l) => typeof l === "string" ? scrubSecretText(boundScrubInput(l)) : l);
|
|
1727
2052
|
}
|
|
1728
2053
|
__name(scrubSecretLines, "scrubSecretLines");
|
|
1729
2054
|
__name2(scrubSecretLines, "scrubSecretLines");
|
|
@@ -1744,13 +2069,18 @@ function messageText(value3) {
|
|
|
1744
2069
|
__name(messageText, "messageText");
|
|
1745
2070
|
__name2(messageText, "messageText");
|
|
1746
2071
|
function scrubProviderMessage(raw, max = PROVIDER_MESSAGE_MAX_CHARS) {
|
|
1747
|
-
const text = messageText(raw).replace(/\s+/g, " ").trim();
|
|
2072
|
+
const text = boundScrubInput(messageText(raw)).replace(/\s+/g, " ").trim();
|
|
1748
2073
|
if (!text) return void 0;
|
|
1749
2074
|
const out = scrubSecretText(text);
|
|
1750
2075
|
return out.length > max ? `${out.slice(0, max - 1)}\u2026` : out;
|
|
1751
2076
|
}
|
|
1752
2077
|
__name(scrubProviderMessage, "scrubProviderMessage");
|
|
1753
2078
|
__name2(scrubProviderMessage, "scrubProviderMessage");
|
|
2079
|
+
function scrubStepErrorMessage(raw) {
|
|
2080
|
+
return scrubProviderMessage(raw, ERROR_MESSAGE_MAX_CHARS);
|
|
2081
|
+
}
|
|
2082
|
+
__name(scrubStepErrorMessage, "scrubStepErrorMessage");
|
|
2083
|
+
__name2(scrubStepErrorMessage, "scrubStepErrorMessage");
|
|
1754
2084
|
var WORKFLOW_AUDIT_EVENTS = [
|
|
1755
2085
|
// --- definitions / versions / templates (13, 11 §11.11.5) ---
|
|
1756
2086
|
"workflow.published",
|
|
@@ -1817,6 +2147,8 @@ var WORKFLOW_AUDIT_EVENTS = [
|
|
|
1817
2147
|
"workflow.goal.resumed",
|
|
1818
2148
|
"workflow.goal.done",
|
|
1819
2149
|
"workflow.goal.closed",
|
|
2150
|
+
// LUA-760: an ended goal's cadence Job retired (deleted) — inline on done / closed, by R21 / R28, or by sweep #30
|
|
2151
|
+
"workflow.goal.job_retired",
|
|
1820
2152
|
// --- org policy (02 §2.10 / 09 R23) ---
|
|
1821
2153
|
"workflow.policy.retention_changed",
|
|
1822
2154
|
"workflow.policy.pacing_changed",
|
|
@@ -1960,475 +2292,940 @@ ${items.join("\n\n")}`;
|
|
|
1960
2292
|
}
|
|
1961
2293
|
__name(renderTargetsBlock, "renderTargetsBlock");
|
|
1962
2294
|
__name2(renderTargetsBlock, "renderTargetsBlock");
|
|
2295
|
+
var WORKFLOW_APPROVAL_OUTPUT_DECISIONS = [
|
|
2296
|
+
"approved",
|
|
2297
|
+
"denied",
|
|
2298
|
+
"timed_out"
|
|
2299
|
+
];
|
|
2300
|
+
var WORKFLOW_APPROVAL_OUTPUT_SCHEMA = {
|
|
2301
|
+
type: "object",
|
|
2302
|
+
properties: {
|
|
2303
|
+
approved: {
|
|
2304
|
+
type: "boolean"
|
|
2305
|
+
},
|
|
2306
|
+
decision: {
|
|
2307
|
+
type: "string",
|
|
2308
|
+
enum: [
|
|
2309
|
+
...WORKFLOW_APPROVAL_OUTPUT_DECISIONS
|
|
2310
|
+
]
|
|
2311
|
+
},
|
|
2312
|
+
/** the approver's note when given, else the decision word — what `${stepResults.<id>.text}` reads */
|
|
2313
|
+
text: {
|
|
2314
|
+
type: "string"
|
|
2315
|
+
},
|
|
2316
|
+
note: {
|
|
2317
|
+
type: "string"
|
|
2318
|
+
},
|
|
2319
|
+
editedPayload: {},
|
|
2320
|
+
editRevision: {
|
|
2321
|
+
type: "integer"
|
|
2322
|
+
},
|
|
2323
|
+
decidedBy: {
|
|
2324
|
+
type: "object",
|
|
2325
|
+
properties: {
|
|
2326
|
+
id: {
|
|
2327
|
+
type: "string"
|
|
2328
|
+
},
|
|
2329
|
+
kind: {
|
|
2330
|
+
type: "string"
|
|
2331
|
+
}
|
|
2332
|
+
}
|
|
2333
|
+
},
|
|
2334
|
+
timedOut: {
|
|
2335
|
+
type: "boolean"
|
|
2336
|
+
},
|
|
2337
|
+
escalations: {
|
|
2338
|
+
type: "integer"
|
|
2339
|
+
},
|
|
2340
|
+
evidence: {
|
|
2341
|
+
type: "array",
|
|
2342
|
+
items: {
|
|
2343
|
+
type: "string"
|
|
2344
|
+
}
|
|
2345
|
+
},
|
|
2346
|
+
items: {
|
|
2347
|
+
type: "array",
|
|
2348
|
+
items: {
|
|
2349
|
+
type: "object"
|
|
2350
|
+
}
|
|
2351
|
+
}
|
|
2352
|
+
},
|
|
2353
|
+
required: [
|
|
2354
|
+
"approved",
|
|
2355
|
+
"decision",
|
|
2356
|
+
"text"
|
|
2357
|
+
]
|
|
2358
|
+
};
|
|
2359
|
+
function workflowApprovalDecisionOf(resumeData) {
|
|
2360
|
+
if (resumeData.timedOut === true) return "timed_out";
|
|
2361
|
+
return resumeData.approved === true ? "approved" : "denied";
|
|
2362
|
+
}
|
|
2363
|
+
__name(workflowApprovalDecisionOf, "workflowApprovalDecisionOf");
|
|
2364
|
+
__name2(workflowApprovalDecisionOf, "workflowApprovalDecisionOf");
|
|
2365
|
+
function workflowApprovalOutput(resumeData) {
|
|
2366
|
+
const decision = typeof resumeData.decision === "string" ? resumeData.decision : workflowApprovalDecisionOf(resumeData);
|
|
2367
|
+
const note = typeof resumeData.note === "string" && resumeData.note.trim() !== "" ? resumeData.note : void 0;
|
|
2368
|
+
const text = typeof resumeData.text === "string" ? resumeData.text : note ?? decision;
|
|
2369
|
+
return {
|
|
2370
|
+
...resumeData,
|
|
2371
|
+
decision,
|
|
2372
|
+
text
|
|
2373
|
+
};
|
|
2374
|
+
}
|
|
2375
|
+
__name(workflowApprovalOutput, "workflowApprovalOutput");
|
|
2376
|
+
__name2(workflowApprovalOutput, "workflowApprovalOutput");
|
|
2377
|
+
function isWorkflowApprovalOutput(value3) {
|
|
2378
|
+
if (typeof value3 !== "object" || value3 === null || Array.isArray(value3)) return false;
|
|
2379
|
+
const v = value3;
|
|
2380
|
+
return typeof v.approved === "boolean" && WORKFLOW_APPROVAL_OUTPUT_DECISIONS.includes(v.decision) && typeof v.text === "string";
|
|
2381
|
+
}
|
|
2382
|
+
__name(isWorkflowApprovalOutput, "isWorkflowApprovalOutput");
|
|
2383
|
+
__name2(isWorkflowApprovalOutput, "isWorkflowApprovalOutput");
|
|
2384
|
+
var JSON_FENCE_RE = /```(?:json)?[ \t]*\r?\n([\s\S]*?)\r?\n?```/g;
|
|
2385
|
+
function extractSingleJsonValue(text) {
|
|
2386
|
+
const trimmed = (text ?? "").trim();
|
|
2387
|
+
if (!trimmed) return {
|
|
2388
|
+
reason: "reply is empty"
|
|
2389
|
+
};
|
|
2390
|
+
const fenced = [
|
|
2391
|
+
...trimmed.matchAll(JSON_FENCE_RE)
|
|
2392
|
+
];
|
|
2393
|
+
if (fenced.length > 1) return {
|
|
2394
|
+
reason: "reply carries more than one fenced block"
|
|
2395
|
+
};
|
|
2396
|
+
const candidate = fenced.length === 1 ? fenced[0][1].trim() : trimmed;
|
|
2397
|
+
try {
|
|
2398
|
+
return {
|
|
2399
|
+
value: JSON.parse(candidate)
|
|
2400
|
+
};
|
|
2401
|
+
} catch {
|
|
2402
|
+
if (fenced.length === 1) return {
|
|
2403
|
+
reason: "fenced block is not valid JSON"
|
|
2404
|
+
};
|
|
2405
|
+
}
|
|
2406
|
+
const opens = [
|
|
2407
|
+
trimmed.indexOf("{"),
|
|
2408
|
+
trimmed.indexOf("[")
|
|
2409
|
+
].filter((i) => i !== -1);
|
|
2410
|
+
const start = opens.length ? Math.min(...opens) : -1;
|
|
2411
|
+
const end = Math.max(trimmed.lastIndexOf("}"), trimmed.lastIndexOf("]"));
|
|
2412
|
+
if (start === -1 || end <= start) return {
|
|
2413
|
+
reason: "reply is not JSON"
|
|
2414
|
+
};
|
|
2415
|
+
try {
|
|
2416
|
+
return {
|
|
2417
|
+
value: JSON.parse(trimmed.slice(start, end + 1))
|
|
2418
|
+
};
|
|
2419
|
+
} catch {
|
|
2420
|
+
return {
|
|
2421
|
+
reason: "reply does not contain a single JSON value"
|
|
2422
|
+
};
|
|
2423
|
+
}
|
|
2424
|
+
}
|
|
2425
|
+
__name(extractSingleJsonValue, "extractSingleJsonValue");
|
|
2426
|
+
__name2(extractSingleJsonValue, "extractSingleJsonValue");
|
|
1963
2427
|
|
|
1964
2428
|
// ../workflow-graph/dist/index.mjs
|
|
2429
|
+
import { createHash } from "crypto";
|
|
1965
2430
|
import { z as z4 } from "zod";
|
|
1966
2431
|
import { z as z22 } from "zod";
|
|
1967
2432
|
import { createHash as createHash2 } from "crypto";
|
|
1968
2433
|
var __defProp3 = Object.defineProperty;
|
|
1969
2434
|
var __name3 = /* @__PURE__ */ __name((target, value22) => __defProp3(target, "name", { value: value22, configurable: true }), "__name");
|
|
1970
|
-
var
|
|
1971
|
-
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
});
|
|
1986
|
-
function sleepUntilUnsupportedMessage(id) {
|
|
1987
|
-
return `the engine does not execute \`sleepUntil\` yet (node "${id}") \u2014 replace it with a \`sleep\` node with a \`duration\` in ms, e.g. { type: 'sleep', id: '${id}', duration: ${SLEEP_UNTIL_REPLACEMENT.duration} }`;
|
|
2435
|
+
var WorkflowTemplateError = class extends Error {
|
|
2436
|
+
static {
|
|
2437
|
+
__name(this, "WorkflowTemplateError");
|
|
2438
|
+
}
|
|
2439
|
+
static {
|
|
2440
|
+
__name3(this, "WorkflowTemplateError");
|
|
2441
|
+
}
|
|
2442
|
+
placeholder;
|
|
2443
|
+
constructor(message, placeholder) {
|
|
2444
|
+
super(message), this.placeholder = placeholder;
|
|
2445
|
+
this.name = "WorkflowTemplateError";
|
|
2446
|
+
}
|
|
2447
|
+
};
|
|
2448
|
+
function isMapConfigObject(v) {
|
|
2449
|
+
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
1988
2450
|
}
|
|
1989
|
-
__name(
|
|
1990
|
-
__name3(
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
|
|
2010
|
-
|
|
2011
|
-
|
|
2012
|
-
|
|
2013
|
-
"
|
|
2451
|
+
__name(isMapConfigObject, "isMapConfigObject");
|
|
2452
|
+
__name3(isMapConfigObject, "isMapConfigObject");
|
|
2453
|
+
function parseMapConfig(raw, stepId) {
|
|
2454
|
+
if (isMapConfigObject(raw)) return raw;
|
|
2455
|
+
if (typeof raw !== "string") {
|
|
2456
|
+
throw new Error(`Stored mapping step "${stepId}" has a mapConfig that is neither a JSON string nor an object.`);
|
|
2457
|
+
}
|
|
2458
|
+
try {
|
|
2459
|
+
return JSON.parse(raw);
|
|
2460
|
+
} catch (e) {
|
|
2461
|
+
throw new Error(`Stored mapping step "${stepId}" has invalid JSON mapConfig: ${e.message}`);
|
|
2462
|
+
}
|
|
2463
|
+
}
|
|
2464
|
+
__name(parseMapConfig, "parseMapConfig");
|
|
2465
|
+
__name3(parseMapConfig, "parseMapConfig");
|
|
2466
|
+
function mapConfigWire(raw) {
|
|
2467
|
+
if (typeof raw === "string") return raw;
|
|
2468
|
+
if (isMapConfigObject(raw)) return canonicalJson(raw);
|
|
2469
|
+
return void 0;
|
|
2470
|
+
}
|
|
2471
|
+
__name(mapConfigWire, "mapConfigWire");
|
|
2472
|
+
__name3(mapConfigWire, "mapConfigWire");
|
|
2473
|
+
var TEMPLATE_PLACEHOLDER = /\$\{([^}]*)\}/g;
|
|
2474
|
+
var TEMPLATE_NAMESPACES = [
|
|
2475
|
+
"initData",
|
|
2476
|
+
"state",
|
|
2477
|
+
"requestContext",
|
|
2478
|
+
"stepResults"
|
|
2014
2479
|
];
|
|
2015
|
-
|
|
2016
|
-
|
|
2017
|
-
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
|
|
2480
|
+
function describeBadPlaceholder(template22, idx, rawExpr) {
|
|
2481
|
+
return `Template placeholder #${idx} (\${${rawExpr}}) in '${template22}'`;
|
|
2482
|
+
}
|
|
2483
|
+
__name(describeBadPlaceholder, "describeBadPlaceholder");
|
|
2484
|
+
__name3(describeBadPlaceholder, "describeBadPlaceholder");
|
|
2485
|
+
function parseTemplatePlaceholder(rawExpr) {
|
|
2486
|
+
const dot = rawExpr.indexOf(".");
|
|
2487
|
+
return {
|
|
2488
|
+
scope: dot === -1 ? rawExpr : rawExpr.slice(0, dot),
|
|
2489
|
+
rest: dot === -1 ? "" : rawExpr.slice(dot + 1)
|
|
2021
2490
|
};
|
|
2022
|
-
if (node.onError === void 0) node.onError = "fail";
|
|
2023
|
-
if ((node.type === "step" || node.type === "tool") && node.sideEffects === void 0) node.sideEffects = "none";
|
|
2024
2491
|
}
|
|
2025
|
-
__name(
|
|
2026
|
-
__name3(
|
|
2027
|
-
function
|
|
2028
|
-
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
|
|
2492
|
+
__name(parseTemplatePlaceholder, "parseTemplatePlaceholder");
|
|
2493
|
+
__name3(parseTemplatePlaceholder, "parseTemplatePlaceholder");
|
|
2494
|
+
function traverseMappingPath(root, path, errorLabel) {
|
|
2495
|
+
if (path === "" || path === ".") return root;
|
|
2496
|
+
const parts = path.split(".");
|
|
2497
|
+
let value22 = root;
|
|
2498
|
+
for (const part of parts) {
|
|
2499
|
+
if (typeof value22 === "object" && value22 !== null) value22 = value22[part];
|
|
2500
|
+
else throw new WorkflowTemplateError(`Invalid path ${path} in ${errorLabel}`, path);
|
|
2501
|
+
}
|
|
2502
|
+
return value22;
|
|
2503
|
+
}
|
|
2504
|
+
__name(traverseMappingPath, "traverseMappingPath");
|
|
2505
|
+
__name3(traverseMappingPath, "traverseMappingPath");
|
|
2506
|
+
function stringifyTemplateValue(v, template22, idx, rawExpr) {
|
|
2507
|
+
if (v === null || v === void 0) return "";
|
|
2508
|
+
if (typeof v === "object") {
|
|
2509
|
+
try {
|
|
2510
|
+
return JSON.stringify(v);
|
|
2511
|
+
} catch (err) {
|
|
2512
|
+
throw new WorkflowTemplateError(`${describeBadPlaceholder(template22, idx, rawExpr)} resolved to a value that could not be JSON-stringified (${err.message}).`, rawExpr);
|
|
2035
2513
|
}
|
|
2036
|
-
case "agent":
|
|
2037
|
-
fillPolicy(node, WORKFLOW_AGENT_DEFAULT_TIMEOUT_SECONDS);
|
|
2038
|
-
return;
|
|
2039
|
-
case "tool":
|
|
2040
|
-
fillPolicy(node, WORKFLOW_STEP_DEFAULT_TIMEOUT_SECONDS);
|
|
2041
|
-
return;
|
|
2042
|
-
case "workflow":
|
|
2043
|
-
if (node.workflowId === WORKFLOW_ARM_SUBRUN_ID && Array.isArray(node.graph) && node.graph[1]) fillSingle(node.graph[1]);
|
|
2044
|
-
return;
|
|
2045
2514
|
}
|
|
2515
|
+
return String(v);
|
|
2046
2516
|
}
|
|
2047
|
-
__name(
|
|
2048
|
-
__name3(
|
|
2049
|
-
function
|
|
2050
|
-
|
|
2517
|
+
__name(stringifyTemplateValue, "stringifyTemplateValue");
|
|
2518
|
+
__name3(stringifyTemplateValue, "stringifyTemplateValue");
|
|
2519
|
+
function escapeFence(content) {
|
|
2520
|
+
return content.replace(/<\/lua-data/g, "<\\/lua-data");
|
|
2051
2521
|
}
|
|
2052
|
-
__name(
|
|
2053
|
-
__name3(
|
|
2054
|
-
function
|
|
2055
|
-
|
|
2056
|
-
case "step":
|
|
2057
|
-
case "agent":
|
|
2058
|
-
case "tool":
|
|
2059
|
-
case "workflow":
|
|
2060
|
-
fillSingle(entry);
|
|
2061
|
-
return;
|
|
2062
|
-
case "parallel":
|
|
2063
|
-
entry.steps.forEach(fillSingle);
|
|
2064
|
-
return;
|
|
2065
|
-
case "conditional": {
|
|
2066
|
-
const c = entry;
|
|
2067
|
-
if (c.exclusive === void 0) c.exclusive = false;
|
|
2068
|
-
c.steps.forEach(fillArm);
|
|
2069
|
-
if (c.otherwise) fillArm(c.otherwise);
|
|
2070
|
-
return;
|
|
2071
|
-
}
|
|
2072
|
-
case "foreach": {
|
|
2073
|
-
const f = entry;
|
|
2074
|
-
f.opts = f.opts ?? {};
|
|
2075
|
-
if (f.opts.concurrency === void 0) f.opts.concurrency = WORKFLOW_FOREACH_DEFAULT_CONCURRENCY;
|
|
2076
|
-
if (f.opts.maxItems === void 0) f.opts.maxItems = WORKFLOW_FOREACH_DEFAULT_MAX_ITEMS;
|
|
2077
|
-
fillSingle(f.step);
|
|
2078
|
-
return;
|
|
2079
|
-
}
|
|
2080
|
-
case "loop": {
|
|
2081
|
-
const l = entry;
|
|
2082
|
-
if (l.maxIterations === void 0) l.maxIterations = WORKFLOW_LOOP_DEFAULT_MAX_ITERATIONS;
|
|
2083
|
-
fillSingle(l.step);
|
|
2084
|
-
return;
|
|
2085
|
-
}
|
|
2086
|
-
case "approval": {
|
|
2087
|
-
const a = entry;
|
|
2088
|
-
if (a.approver === void 0) a.approver = "creator";
|
|
2089
|
-
if (a.timeoutHours === void 0) a.timeoutHours = WORKFLOW_SUSPEND_DEFAULT_TIMEOUT_HOURS;
|
|
2090
|
-
if (a.onTimeout === void 0) a.onTimeout = "deny";
|
|
2091
|
-
if (a.onDeny === void 0) a.onDeny = "continue";
|
|
2092
|
-
if (a.excludeInitiator === void 0) a.excludeInitiator = false;
|
|
2093
|
-
if (a.editable === void 0) a.editable = false;
|
|
2094
|
-
return;
|
|
2095
|
-
}
|
|
2096
|
-
case "waitForSignal": {
|
|
2097
|
-
const w = entry;
|
|
2098
|
-
if (w.timeoutHours === void 0) w.timeoutHours = WORKFLOW_SUSPEND_DEFAULT_TIMEOUT_HOURS;
|
|
2099
|
-
if (w.onTimeout === void 0) w.onTimeout = "fail";
|
|
2100
|
-
if (w.acceptedSources === void 0) w.acceptedSources = [
|
|
2101
|
-
...WORKFLOW_SIGNAL_DEFAULT_SOURCES
|
|
2102
|
-
];
|
|
2103
|
-
return;
|
|
2104
|
-
}
|
|
2105
|
-
case "mapping":
|
|
2106
|
-
case "sleep":
|
|
2107
|
-
case "sleepUntil":
|
|
2108
|
-
return;
|
|
2109
|
-
}
|
|
2110
|
-
}
|
|
2111
|
-
__name(fillEntry, "fillEntry");
|
|
2112
|
-
__name3(fillEntry, "fillEntry");
|
|
2113
|
-
function withDefaultsFilled(g) {
|
|
2114
|
-
const out = clone(g);
|
|
2115
|
-
out.definition.graph.forEach(fillEntry);
|
|
2116
|
-
return out;
|
|
2522
|
+
__name(escapeFence, "escapeFence");
|
|
2523
|
+
__name3(escapeFence, "escapeFence");
|
|
2524
|
+
function fenceBlock(name, source, content) {
|
|
2525
|
+
return `<lua-data name="${name}" source="${source}" untrusted="true">${escapeFence(content)}</lua-data>`;
|
|
2117
2526
|
}
|
|
2118
|
-
__name(
|
|
2119
|
-
__name3(
|
|
2120
|
-
|
|
2121
|
-
|
|
2122
|
-
return
|
|
2527
|
+
__name(fenceBlock, "fenceBlock");
|
|
2528
|
+
__name3(fenceBlock, "fenceBlock");
|
|
2529
|
+
function renderTemplate(template22, ctx, opts) {
|
|
2530
|
+
let idx = 0;
|
|
2531
|
+
return template22.replace(TEMPLATE_PLACEHOLDER, (_match, rawExpr) => {
|
|
2532
|
+
idx += 1;
|
|
2533
|
+
const { scope, rest } = parseTemplatePlaceholder(rawExpr);
|
|
2534
|
+
const label = describeBadPlaceholder(template22, idx, rawExpr);
|
|
2535
|
+
let rendered;
|
|
2536
|
+
let source;
|
|
2537
|
+
switch (scope) {
|
|
2538
|
+
case "initData":
|
|
2539
|
+
rendered = stringifyTemplateValue(traverseMappingPath(ctx.initData, rest, label), template22, idx, rawExpr);
|
|
2540
|
+
source = "initData";
|
|
2541
|
+
break;
|
|
2542
|
+
case "state":
|
|
2543
|
+
rendered = stringifyTemplateValue(traverseMappingPath(ctx.state, rest, label), template22, idx, rawExpr);
|
|
2544
|
+
source = "state";
|
|
2545
|
+
break;
|
|
2546
|
+
case "requestContext":
|
|
2547
|
+
rendered = stringifyTemplateValue(traverseMappingPath(ctx.requestContext, rest, label), template22, idx, rawExpr);
|
|
2548
|
+
source = "requestContext";
|
|
2549
|
+
break;
|
|
2550
|
+
case "stepResults": {
|
|
2551
|
+
const innerDot = rest.indexOf(".");
|
|
2552
|
+
const stepId = innerDot === -1 ? rest : rest.slice(0, innerDot);
|
|
2553
|
+
const subPath = innerDot === -1 ? "" : rest.slice(innerDot + 1);
|
|
2554
|
+
if (!stepId) throw new WorkflowTemplateError(`${label} must name a step: \${stepResults.<stepId>.<path>}.`, rawExpr);
|
|
2555
|
+
if (!(stepId in ctx.stepResults) || ctx.stepResults[stepId] == null) {
|
|
2556
|
+
throw new WorkflowTemplateError(`${label} references stepResults.${stepId} but step "${stepId}" has no resolvable output (not an ancestor, not run, failed, or produced no output).`, rawExpr);
|
|
2557
|
+
}
|
|
2558
|
+
rendered = stringifyTemplateValue(traverseMappingPath(ctx.stepResults[stepId], subPath, label), template22, idx, rawExpr);
|
|
2559
|
+
source = `step:${stepId}`;
|
|
2560
|
+
break;
|
|
2561
|
+
}
|
|
2562
|
+
default:
|
|
2563
|
+
throw new WorkflowTemplateError(`${label} references unknown namespace "${scope}". Use one of: ${TEMPLATE_NAMESPACES.join(", ")}.`, rawExpr);
|
|
2564
|
+
}
|
|
2565
|
+
return opts.fenced ? fenceBlock(rawExpr, source, rendered) : rendered;
|
|
2566
|
+
});
|
|
2123
2567
|
}
|
|
2124
|
-
__name(
|
|
2125
|
-
__name3(
|
|
2126
|
-
function
|
|
2127
|
-
|
|
2568
|
+
__name(renderTemplate, "renderTemplate");
|
|
2569
|
+
__name3(renderTemplate, "renderTemplate");
|
|
2570
|
+
function isMapDescriptor(v) {
|
|
2571
|
+
if (v === null || typeof v !== "object" || Array.isArray(v)) return false;
|
|
2572
|
+
const d = v;
|
|
2573
|
+
const keys = Object.keys(d);
|
|
2574
|
+
const only = /* @__PURE__ */ __name3((...allowed) => keys.every((k) => allowed.includes(k)), "only");
|
|
2575
|
+
if ("value" in d) return keys.length === 1;
|
|
2576
|
+
if ("template" in d) return keys.length === 1 && typeof d.template === "string";
|
|
2577
|
+
if ("requestContextPath" in d) return keys.length === 1 && typeof d.requestContextPath === "string";
|
|
2578
|
+
if ("knowledge" in d) return keys.length === 1 && typeof d.knowledge === "object" && d.knowledge !== null;
|
|
2579
|
+
if ("initData" in d) return d.initData === true && typeof d.path === "string" && only("initData", "path");
|
|
2580
|
+
if ("step" in d) {
|
|
2581
|
+
const stepOk = typeof d.step === "string" || Array.isArray(d.step) && d.step.every((x) => typeof x === "string");
|
|
2582
|
+
return stepOk && typeof d.path === "string" && only("step", "path", "rows");
|
|
2583
|
+
}
|
|
2584
|
+
return false;
|
|
2128
2585
|
}
|
|
2129
|
-
__name(
|
|
2130
|
-
__name3(
|
|
2131
|
-
var
|
|
2132
|
-
"
|
|
2133
|
-
"
|
|
2134
|
-
"
|
|
2135
|
-
"
|
|
2136
|
-
"
|
|
2137
|
-
"
|
|
2138
|
-
"
|
|
2139
|
-
"gh",
|
|
2140
|
-
"fetch"
|
|
2586
|
+
__name(isMapDescriptor, "isMapDescriptor");
|
|
2587
|
+
__name3(isMapDescriptor, "isMapDescriptor");
|
|
2588
|
+
var MAP_DESCRIPTOR_KEYS = [
|
|
2589
|
+
"step",
|
|
2590
|
+
"path",
|
|
2591
|
+
"initData",
|
|
2592
|
+
"value",
|
|
2593
|
+
"template",
|
|
2594
|
+
"requestContextPath",
|
|
2595
|
+
"knowledge"
|
|
2141
2596
|
];
|
|
2142
|
-
var
|
|
2143
|
-
function
|
|
2144
|
-
|
|
2145
|
-
|
|
2146
|
-
|
|
2147
|
-
|
|
2148
|
-
|
|
2149
|
-
|
|
2150
|
-
|
|
2151
|
-
|
|
2152
|
-
|
|
2153
|
-
var workspaceOf = /* @__PURE__ */ __name3((node) => node.workspace, "workspaceOf");
|
|
2154
|
-
var mountsWorkspace = /* @__PURE__ */ __name3((node) => {
|
|
2155
|
-
const w = workspaceOf(node);
|
|
2156
|
-
return w !== void 0 && w !== "inherit";
|
|
2157
|
-
}, "mountsWorkspace");
|
|
2158
|
-
var isJobTier = /* @__PURE__ */ __name3((node) => node.tier === "job" || mountsWorkspace(node), "isJobTier");
|
|
2159
|
-
var jobToolsOf = /* @__PURE__ */ __name3((node) => {
|
|
2160
|
-
if (node.type === "agent") return node.toolScope?.jobTools;
|
|
2161
|
-
return node.jobTools;
|
|
2162
|
-
}, "jobToolsOf");
|
|
2163
|
-
function schemaAtPath(schema, path) {
|
|
2164
|
-
let cur = schema;
|
|
2165
|
-
if (!cur || typeof cur !== "object") return void 0;
|
|
2166
|
-
for (const seg of path.split(".").filter(Boolean)) {
|
|
2167
|
-
const props = cur.properties;
|
|
2168
|
-
const next = props?.[seg];
|
|
2169
|
-
if (!next || typeof next !== "object") return void 0;
|
|
2170
|
-
cur = next;
|
|
2597
|
+
var MAP_MEMBER_MALFORMED_CODE = "map-member-malformed";
|
|
2598
|
+
function malformedMapMembers(cfg) {
|
|
2599
|
+
if (!cfg || typeof cfg !== "object" || Array.isArray(cfg)) return [];
|
|
2600
|
+
const out = [];
|
|
2601
|
+
for (const [member, v] of Object.entries(cfg)) {
|
|
2602
|
+
if (!v || typeof v !== "object" || Array.isArray(v) || isMapDescriptor(v)) continue;
|
|
2603
|
+
const keys = Object.keys(v).filter((k) => MAP_DESCRIPTOR_KEYS.includes(k));
|
|
2604
|
+
if (keys.length > 0) out.push({
|
|
2605
|
+
member,
|
|
2606
|
+
keys
|
|
2607
|
+
});
|
|
2171
2608
|
}
|
|
2172
|
-
return
|
|
2609
|
+
return out;
|
|
2173
2610
|
}
|
|
2174
|
-
__name(
|
|
2175
|
-
__name3(
|
|
2176
|
-
|
|
2177
|
-
|
|
2178
|
-
|
|
2179
|
-
if (t === void 0) return void 0;
|
|
2180
|
-
return Array.isArray(t) ? t.includes("array") : t === "array";
|
|
2181
|
-
}, "schemaIsArray");
|
|
2182
|
-
var singleId = /* @__PURE__ */ __name3((s) => s.type === "step" ? s.step.id : s.id, "singleId");
|
|
2183
|
-
var armId = /* @__PURE__ */ __name3((a) => a.type === "mapping" ? a.id : singleId(a), "armId");
|
|
2184
|
-
var TEMPLATE_STEP_REF = /\$\{\s*stepResults\.([A-Za-z0-9_\-]+)/g;
|
|
2185
|
-
function templateStepRefs(text) {
|
|
2186
|
-
const ids = [];
|
|
2187
|
-
for (const m of text.matchAll(TEMPLATE_STEP_REF)) ids.push(m[1]);
|
|
2188
|
-
return ids;
|
|
2611
|
+
__name(malformedMapMembers, "malformedMapMembers");
|
|
2612
|
+
__name3(malformedMapMembers, "malformedMapMembers");
|
|
2613
|
+
function mapMemberMalformedMessage(id, m) {
|
|
2614
|
+
const keys = m.keys.map((k) => `\`${k}\``).join(", ");
|
|
2615
|
+
return `"${id}".${m.member} carries descriptor key${m.keys.length === 1 ? "" : "s"} ${keys} but is not an exact binding form ({initData:true, path} | {step, path[, rows]} | {value} | {template} | {requestContextPath} | {knowledge}) \u2014 it is passed to the step verbatim as a literal; fix the descriptor, or wrap it in {value: \u2026} if the literal is intended`;
|
|
2189
2616
|
}
|
|
2190
|
-
__name(
|
|
2191
|
-
__name3(
|
|
2192
|
-
function
|
|
2193
|
-
if (!
|
|
2194
|
-
|
|
2617
|
+
__name(mapMemberMalformedMessage, "mapMemberMalformedMessage");
|
|
2618
|
+
__name3(mapMemberMalformedMessage, "mapMemberMalformedMessage");
|
|
2619
|
+
function resolveDescriptor(key, m, ctx) {
|
|
2620
|
+
if (!isMapDescriptor(m)) return {
|
|
2621
|
+
value: m
|
|
2622
|
+
};
|
|
2195
2623
|
try {
|
|
2196
|
-
|
|
2197
|
-
|
|
2198
|
-
|
|
2199
|
-
|
|
2200
|
-
|
|
2201
|
-
|
|
2202
|
-
|
|
2203
|
-
|
|
2204
|
-
|
|
2205
|
-
desc.step
|
|
2206
|
-
]);
|
|
2207
|
-
if (typeof desc.template === "string") ids.push(...templateStepRefs(desc.template));
|
|
2208
|
-
}
|
|
2209
|
-
return ids;
|
|
2210
|
-
}
|
|
2211
|
-
__name(mapConfigStepRefs, "mapConfigStepRefs");
|
|
2212
|
-
__name3(mapConfigStepRefs, "mapConfigStepRefs");
|
|
2213
|
-
function nodeStepRefs(entry) {
|
|
2214
|
-
switch (entry.type) {
|
|
2215
|
-
case "agent": {
|
|
2216
|
-
const a = entry;
|
|
2217
|
-
const p = a.promptTemplate;
|
|
2218
|
-
return typeof p === "string" ? templateStepRefs(p) : p && "template" in p ? templateStepRefs(p.template) : [];
|
|
2624
|
+
if ("value" in m) return {
|
|
2625
|
+
value: m.value
|
|
2626
|
+
};
|
|
2627
|
+
if ("template" in m && typeof m.template === "string") {
|
|
2628
|
+
return {
|
|
2629
|
+
value: renderTemplate(m.template, ctx, {
|
|
2630
|
+
fenced: false
|
|
2631
|
+
})
|
|
2632
|
+
};
|
|
2219
2633
|
}
|
|
2220
|
-
|
|
2221
|
-
return
|
|
2222
|
-
|
|
2223
|
-
|
|
2224
|
-
|
|
2225
|
-
return mapConfigStepRefs(entry.mapConfig);
|
|
2226
|
-
case "approval": {
|
|
2227
|
-
const a = entry;
|
|
2228
|
-
return typeof a.details === "string" ? templateStepRefs(a.details) : [];
|
|
2634
|
+
if ("knowledge" in m || "rows" in m && m.rows !== void 0) {
|
|
2635
|
+
return {
|
|
2636
|
+
error: "binding_unresolved",
|
|
2637
|
+
key
|
|
2638
|
+
};
|
|
2229
2639
|
}
|
|
2230
|
-
|
|
2231
|
-
|
|
2640
|
+
if ("requestContextPath" in m) {
|
|
2641
|
+
const label = `requestContext path for key "${key}"`;
|
|
2642
|
+
return {
|
|
2643
|
+
value: traverseMappingPath(ctx.requestContext, m.requestContextPath, label)
|
|
2644
|
+
};
|
|
2645
|
+
}
|
|
2646
|
+
if ("path" in m) {
|
|
2647
|
+
const source = "initData" in m && m.initData ? "initData" : "step";
|
|
2648
|
+
if (source === "initData") {
|
|
2649
|
+
return {
|
|
2650
|
+
value: traverseMappingPath(ctx.initData, m.path, `initData for key "${key}"`)
|
|
2651
|
+
};
|
|
2652
|
+
}
|
|
2653
|
+
const stepRef = m.step;
|
|
2654
|
+
const candidates = Array.isArray(stepRef) ? stepRef : [
|
|
2655
|
+
stepRef
|
|
2656
|
+
];
|
|
2657
|
+
const stepId = candidates.find((s) => ctx.stepResults[s] !== void 0 && ctx.stepResults[s] !== null);
|
|
2658
|
+
if (stepId === void 0) return {
|
|
2659
|
+
error: "binding_unresolved",
|
|
2660
|
+
key
|
|
2661
|
+
};
|
|
2662
|
+
return {
|
|
2663
|
+
value: traverseMappingPath(ctx.stepResults[stepId], m.path, `step ${candidates.join("|")} for key "${key}"`)
|
|
2664
|
+
};
|
|
2665
|
+
}
|
|
2666
|
+
return {
|
|
2667
|
+
error: "binding_unresolved",
|
|
2668
|
+
key
|
|
2669
|
+
};
|
|
2670
|
+
} catch (err) {
|
|
2671
|
+
if (err instanceof WorkflowTemplateError) return {
|
|
2672
|
+
error: "binding_unresolved",
|
|
2673
|
+
key
|
|
2674
|
+
};
|
|
2675
|
+
throw err;
|
|
2232
2676
|
}
|
|
2233
2677
|
}
|
|
2234
|
-
__name(
|
|
2235
|
-
__name3(
|
|
2236
|
-
function
|
|
2237
|
-
|
|
2238
|
-
|
|
2239
|
-
|
|
2240
|
-
const err = /* @__PURE__ */ __name3((code, message, path, stepId) => {
|
|
2241
|
-
issues.push({
|
|
2242
|
-
code,
|
|
2243
|
-
message,
|
|
2244
|
-
severity: "error",
|
|
2245
|
-
path,
|
|
2246
|
-
stepId
|
|
2247
|
-
});
|
|
2248
|
-
}, "err");
|
|
2249
|
-
const warn = /* @__PURE__ */ __name3((code, message, path, stepId) => {
|
|
2250
|
-
issues.push({
|
|
2251
|
-
code,
|
|
2252
|
-
message,
|
|
2253
|
-
severity: "warning",
|
|
2254
|
-
path,
|
|
2255
|
-
stepId
|
|
2256
|
-
});
|
|
2257
|
-
}, "warn");
|
|
2258
|
-
const graph = g?.definition?.graph;
|
|
2259
|
-
if (!Array.isArray(graph)) {
|
|
2260
|
-
err("invalid-envelope", "`definition.graph` must be an array", "definition.graph");
|
|
2261
|
-
return issues;
|
|
2262
|
-
}
|
|
2263
|
-
if (graph.length === 0) {
|
|
2264
|
-
err("empty-graph", "a workflow needs at least one entry", "definition.graph");
|
|
2265
|
-
return issues;
|
|
2266
|
-
}
|
|
2267
|
-
if (!opts.static && g.concurrencyPolicy !== void 0) {
|
|
2268
|
-
err("static-only-field", "`concurrencyPolicy` is a static-only envelope field (03 \xA73.4.2)", "concurrencyPolicy");
|
|
2269
|
-
}
|
|
2270
|
-
const envelopeWorkspace = g.workspace;
|
|
2271
|
-
if (envelopeWorkspace?.backend && envelopeWorkspace.backend !== "ebs" && opts.policy?.workspaceBackends && !opts.policy.workspaceBackends.includes(envelopeWorkspace.backend)) {
|
|
2272
|
-
err("workspace-backend-unavailable", `workspace.backend '${envelopeWorkspace.backend}' is not enabled (LUA_WF_WORKSPACE_BACKENDS = ${opts.policy.workspaceBackends.join(",")}) \u2014 'ebs' is the normative fallback`, "workspace.backend");
|
|
2678
|
+
__name(resolveDescriptor, "resolveDescriptor");
|
|
2679
|
+
__name3(resolveDescriptor, "resolveDescriptor");
|
|
2680
|
+
function resolveMapping(cfg, ctx) {
|
|
2681
|
+
const keys = Object.keys(cfg);
|
|
2682
|
+
if (keys.length === 1 && keys[0] === "") {
|
|
2683
|
+
return resolveDescriptor("", cfg[""], ctx);
|
|
2273
2684
|
}
|
|
2274
|
-
const
|
|
2275
|
-
|
|
2276
|
-
|
|
2685
|
+
const result = {};
|
|
2686
|
+
for (const key of keys) {
|
|
2687
|
+
const resolved = resolveDescriptor(key, cfg[key], ctx);
|
|
2688
|
+
if ("error" in resolved) return resolved;
|
|
2689
|
+
result[key] = resolved.value;
|
|
2277
2690
|
}
|
|
2278
|
-
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
|
|
2691
|
+
return {
|
|
2692
|
+
value: result
|
|
2693
|
+
};
|
|
2694
|
+
}
|
|
2695
|
+
__name(resolveMapping, "resolveMapping");
|
|
2696
|
+
__name3(resolveMapping, "resolveMapping");
|
|
2697
|
+
var fromInit = /* @__PURE__ */ __name3((path) => ({
|
|
2698
|
+
initData: true,
|
|
2699
|
+
path
|
|
2700
|
+
}), "fromInit");
|
|
2701
|
+
var fromStep = /* @__PURE__ */ __name3((s, path = "") => {
|
|
2702
|
+
const idOf = /* @__PURE__ */ __name3((x) => typeof x === "string" ? x : x.id, "idOf");
|
|
2703
|
+
return {
|
|
2704
|
+
step: Array.isArray(s) ? s.map(idOf) : idOf(s),
|
|
2705
|
+
path
|
|
2706
|
+
};
|
|
2707
|
+
}, "fromStep");
|
|
2708
|
+
var value = /* @__PURE__ */ __name3((v) => ({
|
|
2709
|
+
value: v
|
|
2710
|
+
}), "value");
|
|
2711
|
+
var template = /* @__PURE__ */ __name3((s) => ({
|
|
2712
|
+
template: s
|
|
2713
|
+
}), "template");
|
|
2714
|
+
var fromRequest = /* @__PURE__ */ __name3((path) => ({
|
|
2715
|
+
requestContextPath: path
|
|
2716
|
+
}), "fromRequest");
|
|
2717
|
+
var rows = /* @__PURE__ */ __name3((s, path, page) => ({
|
|
2718
|
+
step: typeof s === "string" ? s : s.id,
|
|
2719
|
+
path,
|
|
2720
|
+
rows: page
|
|
2721
|
+
}), "rows");
|
|
2722
|
+
var fromKnowledge = /* @__PURE__ */ __name3((k) => ({
|
|
2723
|
+
knowledge: k
|
|
2724
|
+
}), "fromKnowledge");
|
|
2725
|
+
var SideEffectsSchema = z4.enum(WORKFLOW_SIDE_EFFECTS);
|
|
2726
|
+
var JobResourcesSchema = z4.enum(WORKFLOW_JOB_RESOURCES);
|
|
2727
|
+
var WORKFLOW_ARM_SUBRUN_ID = "$arm";
|
|
2728
|
+
var WORKSPACE_TEMPLATE_EXPR_RE = /^\$\{\s*(?:initData|input)\.([^}]+?)\s*\}$/;
|
|
2729
|
+
function workspaceTemplatePath(template22) {
|
|
2730
|
+
const key = template22.trim();
|
|
2731
|
+
const expr = WORKSPACE_TEMPLATE_EXPR_RE.exec(key);
|
|
2732
|
+
if (expr) return expr[1].split(".");
|
|
2733
|
+
if (key.includes("${")) return void 0;
|
|
2734
|
+
return key.replace(/^(?:input|initData)\./, "").split(".");
|
|
2735
|
+
}
|
|
2736
|
+
__name(workspaceTemplatePath, "workspaceTemplatePath");
|
|
2737
|
+
__name3(workspaceTemplatePath, "workspaceTemplatePath");
|
|
2738
|
+
function retryBackoffs() {
|
|
2739
|
+
if (!Array.isArray(WORKFLOW_RETRY_BACKOFFS)) {
|
|
2740
|
+
throw new Error("@lua/shared-types.WORKFLOW_RETRY_BACKOFFS is not a tuple \u2014 a jest.mock('@lua/shared-types') must spread jest.requireActual('@lua/shared-types')");
|
|
2741
|
+
}
|
|
2742
|
+
return WORKFLOW_RETRY_BACKOFFS;
|
|
2743
|
+
}
|
|
2744
|
+
__name(retryBackoffs, "retryBackoffs");
|
|
2745
|
+
__name3(retryBackoffs, "retryBackoffs");
|
|
2746
|
+
var SLEEP_UNTIL_REPLACEMENT = Object.freeze({
|
|
2747
|
+
type: "sleep",
|
|
2748
|
+
duration: 6e4
|
|
2749
|
+
});
|
|
2750
|
+
function sleepUntilUnsupportedMessage(id) {
|
|
2751
|
+
return `the engine does not execute \`sleepUntil\` yet (node "${id}") \u2014 replace it with a \`sleep\` node with a \`duration\` in ms, e.g. { type: 'sleep', id: '${id}', duration: ${SLEEP_UNTIL_REPLACEMENT.duration} }`;
|
|
2752
|
+
}
|
|
2753
|
+
__name(sleepUntilUnsupportedMessage, "sleepUntilUnsupportedMessage");
|
|
2754
|
+
__name3(sleepUntilUnsupportedMessage, "sleepUntilUnsupportedMessage");
|
|
2755
|
+
var WORKFLOW_CAPS_DEFAULT = Object.freeze({
|
|
2756
|
+
maxParallelArms: 16,
|
|
2757
|
+
maxForeachConcurrency: 16,
|
|
2758
|
+
maxForeachItems: 2e4,
|
|
2759
|
+
maxNodes: 200,
|
|
2760
|
+
maxNestingDepth: 3,
|
|
2761
|
+
maxForeachRatePerSecond: 50,
|
|
2762
|
+
maxLoopIntervalSeconds: 86400,
|
|
2763
|
+
maxWorkerTimeoutSeconds: 600,
|
|
2764
|
+
maxJobTimeoutSeconds: 86400,
|
|
2765
|
+
maxJobSegmentSeconds: 14400
|
|
2766
|
+
});
|
|
2767
|
+
var WORKFLOW_STEP_DEFAULT_TIMEOUT_SECONDS = 300;
|
|
2768
|
+
var WORKFLOW_AGENT_DEFAULT_TIMEOUT_SECONDS = 600;
|
|
2769
|
+
var WORKFLOW_JOB_DEFAULT_TIMEOUT_SECONDS = 3600;
|
|
2770
|
+
var WORKFLOW_FOREACH_DEFAULT_CONCURRENCY = 4;
|
|
2771
|
+
var WORKFLOW_FOREACH_DEFAULT_MAX_ITEMS = 256;
|
|
2772
|
+
var WORKFLOW_LOOP_DEFAULT_MAX_ITERATIONS = 100;
|
|
2773
|
+
var WORKFLOW_SUSPEND_DEFAULT_TIMEOUT_HOURS = 168;
|
|
2774
|
+
var WORKFLOW_SIGNAL_DEFAULT_SOURCES = [
|
|
2775
|
+
"webhook",
|
|
2776
|
+
"api",
|
|
2777
|
+
"user"
|
|
2778
|
+
];
|
|
2779
|
+
var clone = /* @__PURE__ */ __name3((v) => JSON.parse(JSON.stringify(v)), "clone");
|
|
2780
|
+
function fillPolicy(node, defaultTimeout) {
|
|
2781
|
+
if (node.tier === void 0 && node.workspace !== void 0 && node.workspace !== "inherit") node.tier = "job";
|
|
2782
|
+
if (node.timeoutSeconds === void 0) node.timeoutSeconds = node.tier === "job" ? WORKFLOW_JOB_DEFAULT_TIMEOUT_SECONDS : defaultTimeout;
|
|
2783
|
+
if (node.retry === void 0) node.retry = {
|
|
2784
|
+
maxAttempts: 1
|
|
2785
|
+
};
|
|
2786
|
+
if (node.onError === void 0) node.onError = "fail";
|
|
2787
|
+
if ((node.type === "step" || node.type === "tool") && node.sideEffects === void 0) node.sideEffects = "none";
|
|
2788
|
+
}
|
|
2789
|
+
__name(fillPolicy, "fillPolicy");
|
|
2790
|
+
__name3(fillPolicy, "fillPolicy");
|
|
2791
|
+
function fillSingle(node) {
|
|
2792
|
+
switch (node.type) {
|
|
2793
|
+
case "step": {
|
|
2794
|
+
fillPolicy(node, WORKFLOW_STEP_DEFAULT_TIMEOUT_SECONDS);
|
|
2795
|
+
const s = node;
|
|
2796
|
+
if (s.resumeTimeoutHours === void 0) s.resumeTimeoutHours = WORKFLOW_SUSPEND_DEFAULT_TIMEOUT_HOURS;
|
|
2797
|
+
if (s.onSuspendTimeout === void 0) s.onSuspendTimeout = "fail";
|
|
2284
2798
|
return;
|
|
2285
2799
|
}
|
|
2286
|
-
|
|
2287
|
-
|
|
2800
|
+
case "agent":
|
|
2801
|
+
fillPolicy(node, WORKFLOW_AGENT_DEFAULT_TIMEOUT_SECONDS);
|
|
2288
2802
|
return;
|
|
2289
|
-
|
|
2290
|
-
|
|
2291
|
-
|
|
2803
|
+
case "tool":
|
|
2804
|
+
fillPolicy(node, WORKFLOW_STEP_DEFAULT_TIMEOUT_SECONDS);
|
|
2805
|
+
return;
|
|
2806
|
+
case "workflow":
|
|
2807
|
+
if (node.workflowId === WORKFLOW_ARM_SUBRUN_ID && Array.isArray(node.graph) && node.graph[1]) fillSingle(node.graph[1]);
|
|
2292
2808
|
return;
|
|
2293
|
-
}
|
|
2294
|
-
declaredKeys.add(key);
|
|
2295
|
-
});
|
|
2296
|
-
const undeclaredKey = /* @__PURE__ */ __name3((ref) => typeof ref === "string" && !declaredKeys.has(ref) && isConnectionKeyShaped(ref) && opts.connectionIds?.has(ref) !== true, "undeclaredKey");
|
|
2297
|
-
const credentialsRef = envelopeWorkspace?.credentialsRef;
|
|
2298
|
-
if (undeclaredKey(credentialsRef)) {
|
|
2299
|
-
err("connection-key-undeclared", connectionKeyUndeclaredMessage("workspace.credentialsRef", credentialsRef), "workspace.credentialsRef");
|
|
2300
2809
|
}
|
|
2301
|
-
|
|
2302
|
-
|
|
2303
|
-
|
|
2304
|
-
|
|
2305
|
-
|
|
2306
|
-
|
|
2307
|
-
|
|
2308
|
-
|
|
2309
|
-
|
|
2310
|
-
|
|
2311
|
-
|
|
2312
|
-
|
|
2313
|
-
|
|
2314
|
-
|
|
2315
|
-
|
|
2316
|
-
|
|
2317
|
-
|
|
2318
|
-
|
|
2319
|
-
|
|
2320
|
-
|
|
2321
|
-
|
|
2322
|
-
|
|
2323
|
-
|
|
2324
|
-
|
|
2325
|
-
|
|
2326
|
-
|
|
2327
|
-
|
|
2328
|
-
|
|
2329
|
-
|
|
2330
|
-
|
|
2331
|
-
|
|
2332
|
-
|
|
2333
|
-
|
|
2334
|
-
|
|
2335
|
-
|
|
2336
|
-
|
|
2337
|
-
|
|
2338
|
-
|
|
2339
|
-
|
|
2340
|
-
|
|
2341
|
-
|
|
2342
|
-
|
|
2343
|
-
|
|
2344
|
-
|
|
2345
|
-
|
|
2810
|
+
}
|
|
2811
|
+
__name(fillSingle, "fillSingle");
|
|
2812
|
+
__name3(fillSingle, "fillSingle");
|
|
2813
|
+
function fillHitl(node) {
|
|
2814
|
+
if (node.type === "approval") {
|
|
2815
|
+
const a = node;
|
|
2816
|
+
if (a.approver === void 0) a.approver = "creator";
|
|
2817
|
+
if (a.timeoutHours === void 0) a.timeoutHours = WORKFLOW_SUSPEND_DEFAULT_TIMEOUT_HOURS;
|
|
2818
|
+
if (a.onTimeout === void 0) a.onTimeout = "deny";
|
|
2819
|
+
if (a.onDeny === void 0) a.onDeny = "continue";
|
|
2820
|
+
if (a.excludeInitiator === void 0) a.excludeInitiator = false;
|
|
2821
|
+
if (a.editable === void 0) a.editable = false;
|
|
2822
|
+
return;
|
|
2823
|
+
}
|
|
2824
|
+
const w = node;
|
|
2825
|
+
if (w.timeoutHours === void 0) w.timeoutHours = WORKFLOW_SUSPEND_DEFAULT_TIMEOUT_HOURS;
|
|
2826
|
+
if (w.onTimeout === void 0) w.onTimeout = "fail";
|
|
2827
|
+
if (w.acceptedSources === void 0) w.acceptedSources = [
|
|
2828
|
+
...WORKFLOW_SIGNAL_DEFAULT_SOURCES
|
|
2829
|
+
];
|
|
2830
|
+
}
|
|
2831
|
+
__name(fillHitl, "fillHitl");
|
|
2832
|
+
__name3(fillHitl, "fillHitl");
|
|
2833
|
+
function fillArm(arm) {
|
|
2834
|
+
if (arm.type === "mapping") return;
|
|
2835
|
+
if (isHitlNode(arm)) fillHitl(arm);
|
|
2836
|
+
else fillSingle(arm);
|
|
2837
|
+
}
|
|
2838
|
+
__name(fillArm, "fillArm");
|
|
2839
|
+
__name3(fillArm, "fillArm");
|
|
2840
|
+
function fillEntry(entry) {
|
|
2841
|
+
switch (entry.type) {
|
|
2842
|
+
case "step":
|
|
2843
|
+
case "agent":
|
|
2844
|
+
case "tool":
|
|
2845
|
+
case "workflow":
|
|
2846
|
+
fillSingle(entry);
|
|
2847
|
+
return;
|
|
2848
|
+
case "parallel":
|
|
2849
|
+
entry.steps.forEach(fillArm);
|
|
2850
|
+
return;
|
|
2851
|
+
case "conditional": {
|
|
2852
|
+
const c = entry;
|
|
2853
|
+
if (c.exclusive === void 0) c.exclusive = false;
|
|
2854
|
+
c.steps.forEach(fillArm);
|
|
2855
|
+
if (c.otherwise) fillArm(c.otherwise);
|
|
2346
2856
|
return;
|
|
2347
2857
|
}
|
|
2348
|
-
|
|
2349
|
-
const
|
|
2350
|
-
|
|
2351
|
-
|
|
2352
|
-
|
|
2353
|
-
|
|
2354
|
-
|
|
2355
|
-
} else if (t > caps.maxWorkerTimeoutSeconds) {
|
|
2356
|
-
err("timeout-exceeds-tier", `timeoutSeconds ${t} exceeds the worker tier's ${caps.maxWorkerTimeoutSeconds} s \u2014 steps longer than 10 min run on the Job tier: add tier:'job' (up to ${caps.maxJobSegmentSeconds} s)`, `${path}.timeoutSeconds`, id);
|
|
2357
|
-
}
|
|
2358
|
-
}, "checkTimeout");
|
|
2359
|
-
const checkSpecialistRole = /* @__PURE__ */ __name3((node, path) => {
|
|
2360
|
-
const role = node.role;
|
|
2361
|
-
const hasRef = typeof role.ref === "string";
|
|
2362
|
-
const hasInline = role.name !== void 0 || role.instructions !== void 0 || Array.isArray(role.tools) && role.tools.length > 0;
|
|
2363
|
-
if (hasRef && hasInline) {
|
|
2364
|
-
err("role-ref-and-inline", "a role is either `{ref}` or inline `{name, instructions, tools}`, never both", `${path}.role`, node.id);
|
|
2365
|
-
}
|
|
2366
|
-
if (node.agentId !== "$self") {
|
|
2367
|
-
err("ephemeral-base-not-self", "a role runs on the owner only: use '$self'", `${path}.agentId`, node.id);
|
|
2368
|
-
}
|
|
2369
|
-
if (opts.policy && opts.policy.ephemeralSpecialists !== true) {
|
|
2370
|
-
err("ephemeral-specialists-disabled", "ephemeral specialists are off for this org/agent (workflowPolicy.ephemeralSpecialists)", `${path}.role`, node.id);
|
|
2858
|
+
case "foreach": {
|
|
2859
|
+
const f = entry;
|
|
2860
|
+
f.opts = f.opts ?? {};
|
|
2861
|
+
if (f.opts.concurrency === void 0) f.opts.concurrency = WORKFLOW_FOREACH_DEFAULT_CONCURRENCY;
|
|
2862
|
+
if (f.opts.maxItems === void 0) f.opts.maxItems = WORKFLOW_FOREACH_DEFAULT_MAX_ITEMS;
|
|
2863
|
+
fillArm(f.step);
|
|
2864
|
+
return;
|
|
2371
2865
|
}
|
|
2372
|
-
|
|
2373
|
-
|
|
2374
|
-
|
|
2375
|
-
|
|
2376
|
-
|
|
2377
|
-
} else {
|
|
2378
|
-
tools = saved.tools ?? [];
|
|
2379
|
-
if (typeof role.roleHash === "string" && saved.roleHash && role.roleHash !== saved.roleHash) {
|
|
2380
|
-
warn("role-ref-stale", `saved role \`${role.ref}\` changed since this version was frozen`, `${path}.role.ref`, node.id);
|
|
2381
|
-
}
|
|
2382
|
-
}
|
|
2866
|
+
case "loop": {
|
|
2867
|
+
const l = entry;
|
|
2868
|
+
if (l.maxIterations === void 0) l.maxIterations = WORKFLOW_LOOP_DEFAULT_MAX_ITERATIONS;
|
|
2869
|
+
fillArm(l.step);
|
|
2870
|
+
return;
|
|
2383
2871
|
}
|
|
2384
|
-
|
|
2385
|
-
|
|
2386
|
-
|
|
2387
|
-
|
|
2388
|
-
|
|
2872
|
+
case "approval":
|
|
2873
|
+
case "waitForSignal":
|
|
2874
|
+
fillHitl(entry);
|
|
2875
|
+
return;
|
|
2876
|
+
case "mapping":
|
|
2877
|
+
case "sleep":
|
|
2878
|
+
case "sleepUntil":
|
|
2879
|
+
return;
|
|
2880
|
+
}
|
|
2881
|
+
}
|
|
2882
|
+
__name(fillEntry, "fillEntry");
|
|
2883
|
+
__name3(fillEntry, "fillEntry");
|
|
2884
|
+
function withDefaultsFilled(g) {
|
|
2885
|
+
const out = clone(g);
|
|
2886
|
+
out.definition.graph.forEach(fillEntry);
|
|
2887
|
+
return out;
|
|
2888
|
+
}
|
|
2889
|
+
__name(withDefaultsFilled, "withDefaultsFilled");
|
|
2890
|
+
__name3(withDefaultsFilled, "withDefaultsFilled");
|
|
2891
|
+
var CONNECTION_ID_HEX_RE = /^[0-9a-f]{24}$/;
|
|
2892
|
+
function isConnectionKeyShaped(value22) {
|
|
2893
|
+
return WORKFLOW_CONNECTION_KEY_RE.test(value22) && !CONNECTION_ID_HEX_RE.test(value22);
|
|
2894
|
+
}
|
|
2895
|
+
__name(isConnectionKeyShaped, "isConnectionKeyShaped");
|
|
2896
|
+
__name3(isConnectionKeyShaped, "isConnectionKeyShaped");
|
|
2897
|
+
function connectionKeyUndeclaredMessage(path, key) {
|
|
2898
|
+
return `${path} '${key}' is neither a connection id nor a declared connections[].key \u2014 declare it: connections: [{ key: '${key}', integrationType: '<catalog slug, e.g. github>' }] and it resolves on any agent`;
|
|
2899
|
+
}
|
|
2900
|
+
__name(connectionKeyUndeclaredMessage, "connectionKeyUndeclaredMessage");
|
|
2901
|
+
__name3(connectionKeyUndeclaredMessage, "connectionKeyUndeclaredMessage");
|
|
2902
|
+
var WORKFLOW_JOB_TOOLS = [
|
|
2903
|
+
"shell",
|
|
2904
|
+
"read",
|
|
2905
|
+
"write",
|
|
2906
|
+
"edit",
|
|
2907
|
+
"glob",
|
|
2908
|
+
"grep",
|
|
2909
|
+
"git",
|
|
2910
|
+
"gh",
|
|
2911
|
+
"fetch"
|
|
2912
|
+
];
|
|
2913
|
+
var WORKFLOW_JOB_MAX_WORKTREE_ARMS = 8;
|
|
2914
|
+
function classifyModelProvider(model) {
|
|
2915
|
+
const m = (model ?? "").trim().toLowerCase();
|
|
2916
|
+
if (!m) return null;
|
|
2917
|
+
if (/^(anthropic\/|claude)/.test(m)) return "anthropic";
|
|
2918
|
+
if (/^(openai\/|gpt-|o[1-9](-|$)|chatgpt)/.test(m)) return "openai";
|
|
2919
|
+
if (/^(google\/|gemini)/.test(m)) return "google";
|
|
2920
|
+
return null;
|
|
2921
|
+
}
|
|
2922
|
+
__name(classifyModelProvider, "classifyModelProvider");
|
|
2923
|
+
__name3(classifyModelProvider, "classifyModelProvider");
|
|
2924
|
+
var workspaceOf = /* @__PURE__ */ __name3((node) => node.workspace, "workspaceOf");
|
|
2925
|
+
var mountsWorkspace = /* @__PURE__ */ __name3((node) => {
|
|
2926
|
+
const w = workspaceOf(node);
|
|
2927
|
+
return w !== void 0 && w !== "inherit";
|
|
2928
|
+
}, "mountsWorkspace");
|
|
2929
|
+
var isJobTier = /* @__PURE__ */ __name3((node) => node.tier === "job" || mountsWorkspace(node), "isJobTier");
|
|
2930
|
+
var jobToolsOf = /* @__PURE__ */ __name3((node) => {
|
|
2931
|
+
if (node.type === "agent") return node.toolScope?.jobTools;
|
|
2932
|
+
return node.jobTools;
|
|
2933
|
+
}, "jobToolsOf");
|
|
2934
|
+
function schemaAtPath(schema, path) {
|
|
2935
|
+
let cur = schema;
|
|
2936
|
+
if (!cur || typeof cur !== "object") return void 0;
|
|
2937
|
+
for (const seg of path.split(".").filter(Boolean)) {
|
|
2938
|
+
const props = cur.properties;
|
|
2939
|
+
const next = props?.[seg];
|
|
2940
|
+
if (!next || typeof next !== "object") return void 0;
|
|
2941
|
+
cur = next;
|
|
2942
|
+
}
|
|
2943
|
+
return cur;
|
|
2944
|
+
}
|
|
2945
|
+
__name(schemaAtPath, "schemaAtPath");
|
|
2946
|
+
__name3(schemaAtPath, "schemaAtPath");
|
|
2947
|
+
var schemaIsArray = /* @__PURE__ */ __name3((schema) => {
|
|
2948
|
+
if (!schema) return void 0;
|
|
2949
|
+
const t = schema.type;
|
|
2950
|
+
if (t === void 0) return void 0;
|
|
2951
|
+
return Array.isArray(t) ? t.includes("array") : t === "array";
|
|
2952
|
+
}, "schemaIsArray");
|
|
2953
|
+
var isHitlNode = /* @__PURE__ */ __name3((n2) => isWorkflowHitlEntryType(n2.type), "isHitlNode");
|
|
2954
|
+
var isSingleStep = /* @__PURE__ */ __name3((n2) => !isHitlNode(n2), "isSingleStep");
|
|
2955
|
+
var singleId = /* @__PURE__ */ __name3((s) => s.type === "step" ? s.step.id : s.id, "singleId");
|
|
2956
|
+
var armId = /* @__PURE__ */ __name3((a) => a.type === "mapping" ? a.id : singleId(a), "armId");
|
|
2957
|
+
var TEMPLATE_STEP_REF = /\$\{\s*stepResults\.([A-Za-z0-9_\-]+)/g;
|
|
2958
|
+
function templateStepRefs(text) {
|
|
2959
|
+
const ids = [];
|
|
2960
|
+
for (const m of text.matchAll(TEMPLATE_STEP_REF)) ids.push(m[1]);
|
|
2961
|
+
return ids;
|
|
2962
|
+
}
|
|
2963
|
+
__name(templateStepRefs, "templateStepRefs");
|
|
2964
|
+
__name3(templateStepRefs, "templateStepRefs");
|
|
2965
|
+
function readMapConfig(raw) {
|
|
2966
|
+
if (!raw) return void 0;
|
|
2967
|
+
if (typeof raw !== "string") return raw;
|
|
2968
|
+
try {
|
|
2969
|
+
const cfg = JSON.parse(raw);
|
|
2970
|
+
return cfg && typeof cfg === "object" && !Array.isArray(cfg) ? cfg : void 0;
|
|
2971
|
+
} catch {
|
|
2972
|
+
return void 0;
|
|
2973
|
+
}
|
|
2974
|
+
}
|
|
2975
|
+
__name(readMapConfig, "readMapConfig");
|
|
2976
|
+
__name3(readMapConfig, "readMapConfig");
|
|
2977
|
+
function mapConfigStepRefs(raw) {
|
|
2978
|
+
const cfg = readMapConfig(raw);
|
|
2979
|
+
if (!cfg) return [];
|
|
2980
|
+
const ids = [];
|
|
2981
|
+
for (const d of Object.values(cfg)) {
|
|
2982
|
+
if (!isMapDescriptor(d)) continue;
|
|
2983
|
+
if ("step" in d) ids.push(...Array.isArray(d.step) ? d.step : [
|
|
2984
|
+
d.step
|
|
2985
|
+
]);
|
|
2986
|
+
if ("template" in d) ids.push(...templateStepRefs(d.template));
|
|
2987
|
+
}
|
|
2988
|
+
return ids;
|
|
2989
|
+
}
|
|
2990
|
+
__name(mapConfigStepRefs, "mapConfigStepRefs");
|
|
2991
|
+
__name3(mapConfigStepRefs, "mapConfigStepRefs");
|
|
2992
|
+
function nodeStepRefs(entry) {
|
|
2993
|
+
switch (entry.type) {
|
|
2994
|
+
case "agent": {
|
|
2995
|
+
const a = entry;
|
|
2996
|
+
const p = a.promptTemplate;
|
|
2997
|
+
return typeof p === "string" ? templateStepRefs(p) : p && "template" in p ? templateStepRefs(p.template) : [];
|
|
2389
2998
|
}
|
|
2390
|
-
|
|
2391
|
-
|
|
2392
|
-
|
|
2393
|
-
|
|
2394
|
-
|
|
2395
|
-
|
|
2396
|
-
|
|
2999
|
+
case "tool":
|
|
3000
|
+
return mapConfigStepRefs(entry.input);
|
|
3001
|
+
case "workflow":
|
|
3002
|
+
return mapConfigStepRefs(entry.input);
|
|
3003
|
+
case "mapping":
|
|
3004
|
+
return mapConfigStepRefs(entry.mapConfig);
|
|
3005
|
+
case "approval": {
|
|
3006
|
+
const a = entry;
|
|
3007
|
+
return typeof a.details === "string" ? templateStepRefs(a.details) : [];
|
|
2397
3008
|
}
|
|
2398
|
-
|
|
2399
|
-
|
|
2400
|
-
|
|
2401
|
-
|
|
3009
|
+
default:
|
|
3010
|
+
return [];
|
|
3011
|
+
}
|
|
3012
|
+
}
|
|
3013
|
+
__name(nodeStepRefs, "nodeStepRefs");
|
|
3014
|
+
__name3(nodeStepRefs, "nodeStepRefs");
|
|
3015
|
+
function validateLuaExtensions(g, caps = WORKFLOW_CAPS_DEFAULT, opts = {
|
|
3016
|
+
static: true
|
|
3017
|
+
}) {
|
|
3018
|
+
const issues = [];
|
|
3019
|
+
const err = /* @__PURE__ */ __name3((code, message, path, stepId) => {
|
|
3020
|
+
issues.push({
|
|
3021
|
+
code,
|
|
3022
|
+
message,
|
|
3023
|
+
severity: "error",
|
|
3024
|
+
path,
|
|
3025
|
+
stepId
|
|
3026
|
+
});
|
|
3027
|
+
}, "err");
|
|
3028
|
+
const warn = /* @__PURE__ */ __name3((code, message, path, stepId) => {
|
|
3029
|
+
issues.push({
|
|
3030
|
+
code,
|
|
3031
|
+
message,
|
|
3032
|
+
severity: "warning",
|
|
3033
|
+
path,
|
|
3034
|
+
stepId
|
|
3035
|
+
});
|
|
3036
|
+
}, "warn");
|
|
3037
|
+
const graph = g?.definition?.graph;
|
|
3038
|
+
if (!Array.isArray(graph)) {
|
|
3039
|
+
err("invalid-envelope", "`definition.graph` must be an array", "definition.graph");
|
|
3040
|
+
return issues;
|
|
3041
|
+
}
|
|
3042
|
+
if (graph.length === 0) {
|
|
3043
|
+
err("empty-graph", "a workflow needs at least one entry", "definition.graph");
|
|
3044
|
+
return issues;
|
|
3045
|
+
}
|
|
3046
|
+
if (!opts.static && g.concurrencyPolicy !== void 0) {
|
|
3047
|
+
err("static-only-field", "`concurrencyPolicy` is a static-only envelope field (03 \xA73.4.2)", "concurrencyPolicy");
|
|
3048
|
+
}
|
|
3049
|
+
const envelopeWorkspace = g.workspace;
|
|
3050
|
+
if (envelopeWorkspace?.backend && envelopeWorkspace.backend !== "ebs" && opts.policy?.workspaceBackends && !opts.policy.workspaceBackends.includes(envelopeWorkspace.backend)) {
|
|
3051
|
+
err("workspace-backend-unavailable", `workspace.backend '${envelopeWorkspace.backend}' is not enabled (LUA_WF_WORKSPACE_BACKENDS = ${opts.policy.workspaceBackends.join(",")}) \u2014 'ebs' is the normative fallback`, "workspace.backend");
|
|
3052
|
+
}
|
|
3053
|
+
for (const member of [
|
|
3054
|
+
"repo",
|
|
3055
|
+
"ref"
|
|
3056
|
+
]) {
|
|
3057
|
+
const v = envelopeWorkspace?.[member];
|
|
3058
|
+
const tpl = v && typeof v === "object" && typeof v.template === "string" ? v.template : void 0;
|
|
3059
|
+
if (tpl !== void 0 && workspaceTemplatePath(tpl) === void 0) {
|
|
3060
|
+
warn("workspace-template-composite", `workspace.${member} template ${JSON.stringify(tpl)} is a composite \u2014 the engine binds one whole-string \${initData.<path>} (or an input.<path> key) and every start would fail workspace_provision_failed{binding_unresolved}; put the assembled value in the run input and bind that path`, `workspace.${member}`);
|
|
2402
3061
|
}
|
|
2403
|
-
}
|
|
2404
|
-
const
|
|
2405
|
-
|
|
2406
|
-
|
|
2407
|
-
|
|
3062
|
+
}
|
|
3063
|
+
const declaredKeys = new Set(opts.connectionKeys ?? []);
|
|
3064
|
+
if (g.connections !== void 0 && !Array.isArray(g.connections)) {
|
|
3065
|
+
err("connection-declaration-invalid", "`connections` must be an array of { key, integrationType }", "connections");
|
|
3066
|
+
}
|
|
3067
|
+
(Array.isArray(g.connections) ? g.connections : []).forEach((c, i) => {
|
|
3068
|
+
const path = `connections.${i}`;
|
|
3069
|
+
const key = c?.key;
|
|
3070
|
+
const integrationType = c?.integrationType;
|
|
3071
|
+
if (typeof key !== "string" || !WORKFLOW_CONNECTION_KEY_RE.test(key)) {
|
|
3072
|
+
err("connection-declaration-invalid", `connections[${i}].key must match ${WORKFLOW_CONNECTION_KEY_RE}`, `${path}.key`);
|
|
3073
|
+
return;
|
|
2408
3074
|
}
|
|
2409
|
-
if (
|
|
2410
|
-
err("
|
|
3075
|
+
if (declaredKeys.has(key)) {
|
|
3076
|
+
err("connection-declaration-invalid", `connections[${i}].key "${key}" is declared twice`, `${path}.key`);
|
|
3077
|
+
return;
|
|
2411
3078
|
}
|
|
2412
|
-
|
|
2413
|
-
|
|
2414
|
-
|
|
3079
|
+
if (typeof integrationType !== "string" || !integrationType.trim()) {
|
|
3080
|
+
err("connection-declaration-invalid", `connections[${i}] ("${key}") needs an integrationType (the catalog slug, e.g. 'github')`, `${path}.integrationType`);
|
|
3081
|
+
return;
|
|
2415
3082
|
}
|
|
2416
|
-
|
|
2417
|
-
|
|
3083
|
+
declaredKeys.add(key);
|
|
3084
|
+
});
|
|
3085
|
+
const undeclaredKey = /* @__PURE__ */ __name3((ref) => typeof ref === "string" && !declaredKeys.has(ref) && isConnectionKeyShaped(ref) && opts.connectionIds?.has(ref) !== true, "undeclaredKey");
|
|
3086
|
+
const credentialsRef = envelopeWorkspace?.credentialsRef;
|
|
3087
|
+
if (undeclaredKey(credentialsRef)) {
|
|
3088
|
+
err("connection-key-undeclared", connectionKeyUndeclaredMessage("workspace.credentialsRef", credentialsRef), "workspace.credentialsRef");
|
|
3089
|
+
}
|
|
3090
|
+
const seen = /* @__PURE__ */ new Map();
|
|
3091
|
+
let nodeCount = 0;
|
|
3092
|
+
const upstream = /* @__PURE__ */ new Set();
|
|
3093
|
+
const checkId = /* @__PURE__ */ __name3((id, path) => {
|
|
3094
|
+
nodeCount += 1;
|
|
3095
|
+
if (seen.has(id)) {
|
|
3096
|
+
err("duplicate-step-id", `step id "${id}" is declared twice (first at ${seen.get(id)})`, path, id);
|
|
3097
|
+
} else {
|
|
3098
|
+
seen.set(id, path);
|
|
2418
3099
|
}
|
|
2419
|
-
}, "
|
|
2420
|
-
const
|
|
3100
|
+
}, "checkId");
|
|
3101
|
+
const checkPolicyEnums = /* @__PURE__ */ __name3((node, path) => {
|
|
2421
3102
|
const id = singleId(node);
|
|
2422
|
-
const
|
|
2423
|
-
|
|
2424
|
-
|
|
3103
|
+
const check = /* @__PURE__ */ __name3((member, allowed) => {
|
|
3104
|
+
const value22 = node[member];
|
|
3105
|
+
if (value22 === void 0 || typeof value22 === "string" && allowed.includes(value22)) return;
|
|
3106
|
+
err("invalid-envelope", `\`${member}\` must be ${allowed.map((a) => `'${a}'`).join(" | ")} (got ${JSON.stringify(value22)})`, `${path}.${member}`, id);
|
|
3107
|
+
}, "check");
|
|
3108
|
+
check("sideEffects", WORKFLOW_SIDE_EFFECTS);
|
|
3109
|
+
check("jobResources", WORKFLOW_JOB_RESOURCES);
|
|
3110
|
+
}, "checkPolicyEnums");
|
|
3111
|
+
const checkRetry = /* @__PURE__ */ __name3((node, path) => {
|
|
3112
|
+
const r = node.retry;
|
|
3113
|
+
if (!r) return;
|
|
3114
|
+
const id = singleId(node);
|
|
3115
|
+
const unknown = unknownWorkflowRetryMembers(r);
|
|
3116
|
+
if (unknown.length) err("invalid-envelope", workflowRetryUnknownMembersMessage(unknown), `${path}.retry`, id);
|
|
3117
|
+
if (r.maxAttempts !== void 0 && !isWithinWorkflowRetryAttempts(r.maxAttempts)) {
|
|
3118
|
+
const over = typeof r.maxAttempts === "number" && r.maxAttempts > WORKFLOW_RETRY_MAX_ATTEMPTS;
|
|
3119
|
+
err(over ? "cap-exceeded" : "invalid-envelope", workflowRetryMaxAttemptsMessage(r.maxAttempts), `${path}.retry.maxAttempts`, id);
|
|
2425
3120
|
}
|
|
2426
|
-
const
|
|
2427
|
-
if (
|
|
2428
|
-
|
|
2429
|
-
|
|
3121
|
+
const backoffs = retryBackoffs();
|
|
3122
|
+
if (r.backoff !== void 0 && !backoffs.includes(r.backoff)) {
|
|
3123
|
+
const list = backoffs.map((b) => `'${b}'`).join(" | ");
|
|
3124
|
+
err("backoff-invalid", `retry.backoff must be ${list}`, `${path}.retry.backoff`, id);
|
|
3125
|
+
}
|
|
3126
|
+
if (r.backoffSeconds !== void 0 && r.backoffSeconds < 0) {
|
|
3127
|
+
err("backoff-invalid", "retry.backoffSeconds must be \u2265 0", `${path}.retry.backoffSeconds`, id);
|
|
3128
|
+
}
|
|
3129
|
+
if (r.maxBackoffSeconds !== void 0) {
|
|
3130
|
+
if (r.backoff !== "exponential") {
|
|
3131
|
+
err("backoff-invalid", "retry.maxBackoffSeconds is only meaningful with backoff:'exponential'", `${path}.retry`, id);
|
|
3132
|
+
} else if (r.maxBackoffSeconds <= 0 || r.backoffSeconds !== void 0 && r.maxBackoffSeconds < r.backoffSeconds) {
|
|
3133
|
+
err("backoff-invalid", "retry.maxBackoffSeconds must be > 0 and \u2265 backoffSeconds", `${path}.retry.maxBackoffSeconds`, id);
|
|
2430
3134
|
}
|
|
2431
|
-
|
|
3135
|
+
}
|
|
3136
|
+
}, "checkRetry");
|
|
3137
|
+
const checkTimeout = /* @__PURE__ */ __name3((node, path) => {
|
|
3138
|
+
const t = node.timeoutSeconds;
|
|
3139
|
+
if (t === void 0) return;
|
|
3140
|
+
const id = singleId(node);
|
|
3141
|
+
if (!Number.isInteger(t) || t < 1) {
|
|
3142
|
+
err("timeout-out-of-range", `timeoutSeconds must be an integer \u2265 1 (got ${t})`, `${path}.timeoutSeconds`, id);
|
|
3143
|
+
return;
|
|
3144
|
+
}
|
|
3145
|
+
if (node.tier === "job") {
|
|
3146
|
+
const cap = node.type === "agent" ? caps.maxJobTimeoutSeconds : caps.maxJobSegmentSeconds;
|
|
3147
|
+
if (t > cap) {
|
|
3148
|
+
err("job-timeout-exceeds-cap", `timeoutSeconds ${t} exceeds the Job-tier cap of ${cap} s`, `${path}.timeoutSeconds`, id);
|
|
3149
|
+
} else if (node.type === "agent" && t > caps.maxJobSegmentSeconds && !node.workspace) {
|
|
3150
|
+
err("long-job-requires-workspace", `steps longer than 4 h checkpoint to the run workspace \u2014 add workspace:{mount:'rw'} (and workspace on createWorkflow) or split the step`, `${path}.timeoutSeconds`, id);
|
|
3151
|
+
}
|
|
3152
|
+
} else if (t > caps.maxWorkerTimeoutSeconds) {
|
|
3153
|
+
err("timeout-exceeds-tier", `timeoutSeconds ${t} exceeds the worker tier's ${caps.maxWorkerTimeoutSeconds} s \u2014 steps longer than 10 min run on the Job tier: add tier:'job' (up to ${caps.maxJobSegmentSeconds} s)`, `${path}.timeoutSeconds`, id);
|
|
3154
|
+
}
|
|
3155
|
+
}, "checkTimeout");
|
|
3156
|
+
const checkSpecialistRole = /* @__PURE__ */ __name3((node, path) => {
|
|
3157
|
+
const role = node.role;
|
|
3158
|
+
const hasRef = typeof role.ref === "string";
|
|
3159
|
+
const hasInline = role.name !== void 0 || role.instructions !== void 0 || Array.isArray(role.tools) && role.tools.length > 0;
|
|
3160
|
+
if (hasRef && hasInline) {
|
|
3161
|
+
err("role-ref-and-inline", "a role is either `{ref}` or inline `{name, instructions, tools}`, never both", `${path}.role`, node.id);
|
|
3162
|
+
}
|
|
3163
|
+
if (node.agentId !== "$self") {
|
|
3164
|
+
err("ephemeral-base-not-self", "a role runs on the owner only: use '$self'", `${path}.agentId`, node.id);
|
|
3165
|
+
}
|
|
3166
|
+
if (opts.policy && opts.policy.ephemeralSpecialists !== true) {
|
|
3167
|
+
err("ephemeral-specialists-disabled", "ephemeral specialists are off for this org/agent (workflowPolicy.ephemeralSpecialists)", `${path}.role`, node.id);
|
|
3168
|
+
}
|
|
3169
|
+
let tools = Array.isArray(role.tools) ? role.tools.filter((t) => typeof t === "string") : [];
|
|
3170
|
+
if (hasRef && opts.roleLibrary) {
|
|
3171
|
+
const saved = opts.roleLibrary.get(role.ref);
|
|
3172
|
+
if (!saved) {
|
|
3173
|
+
err("role-ref-unknown", `no saved role \`${role.ref}\` in the owner's library`, `${path}.role.ref`, node.id);
|
|
3174
|
+
} else {
|
|
3175
|
+
tools = saved.tools ?? [];
|
|
3176
|
+
if (typeof role.roleHash === "string" && saved.roleHash && role.roleHash !== saved.roleHash) {
|
|
3177
|
+
warn("role-ref-stale", `saved role \`${role.ref}\` changed since this version was frozen`, `${path}.role.ref`, node.id);
|
|
3178
|
+
}
|
|
3179
|
+
}
|
|
3180
|
+
}
|
|
3181
|
+
if (tools.length && opts.toolCatalog) {
|
|
3182
|
+
const missing = tools.filter((t) => !opts.toolCatalog.has(t));
|
|
3183
|
+
if (missing.length) {
|
|
3184
|
+
err("ephemeral-tools-not-subset", `role tools not in the owner's catalog: ${missing.join(", ")}`, `${path}.role.tools`, node.id);
|
|
3185
|
+
}
|
|
3186
|
+
}
|
|
3187
|
+
}, "checkSpecialistRole");
|
|
3188
|
+
const checkRequiredConnections = /* @__PURE__ */ __name3((node, path) => {
|
|
3189
|
+
const required = node.requiredConnections;
|
|
3190
|
+
if (!Array.isArray(required)) return;
|
|
3191
|
+
const undeclared = required.filter(undeclaredKey);
|
|
3192
|
+
if (undeclared.length) {
|
|
3193
|
+
err("connection-key-undeclared", connectionKeyUndeclaredMessage(`${path}.requiredConnections`, undeclared[0]) + (undeclared.length > 1 ? ` (also undeclared: ${JSON.stringify(undeclared.slice(1))})` : ""), `${path}.requiredConnections`, singleId(node));
|
|
3194
|
+
}
|
|
3195
|
+
if (!opts.connectionIds) return;
|
|
3196
|
+
const unknown = required.filter((c) => typeof c !== "string" || !declaredKeys.has(c) && !opts.connectionIds.has(c));
|
|
3197
|
+
if (unknown.length) {
|
|
3198
|
+
err("required-connection-unknown", `requiredConnections ${JSON.stringify(unknown)} are neither declared connections[].key values nor connections the owner can mount`, `${path}.requiredConnections`, singleId(node));
|
|
3199
|
+
}
|
|
3200
|
+
}, "checkRequiredConnections");
|
|
3201
|
+
const checkTier = /* @__PURE__ */ __name3((node, path) => {
|
|
3202
|
+
const id = singleId(node);
|
|
3203
|
+
if (node.workspace && node.workspace !== "inherit" && node.tier !== void 0 && node.tier !== "job") {
|
|
3204
|
+
err("workspace-requires-job-tier", "a step mounting a workspace must be tier:'job'", `${path}.workspace`, id);
|
|
3205
|
+
}
|
|
3206
|
+
if (node.harness !== void 0 && node.tier !== "job") {
|
|
3207
|
+
err("harness-requires-job-tier", "`harness` is only legal on a tier:'job' agent step", `${path}.harness`, id);
|
|
3208
|
+
}
|
|
3209
|
+
const provider = node.type === "agent" ? classifyModelProvider(node.model) : null;
|
|
3210
|
+
if (node.harness === "claude-code" && provider !== null && provider !== "anthropic") {
|
|
3211
|
+
err("harness-provider-mismatch", `harness:'claude-code' needs an Anthropic model (model "${node.type === "agent" ? node.model : ""}" is ${provider})`, `${path}.harness`, id);
|
|
3212
|
+
}
|
|
3213
|
+
if (isJobTier(node) && provider !== null && opts.policy?.jobProviders && !opts.policy.jobProviders.includes(provider)) {
|
|
3214
|
+
err("job-tier-provider-unsupported", `model provider '${provider}' is outside LUA_WF_JOB_PROVIDERS [${opts.policy.jobProviders.join(", ")}]`, `${path}.model`, id);
|
|
3215
|
+
}
|
|
3216
|
+
}, "checkTier");
|
|
3217
|
+
const checkWorkspace = /* @__PURE__ */ __name3((node, path) => {
|
|
3218
|
+
const id = singleId(node);
|
|
3219
|
+
const ws = workspaceOf(node);
|
|
3220
|
+
if (isJobTier(node) && opts.policy && opts.policy.jobTier !== true) {
|
|
3221
|
+
err("job-tier-disabled", `"${id}" runs on the Job tier but the org's workflowPolicy.jobTier is off \u2014 an org admin enables it (lua features workflows.caps.jobTier true)`, `${path}.tier`, id);
|
|
3222
|
+
}
|
|
3223
|
+
const tools = jobToolsOf(node);
|
|
3224
|
+
if (tools !== void 0) {
|
|
3225
|
+
if (!isJobTier(node)) {
|
|
3226
|
+
err("job-tools-require-job-tier", "`jobTools` needs tier:'job'", `${path}.jobTools`, id);
|
|
3227
|
+
}
|
|
3228
|
+
const unknown = (Array.isArray(tools) ? tools : [
|
|
2432
3229
|
tools
|
|
2433
3230
|
]).filter((t) => !WORKFLOW_JOB_TOOLS.includes(t));
|
|
2434
3231
|
if (unknown.length > 0) {
|
|
@@ -2463,6 +3260,21 @@ function validateLuaExtensions(g, caps = WORKFLOW_CAPS_DEFAULT, opts = {
|
|
|
2463
3260
|
const schema = node.type === "step" ? node.step.outputSchema : node.type === "agent" ? node.outputSchema : void 0;
|
|
2464
3261
|
if (schema !== void 0) outputSchemas.set(singleId(node), schema);
|
|
2465
3262
|
}, "recordOutputSchema");
|
|
3263
|
+
const checkMapMembers = /* @__PURE__ */ __name3((cfg, basePath, id) => {
|
|
3264
|
+
for (const m of malformedMapMembers(cfg)) {
|
|
3265
|
+
warn(MAP_MEMBER_MALFORMED_CODE, mapMemberMalformedMessage(id, m), `${basePath}.${m.member}`, id);
|
|
3266
|
+
}
|
|
3267
|
+
}, "checkMapMembers");
|
|
3268
|
+
const checkInputShape = /* @__PURE__ */ __name3((node, path) => {
|
|
3269
|
+
if (node.type !== "tool" && node.type !== "workflow") return;
|
|
3270
|
+
const input = node.input;
|
|
3271
|
+
if (input === void 0) return;
|
|
3272
|
+
if (input !== null && typeof input === "object" && !Array.isArray(input)) {
|
|
3273
|
+
checkMapMembers(input, `${path}.input`, node.id);
|
|
3274
|
+
return;
|
|
3275
|
+
}
|
|
3276
|
+
err("invalid-envelope", `\`input\` must be an object map \u2014 each member a binding descriptor ({initData:true, path} | {step, path} | {value} | {template} | {requestContextPath}) or a JSON literal (got ${JSON.stringify(input)})`, `${path}.input`, node.id);
|
|
3277
|
+
}, "checkInputShape");
|
|
2466
3278
|
const checkSingle = /* @__PURE__ */ __name3((node, path, depth) => {
|
|
2467
3279
|
recordOutputSchema(node);
|
|
2468
3280
|
if (node.type === "workflow" && node.workflowId === WORKFLOW_ARM_SUBRUN_ID) {
|
|
@@ -2476,8 +3288,13 @@ function validateLuaExtensions(g, caps = WORKFLOW_CAPS_DEFAULT, opts = {
|
|
|
2476
3288
|
err("container-arm-empty", "a bare mapping arm has nothing to run", `${path}.graph.1`, node.id);
|
|
2477
3289
|
return;
|
|
2478
3290
|
}
|
|
3291
|
+
const inner = body[1];
|
|
3292
|
+
if (isHitlNode(inner)) {
|
|
3293
|
+
err("node-type-unsupported-in-container", workflowHitlArmShapeMessage(inner.type, inner.id, "mapped-arm"), `${path}.graph.1`, inner.id);
|
|
3294
|
+
return;
|
|
3295
|
+
}
|
|
2479
3296
|
upstream.add(singleId(body[1]));
|
|
2480
|
-
checkArm(body[0], `${path}.graph.0`, depth);
|
|
3297
|
+
checkArm(body[0], `${path}.graph.0`, depth, "parallel");
|
|
2481
3298
|
checkSingle(body[1], `${path}.graph.1`, depth);
|
|
2482
3299
|
upstream.add(body[0].id);
|
|
2483
3300
|
upstream.add(singleId(body[1]));
|
|
@@ -2485,6 +3302,7 @@ function validateLuaExtensions(g, caps = WORKFLOW_CAPS_DEFAULT, opts = {
|
|
|
2485
3302
|
}
|
|
2486
3303
|
checkId(singleId(node), path);
|
|
2487
3304
|
checkPolicyEnums(node, path);
|
|
3305
|
+
checkInputShape(node, path);
|
|
2488
3306
|
checkTimeout(node, path);
|
|
2489
3307
|
checkTier(node, path);
|
|
2490
3308
|
checkRetry(node, path);
|
|
@@ -2509,20 +3327,72 @@ function validateLuaExtensions(g, caps = WORKFLOW_CAPS_DEFAULT, opts = {
|
|
|
2509
3327
|
if (node.type === "workflow" && node.kind === "subrun" && depth > caps.maxNestingDepth) {
|
|
2510
3328
|
err("cap-exceeded", `nesting depth ${depth} exceeds ${caps.maxNestingDepth}`, path, node.id);
|
|
2511
3329
|
}
|
|
3330
|
+
if (node.type === "workflow" && node.workflowId !== WORKFLOW_ARM_SUBRUN_ID && typeof g.definition?.id === "string" && node.workflowId === g.definition.id) {
|
|
3331
|
+
err("subrun-cycle", `"${node.id}" starts "${node.workflowId}", which is this workflow itself`, path, node.id);
|
|
3332
|
+
}
|
|
2512
3333
|
for (const ref of nodeStepRefs(node)) {
|
|
2513
3334
|
if (!upstream.has(ref)) {
|
|
2514
3335
|
err("template-reference-unresolved", `"${singleId(node)}" references stepResults.${ref}, which is not upstream`, path, singleId(node));
|
|
2515
3336
|
}
|
|
2516
3337
|
}
|
|
2517
3338
|
}, "checkSingle");
|
|
2518
|
-
const
|
|
3339
|
+
const checkHitl = /* @__PURE__ */ __name3((node, path) => {
|
|
3340
|
+
if (node.type === "waitForSignal") {
|
|
3341
|
+
const w = node;
|
|
3342
|
+
checkId(w.id, path);
|
|
3343
|
+
if (typeof w.signal !== "string" || w.signal.length === 0) err("invalid-envelope", "waitForSignal.signal is required", `${path}.signal`, w.id);
|
|
3344
|
+
return;
|
|
3345
|
+
}
|
|
3346
|
+
const a = node;
|
|
3347
|
+
checkId(a.id, path);
|
|
3348
|
+
if (a.approver === "creator" && a.excludeInitiator === true) {
|
|
3349
|
+
err("approver-excludes-only-candidate", "approver:'creator' with excludeInitiator:true always excludes the only candidate", path, a.id);
|
|
3350
|
+
}
|
|
3351
|
+
if (a.fourEyes !== void 0 && a.editable !== true) {
|
|
3352
|
+
err("four-eyes-requires-editable", "`fourEyes` requires editable:true", `${path}.fourEyes`, a.id);
|
|
3353
|
+
}
|
|
3354
|
+
if ((a.editablePaths !== void 0 || a.editedPayloadSchema !== void 0) && a.editable !== true) {
|
|
3355
|
+
err("editable-path-invalid", "`editablePaths` / `editedPayloadSchema` require editable:true", `${path}.editablePaths`, a.id);
|
|
3356
|
+
}
|
|
3357
|
+
for (const p of a.editablePaths ?? []) {
|
|
3358
|
+
if (!EDITABLE_PATH_RE.test(p)) err("editable-path-invalid", `editablePaths entry "${p}" is outside the seg(.seg)*[*]/[n] grammar`, `${path}.editablePaths`, a.id);
|
|
3359
|
+
}
|
|
3360
|
+
if (Array.isArray(a.onTimeout)) {
|
|
3361
|
+
const chain = a.onTimeout;
|
|
3362
|
+
const hops = chain.filter((h) => typeof h === "object" && h !== null && "escalateTo" in h);
|
|
3363
|
+
if (hops.length > 3) err("escalation-chain-too-long", "an onTimeout chain carries at most 3 escalation hops", `${path}.onTimeout`, a.id);
|
|
3364
|
+
const last = chain[chain.length - 1];
|
|
3365
|
+
if (last === void 0 || typeof last === "object" && last !== null && "escalateTo" in last) {
|
|
3366
|
+
err("escalation-chain-not-terminal", "an onTimeout chain must end in a terminal member", `${path}.onTimeout`, a.id);
|
|
3367
|
+
}
|
|
3368
|
+
}
|
|
3369
|
+
if (typeof a.details === "string") {
|
|
3370
|
+
for (const ref of templateStepRefs(a.details)) {
|
|
3371
|
+
if (!upstream.has(ref)) err("template-reference-unresolved", `"${a.id}" references stepResults.${ref}, which is not upstream`, path, a.id);
|
|
3372
|
+
}
|
|
3373
|
+
}
|
|
3374
|
+
}, "checkHitl");
|
|
3375
|
+
const checkHitlArm = /* @__PURE__ */ __name3((node, path, container) => {
|
|
3376
|
+
if (!workflowContainerRunsHitlArm(container)) {
|
|
3377
|
+
checkId(node.id, path);
|
|
3378
|
+
err("node-type-unsupported-in-container", workflowHitlArmUnsupportedMessage(node.type, node.id, container), path, node.id);
|
|
3379
|
+
return;
|
|
3380
|
+
}
|
|
3381
|
+
checkHitl(node, path);
|
|
3382
|
+
}, "checkHitlArm");
|
|
3383
|
+
const checkArm = /* @__PURE__ */ __name3((arm, path, depth, container) => {
|
|
2519
3384
|
if (arm.type === "mapping") {
|
|
2520
3385
|
checkId(arm.id, path);
|
|
3386
|
+
checkMapMembers(readMapConfig(arm.mapConfig), `${path}.mapConfig`, arm.id);
|
|
2521
3387
|
for (const ref of nodeStepRefs(arm)) {
|
|
2522
3388
|
if (!upstream.has(ref)) err("template-reference-unresolved", `"${arm.id}" references stepResults.${ref}, which is not upstream`, path, arm.id);
|
|
2523
3389
|
}
|
|
2524
3390
|
return;
|
|
2525
3391
|
}
|
|
3392
|
+
if (isHitlNode(arm)) {
|
|
3393
|
+
checkHitlArm(arm, path, container);
|
|
3394
|
+
return;
|
|
3395
|
+
}
|
|
2526
3396
|
checkSingle(arm, path, depth);
|
|
2527
3397
|
}, "checkArm");
|
|
2528
3398
|
graph.forEach((entry, i) => {
|
|
@@ -2538,6 +3408,7 @@ function validateLuaExtensions(g, caps = WORKFLOW_CAPS_DEFAULT, opts = {
|
|
|
2538
3408
|
break;
|
|
2539
3409
|
case "mapping":
|
|
2540
3410
|
checkId(entry.id, path);
|
|
3411
|
+
checkMapMembers(readMapConfig(entry.mapConfig), `${path}.mapConfig`, entry.id);
|
|
2541
3412
|
for (const ref of nodeStepRefs(entry)) {
|
|
2542
3413
|
if (!upstream.has(ref)) err("template-reference-unresolved", `"${entry.id}" references stepResults.${ref}, which is not upstream`, path, entry.id);
|
|
2543
3414
|
}
|
|
@@ -2572,18 +3443,15 @@ function validateLuaExtensions(g, caps = WORKFLOW_CAPS_DEFAULT, opts = {
|
|
|
2572
3443
|
err("mapping-placement", "a bare mapping cannot be a parallel arm \u2014 chain it as [map, step]", armPath);
|
|
2573
3444
|
return;
|
|
2574
3445
|
}
|
|
2575
|
-
|
|
2576
|
-
err("approval-inside-container", "approval / waitForSignal are top-level only in v1", armPath);
|
|
2577
|
-
return;
|
|
2578
|
-
}
|
|
2579
|
-
checkSingle(arm, armPath, 1);
|
|
3446
|
+
checkArm(arm, armPath, 1, "parallel");
|
|
2580
3447
|
declared.push(singleId(arm));
|
|
2581
3448
|
});
|
|
2582
|
-
const
|
|
3449
|
+
const executableArms = p.steps.filter(isSingleStep);
|
|
3450
|
+
const worktreeArms = executableArms.filter((a) => a.workspace?.isolation === "worktree");
|
|
2583
3451
|
if (worktreeArms.length > 0 && !p.merge) err("worktree-arms-require-merge", "worktree arms need a `merge` policy", path);
|
|
2584
3452
|
if (worktreeArms.length === 0 && p.merge) err("merge-requires-worktree-arms", "`merge` needs at least one worktree arm", path);
|
|
2585
3453
|
if (worktreeArms.length > WORKFLOW_JOB_MAX_WORKTREE_ARMS) err("worktree-arms-exceed-cap", `at most ${WORKFLOW_JOB_MAX_WORKTREE_ARMS} worktree arms per parallel`, path);
|
|
2586
|
-
const sharedArms =
|
|
3454
|
+
const sharedArms = executableArms.filter((a) => {
|
|
2587
3455
|
const w = workspaceOf(a);
|
|
2588
3456
|
if (!w || w === "inherit" || w.isolation === "worktree") return false;
|
|
2589
3457
|
return !(envelopeWorkspace?.backend === "efs" && w.mount === "ro");
|
|
@@ -2600,11 +3468,11 @@ function validateLuaExtensions(g, caps = WORKFLOW_CAPS_DEFAULT, opts = {
|
|
|
2600
3468
|
if (!isWellFormedPredicate(p)) err("closure-predicate", "a conditional predicate must be a well-formed LuaPredicate object ({op, left/right | value | path | args | arg}), not a function or an expression string", `${path}.predicates.${j}`);
|
|
2601
3469
|
});
|
|
2602
3470
|
c.steps.forEach((arm, j) => {
|
|
2603
|
-
checkArm(arm, `${path}.steps.${j}`, 1);
|
|
3471
|
+
checkArm(arm, `${path}.steps.${j}`, 1, "conditional");
|
|
2604
3472
|
declared.push(armId(arm));
|
|
2605
3473
|
});
|
|
2606
3474
|
if (c.otherwise) {
|
|
2607
|
-
checkArm(c.otherwise, `${path}.otherwise`, 1);
|
|
3475
|
+
checkArm(c.otherwise, `${path}.otherwise`, 1, "conditional");
|
|
2608
3476
|
declared.push(armId(c.otherwise));
|
|
2609
3477
|
}
|
|
2610
3478
|
break;
|
|
@@ -2627,8 +3495,9 @@ function validateLuaExtensions(g, caps = WORKFLOW_CAPS_DEFAULT, opts = {
|
|
|
2627
3495
|
}
|
|
2628
3496
|
if (o.chunk !== void 0) {
|
|
2629
3497
|
const max = o.maxItems ?? WORKFLOW_FOREACH_DEFAULT_MAX_ITEMS;
|
|
2630
|
-
|
|
2631
|
-
|
|
3498
|
+
const size = typeof o.chunk === "number" ? o.chunk : o.chunk.size;
|
|
3499
|
+
if (!Number.isInteger(size) || size < 1 || size > max) {
|
|
3500
|
+
err("chunk-size-invalid", `foreach.chunk.size must be an integer in [1, ${max}]`, typeof o.chunk === "number" ? `${path}.opts.chunk` : `${path}.opts.chunk.size`);
|
|
2632
3501
|
}
|
|
2633
3502
|
}
|
|
2634
3503
|
if (o.rateLimit !== void 0) {
|
|
@@ -2645,12 +3514,7 @@ function validateLuaExtensions(g, caps = WORKFLOW_CAPS_DEFAULT, opts = {
|
|
|
2645
3514
|
const bodyType = f.step.type;
|
|
2646
3515
|
const prevEntry = i > 0 ? graph[i - 1] : void 0;
|
|
2647
3516
|
if (bodyType !== "mapping" && prevEntry?.type === "mapping" && prevEntry.id === `${singleId(f.step)}_items`) {
|
|
2648
|
-
|
|
2649
|
-
try {
|
|
2650
|
-
cfg = JSON.parse(prevEntry.mapConfig);
|
|
2651
|
-
} catch {
|
|
2652
|
-
cfg = void 0;
|
|
2653
|
-
}
|
|
3517
|
+
const cfg = readMapConfig(prevEntry.mapConfig);
|
|
2654
3518
|
const d = cfg?.[""];
|
|
2655
3519
|
let arrayLike;
|
|
2656
3520
|
if (d && "value" in d) arrayLike = Array.isArray(d.value);
|
|
@@ -2662,8 +3526,13 @@ function validateLuaExtensions(g, caps = WORKFLOW_CAPS_DEFAULT, opts = {
|
|
|
2662
3526
|
if (arrayLike === false) err("foreach-items-not-array", `foreach({items}) for "${singleId(f.step)}" binds a value that is not an array`, `${path}.step`, singleId(f.step));
|
|
2663
3527
|
}
|
|
2664
3528
|
if (bodyType === "mapping") err("container-arm-empty", "a foreach body needs a step, not a bare mapping", `${path}.step`);
|
|
2665
|
-
else if (
|
|
2666
|
-
|
|
3529
|
+
else if (isHitlNode(f.step)) {
|
|
3530
|
+
if (o.chunk !== void 0) {
|
|
3531
|
+
checkId(f.step.id, `${path}.step`);
|
|
3532
|
+
err("node-type-unsupported-in-container", workflowHitlArmShapeMessage(f.step.type, f.step.id, "chunked-foreach"), `${path}.step`, f.step.id);
|
|
3533
|
+
} else checkHitlArm(f.step, `${path}.step`, "foreach");
|
|
3534
|
+
declared.push(f.step.id);
|
|
3535
|
+
} else {
|
|
2667
3536
|
checkSingle(f.step, `${path}.step`, o.chunk ? 2 : 1);
|
|
2668
3537
|
declared.push(singleId(f.step));
|
|
2669
3538
|
}
|
|
@@ -2680,52 +3549,20 @@ function validateLuaExtensions(g, caps = WORKFLOW_CAPS_DEFAULT, opts = {
|
|
|
2680
3549
|
if (!isWellFormedPredicate(l.predicate)) err("closure-predicate", "a loop predicate must be a well-formed LuaPredicate object ({op, left/right | value | path | args | arg}), not a function or an expression string", `${path}.predicate`);
|
|
2681
3550
|
const bodyType = l.step.type;
|
|
2682
3551
|
if (bodyType === "mapping") err("container-arm-empty", "a loop body needs a step, not a bare mapping", `${path}.step`);
|
|
2683
|
-
else if (
|
|
2684
|
-
|
|
3552
|
+
else if (isHitlNode(l.step)) {
|
|
3553
|
+
checkHitlArm(l.step, `${path}.step`, "loop");
|
|
3554
|
+
declared.push(l.step.id);
|
|
3555
|
+
} else {
|
|
2685
3556
|
checkSingle(l.step, `${path}.step`, 1);
|
|
2686
3557
|
declared.push(singleId(l.step));
|
|
2687
3558
|
}
|
|
2688
3559
|
break;
|
|
2689
3560
|
}
|
|
2690
|
-
case "approval":
|
|
2691
|
-
|
|
2692
|
-
|
|
2693
|
-
|
|
2694
|
-
err("approver-excludes-only-candidate", "approver:'creator' with excludeInitiator:true always excludes the only candidate", path, a.id);
|
|
2695
|
-
}
|
|
2696
|
-
if (a.fourEyes !== void 0 && a.editable !== true) {
|
|
2697
|
-
err("four-eyes-requires-editable", "`fourEyes` requires editable:true", `${path}.fourEyes`, a.id);
|
|
2698
|
-
}
|
|
2699
|
-
if ((a.editablePaths !== void 0 || a.editedPayloadSchema !== void 0) && a.editable !== true) {
|
|
2700
|
-
err("editable-path-invalid", "`editablePaths` / `editedPayloadSchema` require editable:true", `${path}.editablePaths`, a.id);
|
|
2701
|
-
}
|
|
2702
|
-
for (const p of a.editablePaths ?? []) {
|
|
2703
|
-
if (!EDITABLE_PATH_RE.test(p)) err("editable-path-invalid", `editablePaths entry "${p}" is outside the seg(.seg)*[*]/[n] grammar`, `${path}.editablePaths`, a.id);
|
|
2704
|
-
}
|
|
2705
|
-
if (Array.isArray(a.onTimeout)) {
|
|
2706
|
-
const chain = a.onTimeout;
|
|
2707
|
-
const hops = chain.filter((h) => typeof h === "object" && h !== null && "escalateTo" in h);
|
|
2708
|
-
if (hops.length > 3) err("escalation-chain-too-long", "an onTimeout chain carries at most 3 escalation hops", `${path}.onTimeout`, a.id);
|
|
2709
|
-
const last = chain[chain.length - 1];
|
|
2710
|
-
if (last === void 0 || typeof last === "object" && last !== null && "escalateTo" in last) {
|
|
2711
|
-
err("escalation-chain-not-terminal", "an onTimeout chain must end in a terminal member", `${path}.onTimeout`, a.id);
|
|
2712
|
-
}
|
|
2713
|
-
}
|
|
2714
|
-
if (typeof a.details === "string") {
|
|
2715
|
-
for (const ref of templateStepRefs(a.details)) {
|
|
2716
|
-
if (!upstream.has(ref)) err("template-reference-unresolved", `"${a.id}" references stepResults.${ref}, which is not upstream`, path, a.id);
|
|
2717
|
-
}
|
|
2718
|
-
}
|
|
2719
|
-
declared.push(a.id);
|
|
2720
|
-
break;
|
|
2721
|
-
}
|
|
2722
|
-
case "waitForSignal": {
|
|
2723
|
-
const w = entry;
|
|
2724
|
-
checkId(w.id, path);
|
|
2725
|
-
if (typeof w.signal !== "string" || w.signal.length === 0) err("invalid-envelope", "waitForSignal.signal is required", `${path}.signal`, w.id);
|
|
2726
|
-
declared.push(w.id);
|
|
3561
|
+
case "approval":
|
|
3562
|
+
case "waitForSignal":
|
|
3563
|
+
checkHitl(entry, path);
|
|
3564
|
+
declared.push(entry.id);
|
|
2727
3565
|
break;
|
|
2728
|
-
}
|
|
2729
3566
|
default:
|
|
2730
3567
|
err("invalid-envelope", `unknown entry type "${entry.type}"`, path);
|
|
2731
3568
|
}
|
|
@@ -2846,14 +3683,9 @@ var WorkflowPlanError = class extends Error {
|
|
|
2846
3683
|
this.name = "WorkflowPlanError";
|
|
2847
3684
|
}
|
|
2848
3685
|
};
|
|
2849
|
-
var
|
|
2850
|
-
|
|
2851
|
-
|
|
2852
|
-
tool: "tool",
|
|
2853
|
-
workflow: "subrun"
|
|
2854
|
-
};
|
|
2855
|
-
var isSingleStep = /* @__PURE__ */ __name3((e) => e.type === "step" || e.type === "agent" || e.type === "tool" || e.type === "workflow", "isSingleStep");
|
|
2856
|
-
var singleStepId = /* @__PURE__ */ __name3((e) => e.type === "step" ? e.step.id : e.id, "singleStepId");
|
|
3686
|
+
var isArmStep = /* @__PURE__ */ __name3((e) => isWorkflowArmEntryType(e.type), "isArmStep");
|
|
3687
|
+
var armStepId = /* @__PURE__ */ __name3((e) => e.type === "step" ? e.step.id : e.id, "armStepId");
|
|
3688
|
+
var armStepKind = /* @__PURE__ */ __name3((e) => WORKFLOW_ARM_ENTRY_STEP_KINDS[e.type], "armStepKind");
|
|
2857
3689
|
var joinIdOf = /* @__PURE__ */ __name3((entryId) => `${entryId}.join`, "joinIdOf");
|
|
2858
3690
|
var containerIdOf = /* @__PURE__ */ __name3((type, entryIndex) => `${type}@${entryIndex}`, "containerIdOf");
|
|
2859
3691
|
function compilePlan(g) {
|
|
@@ -2869,10 +3701,10 @@ function compilePlan(g) {
|
|
|
2869
3701
|
let prevTails = [];
|
|
2870
3702
|
const foreachJoinToEntry = /* @__PURE__ */ new Map();
|
|
2871
3703
|
g.definition.graph.forEach((entry, entryIndex) => {
|
|
2872
|
-
if (
|
|
2873
|
-
const id =
|
|
3704
|
+
if (isArmStep(entry)) {
|
|
3705
|
+
const id = armStepId(entry);
|
|
2874
3706
|
addNode(id, {
|
|
2875
|
-
kind:
|
|
3707
|
+
kind: armStepKind(entry),
|
|
2876
3708
|
dependsOn: prevTails,
|
|
2877
3709
|
downstream: [],
|
|
2878
3710
|
unsatisfiedDeps: prevTails.length,
|
|
@@ -2897,9 +3729,8 @@ function compilePlan(g) {
|
|
|
2897
3729
|
];
|
|
2898
3730
|
return;
|
|
2899
3731
|
case "sleep":
|
|
2900
|
-
case "sleepUntil":
|
|
2901
|
-
|
|
2902
|
-
const kind = entry.type === "approval" ? "approval" : entry.type;
|
|
3732
|
+
case "sleepUntil": {
|
|
3733
|
+
const kind = entry.type;
|
|
2903
3734
|
addNode(entry.id, {
|
|
2904
3735
|
kind,
|
|
2905
3736
|
dependsOn: prevTails,
|
|
@@ -2912,24 +3743,12 @@ function compilePlan(g) {
|
|
|
2912
3743
|
];
|
|
2913
3744
|
return;
|
|
2914
3745
|
}
|
|
2915
|
-
case "waitForSignal":
|
|
2916
|
-
addNode(entry.id, {
|
|
2917
|
-
kind: "signal",
|
|
2918
|
-
dependsOn: prevTails,
|
|
2919
|
-
downstream: [],
|
|
2920
|
-
unsatisfiedDeps: prevTails.length,
|
|
2921
|
-
entry
|
|
2922
|
-
});
|
|
2923
|
-
prevTails = [
|
|
2924
|
-
entry.id
|
|
2925
|
-
];
|
|
2926
|
-
return;
|
|
2927
3746
|
case "parallel": {
|
|
2928
3747
|
const entryId = containerIdOf("parallel", entryIndex);
|
|
2929
3748
|
const childIds = entry.steps.map((arm) => {
|
|
2930
|
-
const childId =
|
|
3749
|
+
const childId = armStepId(arm);
|
|
2931
3750
|
addNode(childId, {
|
|
2932
|
-
kind:
|
|
3751
|
+
kind: armStepKind(arm),
|
|
2933
3752
|
dependsOn: prevTails,
|
|
2934
3753
|
downstream: [],
|
|
2935
3754
|
unsatisfiedDeps: prevTails.length,
|
|
@@ -2967,9 +3786,9 @@ function compilePlan(g) {
|
|
|
2967
3786
|
node.otherwise
|
|
2968
3787
|
] : node.steps;
|
|
2969
3788
|
const childIds = arms.map((arm) => {
|
|
2970
|
-
const childId = arm.type === "mapping" ? arm.id :
|
|
3789
|
+
const childId = arm.type === "mapping" ? arm.id : armStepId(arm);
|
|
2971
3790
|
addNode(childId, {
|
|
2972
|
-
kind: arm.type === "mapping" ? "map" :
|
|
3791
|
+
kind: arm.type === "mapping" ? "map" : armStepKind(arm),
|
|
2973
3792
|
dependsOn: [
|
|
2974
3793
|
entryId
|
|
2975
3794
|
],
|
|
@@ -3062,496 +3881,274 @@ function resolvePath(rawPath, ctx) {
|
|
|
3062
3881
|
root = ctx.inputData;
|
|
3063
3882
|
break;
|
|
3064
3883
|
case "state":
|
|
3065
|
-
root = ctx.state;
|
|
3066
|
-
break;
|
|
3067
|
-
case "stepResults": {
|
|
3068
|
-
if (!rest) return MISSING;
|
|
3069
|
-
const innerDot = rest.indexOf(".");
|
|
3070
|
-
const stepId = innerDot === -1 ? rest : rest.slice(0, innerDot);
|
|
3071
|
-
const subPath = innerDot === -1 ? "" : rest.slice(innerDot + 1);
|
|
3072
|
-
let stepResult;
|
|
3073
|
-
if (ctx.stepResults && stepId in ctx.stepResults) stepResult = ctx.stepResults[stepId];
|
|
3074
|
-
else if (ctx.getStepResult) {
|
|
3075
|
-
try {
|
|
3076
|
-
stepResult = ctx.getStepResult(stepId);
|
|
3077
|
-
} catch {
|
|
3078
|
-
return MISSING;
|
|
3079
|
-
}
|
|
3080
|
-
} else return MISSING;
|
|
3081
|
-
if (stepResult === void 0 || stepResult === null) return MISSING;
|
|
3082
|
-
return walk(stepResult, subPath);
|
|
3083
|
-
}
|
|
3084
|
-
default:
|
|
3085
|
-
return MISSING;
|
|
3086
|
-
}
|
|
3087
|
-
return walk(root, rest);
|
|
3088
|
-
}
|
|
3089
|
-
__name(resolvePath, "resolvePath");
|
|
3090
|
-
__name3(resolvePath, "resolvePath");
|
|
3091
|
-
function walk(root, path) {
|
|
3092
|
-
if (path === "") return root;
|
|
3093
|
-
const parts = path.split(".");
|
|
3094
|
-
let value22 = root;
|
|
3095
|
-
for (const part of parts) {
|
|
3096
|
-
if (value22 === null || value22 === void 0) return MISSING;
|
|
3097
|
-
if (typeof value22 !== "object") return MISSING;
|
|
3098
|
-
const record = value22;
|
|
3099
|
-
if (!(part in record)) return MISSING;
|
|
3100
|
-
value22 = record[part];
|
|
3101
|
-
}
|
|
3102
|
-
return value22;
|
|
3103
|
-
}
|
|
3104
|
-
__name(walk, "walk");
|
|
3105
|
-
__name3(walk, "walk");
|
|
3106
|
-
function resolveValue(ref, ctx) {
|
|
3107
|
-
if ("literal" in ref) return ref.literal;
|
|
3108
|
-
return resolvePath(ref.path, ctx);
|
|
3109
|
-
}
|
|
3110
|
-
__name(resolveValue, "resolveValue");
|
|
3111
|
-
__name3(resolveValue, "resolveValue");
|
|
3112
|
-
function evaluatePredicate(pred, ctx) {
|
|
3113
|
-
switch (pred.op) {
|
|
3114
|
-
case "and":
|
|
3115
|
-
return pred.args.every((arg) => evaluatePredicate(arg, ctx));
|
|
3116
|
-
case "or":
|
|
3117
|
-
return pred.args.some((arg) => evaluatePredicate(arg, ctx));
|
|
3118
|
-
case "not":
|
|
3119
|
-
return !evaluatePredicate(pred.arg, ctx);
|
|
3120
|
-
case "exists":
|
|
3121
|
-
return resolvePath(pred.path, ctx) !== MISSING;
|
|
3122
|
-
case "notExists":
|
|
3123
|
-
return resolvePath(pred.path, ctx) === MISSING;
|
|
3124
|
-
case "truthy":
|
|
3125
|
-
case "falsy": {
|
|
3126
|
-
const v = resolveValue(pred.value, ctx);
|
|
3127
|
-
const truthy22 = v !== MISSING && Boolean(v);
|
|
3128
|
-
return pred.op === "truthy" ? truthy22 : !truthy22;
|
|
3129
|
-
}
|
|
3130
|
-
case "in":
|
|
3131
|
-
case "notIn": {
|
|
3132
|
-
const v = resolveValue(pred.value, ctx);
|
|
3133
|
-
if (v === MISSING) return pred.op === "notIn";
|
|
3134
|
-
const member = pred.set.some((candidate) => candidate === v);
|
|
3135
|
-
return pred.op === "in" ? member : !member;
|
|
3136
|
-
}
|
|
3137
|
-
case "eq":
|
|
3138
|
-
case "ne":
|
|
3139
|
-
case "lt":
|
|
3140
|
-
case "lte":
|
|
3141
|
-
case "gt":
|
|
3142
|
-
case "gte": {
|
|
3143
|
-
const left = resolveValue(pred.left, ctx);
|
|
3144
|
-
const right = resolveValue(pred.right, ctx);
|
|
3145
|
-
if (left === MISSING || right === MISSING) return false;
|
|
3146
|
-
return compare(pred.op, left, right);
|
|
3147
|
-
}
|
|
3148
|
-
}
|
|
3149
|
-
}
|
|
3150
|
-
__name(evaluatePredicate, "evaluatePredicate");
|
|
3151
|
-
__name3(evaluatePredicate, "evaluatePredicate");
|
|
3152
|
-
function compare(op, left, right) {
|
|
3153
|
-
if (op === "eq") return left === right;
|
|
3154
|
-
if (op === "ne") return left !== right;
|
|
3155
|
-
if (typeof left === "number" && typeof right === "number" || typeof left === "string" && typeof right === "string") {
|
|
3156
|
-
switch (op) {
|
|
3157
|
-
case "lt":
|
|
3158
|
-
return left < right;
|
|
3159
|
-
case "lte":
|
|
3160
|
-
return left <= right;
|
|
3161
|
-
case "gt":
|
|
3162
|
-
return left > right;
|
|
3163
|
-
case "gte":
|
|
3164
|
-
return left >= right;
|
|
3165
|
-
}
|
|
3166
|
-
}
|
|
3167
|
-
return false;
|
|
3168
|
-
}
|
|
3169
|
-
__name(compare, "compare");
|
|
3170
|
-
__name3(compare, "compare");
|
|
3171
|
-
function derivePredicateLabel(pred, maxLength = 80) {
|
|
3172
|
-
const raw = renderPredicate(pred);
|
|
3173
|
-
if (raw.length <= maxLength) return raw;
|
|
3174
|
-
return raw.slice(0, maxLength - 1) + "\u2026";
|
|
3175
|
-
}
|
|
3176
|
-
__name(derivePredicateLabel, "derivePredicateLabel");
|
|
3177
|
-
__name3(derivePredicateLabel, "derivePredicateLabel");
|
|
3178
|
-
function renderPredicate(pred) {
|
|
3179
|
-
switch (pred.op) {
|
|
3180
|
-
case "and":
|
|
3181
|
-
case "or":
|
|
3182
|
-
return pred.args.map((arg) => wrapLabel(arg, renderPredicate(arg))).join(pred.op === "and" ? " AND " : " OR ");
|
|
3183
|
-
case "not":
|
|
3184
|
-
return `NOT ${wrapLabel(pred.arg, renderPredicate(pred.arg))}`;
|
|
3185
|
-
case "exists":
|
|
3186
|
-
return `${pred.path} exists`;
|
|
3187
|
-
case "notExists":
|
|
3188
|
-
return `${pred.path} missing`;
|
|
3189
|
-
case "truthy":
|
|
3190
|
-
return `${renderRef(pred.value)} is truthy`;
|
|
3191
|
-
case "falsy":
|
|
3192
|
-
return `${renderRef(pred.value)} is falsy`;
|
|
3193
|
-
case "in":
|
|
3194
|
-
return `${renderRef(pred.value)} in ${JSON.stringify(pred.set)}`;
|
|
3195
|
-
case "notIn":
|
|
3196
|
-
return `${renderRef(pred.value)} not in ${JSON.stringify(pred.set)}`;
|
|
3197
|
-
case "eq":
|
|
3198
|
-
return `${renderRef(pred.left)} == ${renderRef(pred.right)}`;
|
|
3199
|
-
case "ne":
|
|
3200
|
-
return `${renderRef(pred.left)} != ${renderRef(pred.right)}`;
|
|
3201
|
-
case "lt":
|
|
3202
|
-
return `${renderRef(pred.left)} < ${renderRef(pred.right)}`;
|
|
3203
|
-
case "lte":
|
|
3204
|
-
return `${renderRef(pred.left)} <= ${renderRef(pred.right)}`;
|
|
3205
|
-
case "gt":
|
|
3206
|
-
return `${renderRef(pred.left)} > ${renderRef(pred.right)}`;
|
|
3207
|
-
case "gte":
|
|
3208
|
-
return `${renderRef(pred.left)} >= ${renderRef(pred.right)}`;
|
|
3209
|
-
}
|
|
3210
|
-
}
|
|
3211
|
-
__name(renderPredicate, "renderPredicate");
|
|
3212
|
-
__name3(renderPredicate, "renderPredicate");
|
|
3213
|
-
function wrapLabel(child, rendered) {
|
|
3214
|
-
return child.op === "and" || child.op === "or" || child.op === "not" ? `(${rendered})` : rendered;
|
|
3215
|
-
}
|
|
3216
|
-
__name(wrapLabel, "wrapLabel");
|
|
3217
|
-
__name3(wrapLabel, "wrapLabel");
|
|
3218
|
-
function renderRef(ref) {
|
|
3219
|
-
if ("literal" in ref) return JSON.stringify(ref.literal);
|
|
3220
|
-
return ref.path;
|
|
3221
|
-
}
|
|
3222
|
-
__name(renderRef, "renderRef");
|
|
3223
|
-
__name3(renderRef, "renderRef");
|
|
3224
|
-
var stepIdOf = /* @__PURE__ */ __name3((s) => typeof s === "string" ? s : s.id, "stepIdOf");
|
|
3225
|
-
function step(s) {
|
|
3226
|
-
const id = stepIdOf(s);
|
|
3227
|
-
return {
|
|
3228
|
-
path: /* @__PURE__ */ __name3((p) => ({
|
|
3229
|
-
path: p === "" ? `stepResults.${id}` : `stepResults.${id}.${p}`
|
|
3230
|
-
}), "path")
|
|
3231
|
-
};
|
|
3232
|
-
}
|
|
3233
|
-
__name(step, "step");
|
|
3234
|
-
__name3(step, "step");
|
|
3235
|
-
function stepOf(id) {
|
|
3236
|
-
return step(id);
|
|
3237
|
-
}
|
|
3238
|
-
__name(stepOf, "stepOf");
|
|
3239
|
-
__name3(stepOf, "stepOf");
|
|
3240
|
-
function init(path) {
|
|
3241
|
-
return {
|
|
3242
|
-
path: path === "" ? "initData" : `initData.${path}`
|
|
3243
|
-
};
|
|
3244
|
-
}
|
|
3245
|
-
__name(init, "init");
|
|
3246
|
-
__name3(init, "init");
|
|
3247
|
-
function state(path) {
|
|
3248
|
-
return {
|
|
3249
|
-
path: path === "" ? "state" : `state.${path}`
|
|
3250
|
-
};
|
|
3251
|
-
}
|
|
3252
|
-
__name(state, "state");
|
|
3253
|
-
__name3(state, "state");
|
|
3254
|
-
function lit(v) {
|
|
3255
|
-
return {
|
|
3256
|
-
literal: v
|
|
3257
|
-
};
|
|
3258
|
-
}
|
|
3259
|
-
__name(lit, "lit");
|
|
3260
|
-
__name3(lit, "lit");
|
|
3261
|
-
function toPathOrLiteral(v) {
|
|
3262
|
-
if (typeof v === "object" && v !== null) {
|
|
3263
|
-
if ("path" in v) return {
|
|
3264
|
-
path: v.path
|
|
3265
|
-
};
|
|
3266
|
-
if ("literal" in v) return {
|
|
3267
|
-
literal: v.literal
|
|
3268
|
-
};
|
|
3269
|
-
}
|
|
3270
|
-
return {
|
|
3271
|
-
literal: v
|
|
3272
|
-
};
|
|
3273
|
-
}
|
|
3274
|
-
__name(toPathOrLiteral, "toPathOrLiteral");
|
|
3275
|
-
__name3(toPathOrLiteral, "toPathOrLiteral");
|
|
3276
|
-
var cmp = /* @__PURE__ */ __name3((op) => (l, r) => ({
|
|
3277
|
-
op,
|
|
3278
|
-
left: toPathOrLiteral(l),
|
|
3279
|
-
right: toPathOrLiteral(r)
|
|
3280
|
-
}), "cmp");
|
|
3281
|
-
var eq = cmp("eq");
|
|
3282
|
-
var ne = cmp("ne");
|
|
3283
|
-
var gt = cmp("gt");
|
|
3284
|
-
var gte = cmp("gte");
|
|
3285
|
-
var lt = cmp("lt");
|
|
3286
|
-
var lte = cmp("lte");
|
|
3287
|
-
var inSet = /* @__PURE__ */ __name3((v, set) => ({
|
|
3288
|
-
op: "in",
|
|
3289
|
-
value: {
|
|
3290
|
-
path: v.path
|
|
3291
|
-
},
|
|
3292
|
-
set
|
|
3293
|
-
}), "inSet");
|
|
3294
|
-
var notIn = /* @__PURE__ */ __name3((v, set) => ({
|
|
3295
|
-
op: "notIn",
|
|
3296
|
-
value: {
|
|
3297
|
-
path: v.path
|
|
3298
|
-
},
|
|
3299
|
-
set
|
|
3300
|
-
}), "notIn");
|
|
3301
|
-
var exists = /* @__PURE__ */ __name3((ref) => ({
|
|
3302
|
-
op: "exists",
|
|
3303
|
-
path: ref.path
|
|
3304
|
-
}), "exists");
|
|
3305
|
-
var notExists = /* @__PURE__ */ __name3((ref) => ({
|
|
3306
|
-
op: "notExists",
|
|
3307
|
-
path: ref.path
|
|
3308
|
-
}), "notExists");
|
|
3309
|
-
var truthy = /* @__PURE__ */ __name3((ref) => ({
|
|
3310
|
-
op: "truthy",
|
|
3311
|
-
value: {
|
|
3312
|
-
path: ref.path
|
|
3313
|
-
}
|
|
3314
|
-
}), "truthy");
|
|
3315
|
-
var falsy = /* @__PURE__ */ __name3((ref) => ({
|
|
3316
|
-
op: "falsy",
|
|
3317
|
-
value: {
|
|
3318
|
-
path: ref.path
|
|
3319
|
-
}
|
|
3320
|
-
}), "falsy");
|
|
3321
|
-
var and = /* @__PURE__ */ __name3((...args) => ({
|
|
3322
|
-
op: "and",
|
|
3323
|
-
args
|
|
3324
|
-
}), "and");
|
|
3325
|
-
var or = /* @__PURE__ */ __name3((...args) => ({
|
|
3326
|
-
op: "or",
|
|
3327
|
-
args
|
|
3328
|
-
}), "or");
|
|
3329
|
-
var not = /* @__PURE__ */ __name3((arg) => ({
|
|
3330
|
-
op: "not",
|
|
3331
|
-
arg
|
|
3332
|
-
}), "not");
|
|
3333
|
-
var WorkflowTemplateError = class extends Error {
|
|
3334
|
-
static {
|
|
3335
|
-
__name(this, "WorkflowTemplateError");
|
|
3336
|
-
}
|
|
3337
|
-
static {
|
|
3338
|
-
__name3(this, "WorkflowTemplateError");
|
|
3339
|
-
}
|
|
3340
|
-
placeholder;
|
|
3341
|
-
constructor(message, placeholder) {
|
|
3342
|
-
super(message), this.placeholder = placeholder;
|
|
3343
|
-
this.name = "WorkflowTemplateError";
|
|
3344
|
-
}
|
|
3345
|
-
};
|
|
3346
|
-
function parseMapConfig(raw, stepId) {
|
|
3347
|
-
try {
|
|
3348
|
-
return JSON.parse(raw);
|
|
3349
|
-
} catch (e) {
|
|
3350
|
-
throw new Error(`Stored mapping step "${stepId}" has invalid JSON mapConfig: ${e.message}`);
|
|
3884
|
+
root = ctx.state;
|
|
3885
|
+
break;
|
|
3886
|
+
case "stepResults": {
|
|
3887
|
+
if (!rest) return MISSING;
|
|
3888
|
+
const innerDot = rest.indexOf(".");
|
|
3889
|
+
const stepId = innerDot === -1 ? rest : rest.slice(0, innerDot);
|
|
3890
|
+
const subPath = innerDot === -1 ? "" : rest.slice(innerDot + 1);
|
|
3891
|
+
let stepResult;
|
|
3892
|
+
if (ctx.stepResults && stepId in ctx.stepResults) stepResult = ctx.stepResults[stepId];
|
|
3893
|
+
else if (ctx.getStepResult) {
|
|
3894
|
+
try {
|
|
3895
|
+
stepResult = ctx.getStepResult(stepId);
|
|
3896
|
+
} catch {
|
|
3897
|
+
return MISSING;
|
|
3898
|
+
}
|
|
3899
|
+
} else return MISSING;
|
|
3900
|
+
if (stepResult === void 0 || stepResult === null) return MISSING;
|
|
3901
|
+
return walk(stepResult, subPath);
|
|
3902
|
+
}
|
|
3903
|
+
default:
|
|
3904
|
+
return MISSING;
|
|
3351
3905
|
}
|
|
3906
|
+
return walk(root, rest);
|
|
3352
3907
|
}
|
|
3353
|
-
__name(
|
|
3354
|
-
__name3(
|
|
3355
|
-
|
|
3356
|
-
|
|
3357
|
-
"initData",
|
|
3358
|
-
"state",
|
|
3359
|
-
"requestContext",
|
|
3360
|
-
"stepResults"
|
|
3361
|
-
];
|
|
3362
|
-
function describeBadPlaceholder(template22, idx, rawExpr) {
|
|
3363
|
-
return `Template placeholder #${idx} (\${${rawExpr}}) in '${template22}'`;
|
|
3364
|
-
}
|
|
3365
|
-
__name(describeBadPlaceholder, "describeBadPlaceholder");
|
|
3366
|
-
__name3(describeBadPlaceholder, "describeBadPlaceholder");
|
|
3367
|
-
function parseTemplatePlaceholder(rawExpr) {
|
|
3368
|
-
const dot = rawExpr.indexOf(".");
|
|
3369
|
-
return {
|
|
3370
|
-
scope: dot === -1 ? rawExpr : rawExpr.slice(0, dot),
|
|
3371
|
-
rest: dot === -1 ? "" : rawExpr.slice(dot + 1)
|
|
3372
|
-
};
|
|
3373
|
-
}
|
|
3374
|
-
__name(parseTemplatePlaceholder, "parseTemplatePlaceholder");
|
|
3375
|
-
__name3(parseTemplatePlaceholder, "parseTemplatePlaceholder");
|
|
3376
|
-
function traverseMappingPath(root, path, errorLabel) {
|
|
3377
|
-
if (path === "" || path === ".") return root;
|
|
3908
|
+
__name(resolvePath, "resolvePath");
|
|
3909
|
+
__name3(resolvePath, "resolvePath");
|
|
3910
|
+
function walk(root, path) {
|
|
3911
|
+
if (path === "") return root;
|
|
3378
3912
|
const parts = path.split(".");
|
|
3379
3913
|
let value22 = root;
|
|
3380
3914
|
for (const part of parts) {
|
|
3381
|
-
if (
|
|
3382
|
-
|
|
3915
|
+
if (value22 === null || value22 === void 0) return MISSING;
|
|
3916
|
+
if (typeof value22 !== "object") return MISSING;
|
|
3917
|
+
const record = value22;
|
|
3918
|
+
if (!(part in record)) return MISSING;
|
|
3919
|
+
value22 = record[part];
|
|
3383
3920
|
}
|
|
3384
3921
|
return value22;
|
|
3385
3922
|
}
|
|
3386
|
-
__name(
|
|
3387
|
-
__name3(
|
|
3388
|
-
function
|
|
3389
|
-
if (
|
|
3390
|
-
|
|
3391
|
-
try {
|
|
3392
|
-
return JSON.stringify(v);
|
|
3393
|
-
} catch (err) {
|
|
3394
|
-
throw new WorkflowTemplateError(`${describeBadPlaceholder(template22, idx, rawExpr)} resolved to a value that could not be JSON-stringified (${err.message}).`, rawExpr);
|
|
3395
|
-
}
|
|
3396
|
-
}
|
|
3397
|
-
return String(v);
|
|
3398
|
-
}
|
|
3399
|
-
__name(stringifyTemplateValue, "stringifyTemplateValue");
|
|
3400
|
-
__name3(stringifyTemplateValue, "stringifyTemplateValue");
|
|
3401
|
-
function escapeFence(content) {
|
|
3402
|
-
return content.replace(/<\/lua-data/g, "<\\/lua-data");
|
|
3403
|
-
}
|
|
3404
|
-
__name(escapeFence, "escapeFence");
|
|
3405
|
-
__name3(escapeFence, "escapeFence");
|
|
3406
|
-
function fenceBlock(name, source, content) {
|
|
3407
|
-
return `<lua-data name="${name}" source="${source}" untrusted="true">${escapeFence(content)}</lua-data>`;
|
|
3408
|
-
}
|
|
3409
|
-
__name(fenceBlock, "fenceBlock");
|
|
3410
|
-
__name3(fenceBlock, "fenceBlock");
|
|
3411
|
-
function renderTemplate(template22, ctx, opts) {
|
|
3412
|
-
let idx = 0;
|
|
3413
|
-
return template22.replace(TEMPLATE_PLACEHOLDER, (_match, rawExpr) => {
|
|
3414
|
-
idx += 1;
|
|
3415
|
-
const { scope, rest } = parseTemplatePlaceholder(rawExpr);
|
|
3416
|
-
const label = describeBadPlaceholder(template22, idx, rawExpr);
|
|
3417
|
-
let rendered;
|
|
3418
|
-
let source;
|
|
3419
|
-
switch (scope) {
|
|
3420
|
-
case "initData":
|
|
3421
|
-
rendered = stringifyTemplateValue(traverseMappingPath(ctx.initData, rest, label), template22, idx, rawExpr);
|
|
3422
|
-
source = "initData";
|
|
3423
|
-
break;
|
|
3424
|
-
case "state":
|
|
3425
|
-
rendered = stringifyTemplateValue(traverseMappingPath(ctx.state, rest, label), template22, idx, rawExpr);
|
|
3426
|
-
source = "state";
|
|
3427
|
-
break;
|
|
3428
|
-
case "requestContext":
|
|
3429
|
-
rendered = stringifyTemplateValue(traverseMappingPath(ctx.requestContext, rest, label), template22, idx, rawExpr);
|
|
3430
|
-
source = "requestContext";
|
|
3431
|
-
break;
|
|
3432
|
-
case "stepResults": {
|
|
3433
|
-
const innerDot = rest.indexOf(".");
|
|
3434
|
-
const stepId = innerDot === -1 ? rest : rest.slice(0, innerDot);
|
|
3435
|
-
const subPath = innerDot === -1 ? "" : rest.slice(innerDot + 1);
|
|
3436
|
-
if (!stepId) throw new WorkflowTemplateError(`${label} must name a step: \${stepResults.<stepId>.<path>}.`, rawExpr);
|
|
3437
|
-
if (!(stepId in ctx.stepResults) || ctx.stepResults[stepId] == null) {
|
|
3438
|
-
throw new WorkflowTemplateError(`${label} references stepResults.${stepId} but step "${stepId}" has no resolvable output (not an ancestor, not run, failed, or produced no output).`, rawExpr);
|
|
3439
|
-
}
|
|
3440
|
-
rendered = stringifyTemplateValue(traverseMappingPath(ctx.stepResults[stepId], subPath, label), template22, idx, rawExpr);
|
|
3441
|
-
source = `step:${stepId}`;
|
|
3442
|
-
break;
|
|
3443
|
-
}
|
|
3444
|
-
default:
|
|
3445
|
-
throw new WorkflowTemplateError(`${label} references unknown namespace "${scope}". Use one of: ${TEMPLATE_NAMESPACES.join(", ")}.`, rawExpr);
|
|
3446
|
-
}
|
|
3447
|
-
return opts.fenced ? fenceBlock(rawExpr, source, rendered) : rendered;
|
|
3448
|
-
});
|
|
3923
|
+
__name(walk, "walk");
|
|
3924
|
+
__name3(walk, "walk");
|
|
3925
|
+
function resolveValue(ref, ctx) {
|
|
3926
|
+
if ("literal" in ref) return ref.literal;
|
|
3927
|
+
return resolvePath(ref.path, ctx);
|
|
3449
3928
|
}
|
|
3450
|
-
__name(
|
|
3451
|
-
__name3(
|
|
3452
|
-
function
|
|
3453
|
-
|
|
3454
|
-
|
|
3455
|
-
|
|
3456
|
-
|
|
3457
|
-
|
|
3458
|
-
|
|
3459
|
-
|
|
3460
|
-
|
|
3461
|
-
|
|
3462
|
-
|
|
3929
|
+
__name(resolveValue, "resolveValue");
|
|
3930
|
+
__name3(resolveValue, "resolveValue");
|
|
3931
|
+
function evaluatePredicate(pred, ctx) {
|
|
3932
|
+
switch (pred.op) {
|
|
3933
|
+
case "and":
|
|
3934
|
+
return pred.args.every((arg) => evaluatePredicate(arg, ctx));
|
|
3935
|
+
case "or":
|
|
3936
|
+
return pred.args.some((arg) => evaluatePredicate(arg, ctx));
|
|
3937
|
+
case "not":
|
|
3938
|
+
return !evaluatePredicate(pred.arg, ctx);
|
|
3939
|
+
case "exists":
|
|
3940
|
+
return resolvePath(pred.path, ctx) !== MISSING;
|
|
3941
|
+
case "notExists":
|
|
3942
|
+
return resolvePath(pred.path, ctx) === MISSING;
|
|
3943
|
+
case "truthy":
|
|
3944
|
+
case "falsy": {
|
|
3945
|
+
const v = resolveValue(pred.value, ctx);
|
|
3946
|
+
const truthy22 = v !== MISSING && Boolean(v);
|
|
3947
|
+
return pred.op === "truthy" ? truthy22 : !truthy22;
|
|
3463
3948
|
}
|
|
3464
|
-
|
|
3465
|
-
|
|
3466
|
-
|
|
3467
|
-
|
|
3468
|
-
|
|
3949
|
+
case "in":
|
|
3950
|
+
case "notIn": {
|
|
3951
|
+
const v = resolveValue(pred.value, ctx);
|
|
3952
|
+
if (v === MISSING) return pred.op === "notIn";
|
|
3953
|
+
const member = pred.set.some((candidate) => candidate === v);
|
|
3954
|
+
return pred.op === "in" ? member : !member;
|
|
3469
3955
|
}
|
|
3470
|
-
|
|
3471
|
-
|
|
3472
|
-
|
|
3473
|
-
|
|
3474
|
-
|
|
3956
|
+
case "eq":
|
|
3957
|
+
case "ne":
|
|
3958
|
+
case "lt":
|
|
3959
|
+
case "lte":
|
|
3960
|
+
case "gt":
|
|
3961
|
+
case "gte": {
|
|
3962
|
+
const left = resolveValue(pred.left, ctx);
|
|
3963
|
+
const right = resolveValue(pred.right, ctx);
|
|
3964
|
+
if (left === MISSING || right === MISSING) return false;
|
|
3965
|
+
return compare(pred.op, left, right);
|
|
3475
3966
|
}
|
|
3476
|
-
|
|
3477
|
-
|
|
3478
|
-
|
|
3479
|
-
|
|
3480
|
-
|
|
3481
|
-
|
|
3482
|
-
|
|
3483
|
-
|
|
3484
|
-
|
|
3485
|
-
|
|
3486
|
-
|
|
3487
|
-
|
|
3488
|
-
|
|
3489
|
-
|
|
3490
|
-
|
|
3491
|
-
|
|
3492
|
-
|
|
3493
|
-
value: traverseMappingPath(ctx.stepResults[stepId], m.path, `step ${candidates.join("|")} for key "${key}"`)
|
|
3494
|
-
};
|
|
3967
|
+
}
|
|
3968
|
+
}
|
|
3969
|
+
__name(evaluatePredicate, "evaluatePredicate");
|
|
3970
|
+
__name3(evaluatePredicate, "evaluatePredicate");
|
|
3971
|
+
function compare(op, left, right) {
|
|
3972
|
+
if (op === "eq") return left === right;
|
|
3973
|
+
if (op === "ne") return left !== right;
|
|
3974
|
+
if (typeof left === "number" && typeof right === "number" || typeof left === "string" && typeof right === "string") {
|
|
3975
|
+
switch (op) {
|
|
3976
|
+
case "lt":
|
|
3977
|
+
return left < right;
|
|
3978
|
+
case "lte":
|
|
3979
|
+
return left <= right;
|
|
3980
|
+
case "gt":
|
|
3981
|
+
return left > right;
|
|
3982
|
+
case "gte":
|
|
3983
|
+
return left >= right;
|
|
3495
3984
|
}
|
|
3496
|
-
|
|
3497
|
-
|
|
3498
|
-
|
|
3499
|
-
|
|
3500
|
-
|
|
3501
|
-
|
|
3502
|
-
|
|
3503
|
-
|
|
3504
|
-
|
|
3505
|
-
|
|
3985
|
+
}
|
|
3986
|
+
return false;
|
|
3987
|
+
}
|
|
3988
|
+
__name(compare, "compare");
|
|
3989
|
+
__name3(compare, "compare");
|
|
3990
|
+
function derivePredicateLabel(pred, maxLength = 80) {
|
|
3991
|
+
const raw = renderPredicate(pred);
|
|
3992
|
+
if (raw.length <= maxLength) return raw;
|
|
3993
|
+
return raw.slice(0, maxLength - 1) + "\u2026";
|
|
3994
|
+
}
|
|
3995
|
+
__name(derivePredicateLabel, "derivePredicateLabel");
|
|
3996
|
+
__name3(derivePredicateLabel, "derivePredicateLabel");
|
|
3997
|
+
function renderPredicate(pred) {
|
|
3998
|
+
switch (pred.op) {
|
|
3999
|
+
case "and":
|
|
4000
|
+
case "or":
|
|
4001
|
+
return pred.args.map((arg) => wrapLabel(arg, renderPredicate(arg))).join(pred.op === "and" ? " AND " : " OR ");
|
|
4002
|
+
case "not":
|
|
4003
|
+
return `NOT ${wrapLabel(pred.arg, renderPredicate(pred.arg))}`;
|
|
4004
|
+
case "exists":
|
|
4005
|
+
return `${pred.path} exists`;
|
|
4006
|
+
case "notExists":
|
|
4007
|
+
return `${pred.path} missing`;
|
|
4008
|
+
case "truthy":
|
|
4009
|
+
return `${renderRef(pred.value)} is truthy`;
|
|
4010
|
+
case "falsy":
|
|
4011
|
+
return `${renderRef(pred.value)} is falsy`;
|
|
4012
|
+
case "in":
|
|
4013
|
+
return `${renderRef(pred.value)} in ${JSON.stringify(pred.set)}`;
|
|
4014
|
+
case "notIn":
|
|
4015
|
+
return `${renderRef(pred.value)} not in ${JSON.stringify(pred.set)}`;
|
|
4016
|
+
case "eq":
|
|
4017
|
+
return `${renderRef(pred.left)} == ${renderRef(pred.right)}`;
|
|
4018
|
+
case "ne":
|
|
4019
|
+
return `${renderRef(pred.left)} != ${renderRef(pred.right)}`;
|
|
4020
|
+
case "lt":
|
|
4021
|
+
return `${renderRef(pred.left)} < ${renderRef(pred.right)}`;
|
|
4022
|
+
case "lte":
|
|
4023
|
+
return `${renderRef(pred.left)} <= ${renderRef(pred.right)}`;
|
|
4024
|
+
case "gt":
|
|
4025
|
+
return `${renderRef(pred.left)} > ${renderRef(pred.right)}`;
|
|
4026
|
+
case "gte":
|
|
4027
|
+
return `${renderRef(pred.left)} >= ${renderRef(pred.right)}`;
|
|
3506
4028
|
}
|
|
3507
4029
|
}
|
|
3508
|
-
__name(
|
|
3509
|
-
__name3(
|
|
3510
|
-
function
|
|
3511
|
-
|
|
3512
|
-
|
|
3513
|
-
|
|
3514
|
-
|
|
3515
|
-
|
|
3516
|
-
|
|
3517
|
-
|
|
3518
|
-
|
|
3519
|
-
|
|
3520
|
-
|
|
4030
|
+
__name(renderPredicate, "renderPredicate");
|
|
4031
|
+
__name3(renderPredicate, "renderPredicate");
|
|
4032
|
+
function wrapLabel(child, rendered) {
|
|
4033
|
+
return child.op === "and" || child.op === "or" || child.op === "not" ? `(${rendered})` : rendered;
|
|
4034
|
+
}
|
|
4035
|
+
__name(wrapLabel, "wrapLabel");
|
|
4036
|
+
__name3(wrapLabel, "wrapLabel");
|
|
4037
|
+
function renderRef(ref) {
|
|
4038
|
+
if ("literal" in ref) return JSON.stringify(ref.literal);
|
|
4039
|
+
return ref.path;
|
|
4040
|
+
}
|
|
4041
|
+
__name(renderRef, "renderRef");
|
|
4042
|
+
__name3(renderRef, "renderRef");
|
|
4043
|
+
var stepIdOf = /* @__PURE__ */ __name3((s) => typeof s === "string" ? s : s.id, "stepIdOf");
|
|
4044
|
+
function step(s) {
|
|
4045
|
+
const id = stepIdOf(s);
|
|
3521
4046
|
return {
|
|
3522
|
-
|
|
4047
|
+
path: /* @__PURE__ */ __name3((p) => ({
|
|
4048
|
+
path: p === "" ? `stepResults.${id}` : `stepResults.${id}.${p}`
|
|
4049
|
+
}), "path")
|
|
3523
4050
|
};
|
|
3524
4051
|
}
|
|
3525
|
-
__name(
|
|
3526
|
-
__name3(
|
|
3527
|
-
|
|
3528
|
-
|
|
3529
|
-
|
|
3530
|
-
|
|
3531
|
-
|
|
3532
|
-
|
|
4052
|
+
__name(step, "step");
|
|
4053
|
+
__name3(step, "step");
|
|
4054
|
+
function stepOf(id) {
|
|
4055
|
+
return step(id);
|
|
4056
|
+
}
|
|
4057
|
+
__name(stepOf, "stepOf");
|
|
4058
|
+
__name3(stepOf, "stepOf");
|
|
4059
|
+
function init(path) {
|
|
3533
4060
|
return {
|
|
3534
|
-
|
|
3535
|
-
path
|
|
4061
|
+
path: path === "" ? "initData" : `initData.${path}`
|
|
3536
4062
|
};
|
|
3537
|
-
}
|
|
3538
|
-
|
|
3539
|
-
|
|
3540
|
-
|
|
3541
|
-
|
|
3542
|
-
|
|
3543
|
-
}
|
|
3544
|
-
|
|
3545
|
-
|
|
3546
|
-
|
|
3547
|
-
|
|
3548
|
-
|
|
3549
|
-
|
|
3550
|
-
|
|
3551
|
-
}
|
|
3552
|
-
|
|
3553
|
-
|
|
3554
|
-
|
|
4063
|
+
}
|
|
4064
|
+
__name(init, "init");
|
|
4065
|
+
__name3(init, "init");
|
|
4066
|
+
function state(path) {
|
|
4067
|
+
return {
|
|
4068
|
+
path: path === "" ? "state" : `state.${path}`
|
|
4069
|
+
};
|
|
4070
|
+
}
|
|
4071
|
+
__name(state, "state");
|
|
4072
|
+
__name3(state, "state");
|
|
4073
|
+
function lit(v) {
|
|
4074
|
+
return {
|
|
4075
|
+
literal: v
|
|
4076
|
+
};
|
|
4077
|
+
}
|
|
4078
|
+
__name(lit, "lit");
|
|
4079
|
+
__name3(lit, "lit");
|
|
4080
|
+
function toPathOrLiteral(v) {
|
|
4081
|
+
if (typeof v === "object" && v !== null) {
|
|
4082
|
+
if ("path" in v) return {
|
|
4083
|
+
path: v.path
|
|
4084
|
+
};
|
|
4085
|
+
if ("literal" in v) return {
|
|
4086
|
+
literal: v.literal
|
|
4087
|
+
};
|
|
4088
|
+
}
|
|
4089
|
+
return {
|
|
4090
|
+
literal: v
|
|
4091
|
+
};
|
|
4092
|
+
}
|
|
4093
|
+
__name(toPathOrLiteral, "toPathOrLiteral");
|
|
4094
|
+
__name3(toPathOrLiteral, "toPathOrLiteral");
|
|
4095
|
+
var cmp = /* @__PURE__ */ __name3((op) => (l, r) => ({
|
|
4096
|
+
op,
|
|
4097
|
+
left: toPathOrLiteral(l),
|
|
4098
|
+
right: toPathOrLiteral(r)
|
|
4099
|
+
}), "cmp");
|
|
4100
|
+
var eq = cmp("eq");
|
|
4101
|
+
var ne = cmp("ne");
|
|
4102
|
+
var gt = cmp("gt");
|
|
4103
|
+
var gte = cmp("gte");
|
|
4104
|
+
var lt = cmp("lt");
|
|
4105
|
+
var lte = cmp("lte");
|
|
4106
|
+
var inSet = /* @__PURE__ */ __name3((v, set) => ({
|
|
4107
|
+
op: "in",
|
|
4108
|
+
value: {
|
|
4109
|
+
path: v.path
|
|
4110
|
+
},
|
|
4111
|
+
set
|
|
4112
|
+
}), "inSet");
|
|
4113
|
+
var notIn = /* @__PURE__ */ __name3((v, set) => ({
|
|
4114
|
+
op: "notIn",
|
|
4115
|
+
value: {
|
|
4116
|
+
path: v.path
|
|
4117
|
+
},
|
|
4118
|
+
set
|
|
4119
|
+
}), "notIn");
|
|
4120
|
+
var exists = /* @__PURE__ */ __name3((ref) => ({
|
|
4121
|
+
op: "exists",
|
|
4122
|
+
path: ref.path
|
|
4123
|
+
}), "exists");
|
|
4124
|
+
var notExists = /* @__PURE__ */ __name3((ref) => ({
|
|
4125
|
+
op: "notExists",
|
|
4126
|
+
path: ref.path
|
|
4127
|
+
}), "notExists");
|
|
4128
|
+
var truthy = /* @__PURE__ */ __name3((ref) => ({
|
|
4129
|
+
op: "truthy",
|
|
4130
|
+
value: {
|
|
4131
|
+
path: ref.path
|
|
4132
|
+
}
|
|
4133
|
+
}), "truthy");
|
|
4134
|
+
var falsy = /* @__PURE__ */ __name3((ref) => ({
|
|
4135
|
+
op: "falsy",
|
|
4136
|
+
value: {
|
|
4137
|
+
path: ref.path
|
|
4138
|
+
}
|
|
4139
|
+
}), "falsy");
|
|
4140
|
+
var and = /* @__PURE__ */ __name3((...args) => ({
|
|
4141
|
+
op: "and",
|
|
4142
|
+
args
|
|
4143
|
+
}), "and");
|
|
4144
|
+
var or = /* @__PURE__ */ __name3((...args) => ({
|
|
4145
|
+
op: "or",
|
|
4146
|
+
args
|
|
4147
|
+
}), "or");
|
|
4148
|
+
var not = /* @__PURE__ */ __name3((arg) => ({
|
|
4149
|
+
op: "not",
|
|
4150
|
+
arg
|
|
4151
|
+
}), "not");
|
|
3555
4152
|
var CONTINUED_FAILURE_TAG = "continued_failure";
|
|
3556
4153
|
var CONTINUED_FAILURE_DEFAULT_CODE = "step_failed";
|
|
3557
4154
|
var CONTINUED_FAILURE_OUTPUT_SCHEMA = Object.freeze({
|
|
@@ -3622,6 +4219,7 @@ function isContinuedFailureValue(v) {
|
|
|
3622
4219
|
}
|
|
3623
4220
|
__name(isContinuedFailureValue, "isContinuedFailureValue");
|
|
3624
4221
|
__name3(isContinuedFailureValue, "isContinuedFailureValue");
|
|
4222
|
+
var isHitlNode2 = /* @__PURE__ */ __name3((n2) => isWorkflowHitlEntryType(n2.type), "isHitlNode");
|
|
3625
4223
|
function lowerContainerArm(mapping, step22) {
|
|
3626
4224
|
const stepId = nodeIdOf(step22);
|
|
3627
4225
|
return {
|
|
@@ -3707,7 +4305,28 @@ function resolvePlacements(calls) {
|
|
|
3707
4305
|
break;
|
|
3708
4306
|
}
|
|
3709
4307
|
});
|
|
3710
|
-
const
|
|
4308
|
+
const hitlPlacementIssue = /* @__PURE__ */ __name3((node, ref, i, container) => {
|
|
4309
|
+
if (!isHitlNode2(node)) return void 0;
|
|
4310
|
+
const id = node.id;
|
|
4311
|
+
if (ref.armMap) {
|
|
4312
|
+
return {
|
|
4313
|
+
code: "node-type-unsupported-in-container",
|
|
4314
|
+
message: workflowHitlArmShapeMessage(node.type, id, "mapped-arm"),
|
|
4315
|
+
callIndex: i,
|
|
4316
|
+
stepId: id
|
|
4317
|
+
};
|
|
4318
|
+
}
|
|
4319
|
+
if (container !== "place" && !workflowContainerRunsHitlArm(container)) {
|
|
4320
|
+
return {
|
|
4321
|
+
code: "node-type-unsupported-in-container",
|
|
4322
|
+
message: workflowHitlArmUnsupportedMessage(node.type, id, container),
|
|
4323
|
+
callIndex: i,
|
|
4324
|
+
stepId: id
|
|
4325
|
+
};
|
|
4326
|
+
}
|
|
4327
|
+
return void 0;
|
|
4328
|
+
}, "hitlPlacementIssue");
|
|
4329
|
+
const resolve = /* @__PURE__ */ __name3((ref, i, allowMapping, container) => {
|
|
3711
4330
|
if ("node" in ref) {
|
|
3712
4331
|
if (ref.node.type === "mapping" && !allowMapping) {
|
|
3713
4332
|
issues.push({
|
|
@@ -3724,7 +4343,7 @@ function resolvePlacements(calls) {
|
|
|
3724
4343
|
if (!d) {
|
|
3725
4344
|
issues.push({
|
|
3726
4345
|
code: "unknown-step-ref",
|
|
3727
|
-
message: `"${ref.ref}" is not declared anywhere in the chain \u2014 declare it with agentStep/specialistStep/toolStep/map(\u2026, { id })/workflow(\u2026)`,
|
|
4346
|
+
message: `"${ref.ref}" is not declared anywhere in the chain \u2014 declare it with agentStep/specialistStep/toolStep/map(\u2026, { id })/workflow(\u2026)/approval(\u2026)/waitForSignal(\u2026)`,
|
|
3728
4347
|
callIndex: i,
|
|
3729
4348
|
stepId: ref.ref
|
|
3730
4349
|
});
|
|
@@ -3739,6 +4358,11 @@ function resolvePlacements(calls) {
|
|
|
3739
4358
|
});
|
|
3740
4359
|
return void 0;
|
|
3741
4360
|
}
|
|
4361
|
+
const hitl = hitlPlacementIssue(d.node, ref, i, container);
|
|
4362
|
+
if (hitl) {
|
|
4363
|
+
issues.push(hitl);
|
|
4364
|
+
return void 0;
|
|
4365
|
+
}
|
|
3742
4366
|
const prior = placedBy.get(ref.ref);
|
|
3743
4367
|
if (prior !== void 0 && prior !== i) {
|
|
3744
4368
|
issues.push({
|
|
@@ -3752,23 +4376,31 @@ function resolvePlacements(calls) {
|
|
|
3752
4376
|
placedBy.set(ref.ref, i);
|
|
3753
4377
|
return d.node;
|
|
3754
4378
|
}, "resolve");
|
|
4379
|
+
const claim = /* @__PURE__ */ __name3((ref, i, allowMapping, container) => {
|
|
4380
|
+
if ("ref" in ref) {
|
|
4381
|
+
resolve(ref, i, allowMapping, container);
|
|
4382
|
+
return;
|
|
4383
|
+
}
|
|
4384
|
+
const hitl = hitlPlacementIssue(ref.node, ref, i, container);
|
|
4385
|
+
if (hitl) issues.push(hitl);
|
|
4386
|
+
}, "claim");
|
|
3755
4387
|
calls.forEach((call, i) => {
|
|
3756
4388
|
switch (call.kind) {
|
|
3757
4389
|
case "place":
|
|
3758
|
-
|
|
4390
|
+
claim({
|
|
3759
4391
|
ref: call.ref
|
|
3760
|
-
}, i, false);
|
|
4392
|
+
}, i, false, "place");
|
|
3761
4393
|
break;
|
|
3762
4394
|
case "parallel":
|
|
3763
|
-
for (const arm of call.arms)
|
|
4395
|
+
for (const arm of call.arms) claim(arm, i, false, "parallel");
|
|
3764
4396
|
break;
|
|
3765
4397
|
case "conditional":
|
|
3766
|
-
for (const a of call.arms)
|
|
3767
|
-
if (call.otherwise
|
|
4398
|
+
for (const a of call.arms) claim(a.target, i, true, "conditional");
|
|
4399
|
+
if (call.otherwise) claim(call.otherwise, i, true, "conditional");
|
|
3768
4400
|
break;
|
|
3769
4401
|
case "foreach":
|
|
3770
4402
|
case "loop":
|
|
3771
|
-
|
|
4403
|
+
claim(call.body, i, false, call.kind);
|
|
3772
4404
|
break;
|
|
3773
4405
|
default:
|
|
3774
4406
|
break;
|
|
@@ -3777,7 +4409,7 @@ function resolvePlacements(calls) {
|
|
|
3777
4409
|
const graph = [];
|
|
3778
4410
|
const lookup = /* @__PURE__ */ __name3((ref) => {
|
|
3779
4411
|
const n2 = "node" in ref ? ref.node : declared.get(ref.ref)?.node;
|
|
3780
|
-
if (!n2 || !ref.armMap || n2.type === "mapping") return n2;
|
|
4412
|
+
if (!n2 || !ref.armMap || n2.type === "mapping" || isHitlNode2(n2)) return n2;
|
|
3781
4413
|
return lowerContainerArm(ref.armMap, n2);
|
|
3782
4414
|
}, "lookup");
|
|
3783
4415
|
calls.forEach((call, i) => {
|
|
@@ -3859,6 +4491,75 @@ function resolvePlacements(calls) {
|
|
|
3859
4491
|
}
|
|
3860
4492
|
__name(resolvePlacements, "resolvePlacements");
|
|
3861
4493
|
__name3(resolvePlacements, "resolvePlacements");
|
|
4494
|
+
var GOAL_JUDGE_STEP_ID = "__goal_judge";
|
|
4495
|
+
var NON_LEAF_KINDS = /* @__PURE__ */ new Set([
|
|
4496
|
+
"foreach",
|
|
4497
|
+
"branch"
|
|
4498
|
+
]);
|
|
4499
|
+
var CONDITIONAL_JOIN_ID = /^conditional@\d+\.join$/;
|
|
4500
|
+
function isConditionalJoinId(stepId) {
|
|
4501
|
+
return CONDITIONAL_JOIN_ID.test(stepId);
|
|
4502
|
+
}
|
|
4503
|
+
__name(isConditionalJoinId, "isConditionalJoinId");
|
|
4504
|
+
__name3(isConditionalJoinId, "isConditionalJoinId");
|
|
4505
|
+
function isPlainObject(v) {
|
|
4506
|
+
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
4507
|
+
}
|
|
4508
|
+
__name(isPlainObject, "isPlainObject");
|
|
4509
|
+
__name3(isPlainObject, "isPlainObject");
|
|
4510
|
+
function leafValue(row) {
|
|
4511
|
+
if (row.status === "completed") return row.output === void 0 ? null : row.output;
|
|
4512
|
+
return continuedFailureValue(row.error, row.killReason);
|
|
4513
|
+
}
|
|
4514
|
+
__name(leafValue, "leafValue");
|
|
4515
|
+
__name3(leafValue, "leafValue");
|
|
4516
|
+
function runOutputLeaves(steps) {
|
|
4517
|
+
const dependedOn = /* @__PURE__ */ new Set();
|
|
4518
|
+
for (const s of steps) {
|
|
4519
|
+
if (s.stepId === GOAL_JUDGE_STEP_ID) continue;
|
|
4520
|
+
for (const d of s.dependsOn ?? []) dependedOn.add(d);
|
|
4521
|
+
}
|
|
4522
|
+
return steps.filter((s) => s.stepId !== GOAL_JUDGE_STEP_ID && !NON_LEAF_KINDS.has(s.kind ?? "") && s.foreachIndex === void 0 && s.loopParentId === void 0 && s.status !== "skipped" && !dependedOn.has(s.stepId));
|
|
4523
|
+
}
|
|
4524
|
+
__name(runOutputLeaves, "runOutputLeaves");
|
|
4525
|
+
__name3(runOutputLeaves, "runOutputLeaves");
|
|
4526
|
+
function deriveRunOutput(steps) {
|
|
4527
|
+
const leaves = runOutputLeaves(steps);
|
|
4528
|
+
if (leaves.length === 0) return void 0;
|
|
4529
|
+
if (leaves.length === 1) {
|
|
4530
|
+
const leaf = leaves[0];
|
|
4531
|
+
const value22 = leafValue(leaf);
|
|
4532
|
+
if (isConditionalJoinId(leaf.stepId) && isPlainObject(value22)) {
|
|
4533
|
+
const keys = Object.keys(value22);
|
|
4534
|
+
if (keys.length === 1) return {
|
|
4535
|
+
output: value22[keys[0]],
|
|
4536
|
+
leafIds: [
|
|
4537
|
+
keys[0]
|
|
4538
|
+
]
|
|
4539
|
+
};
|
|
4540
|
+
}
|
|
4541
|
+
return {
|
|
4542
|
+
output: value22,
|
|
4543
|
+
leafIds: [
|
|
4544
|
+
leaf.stepId
|
|
4545
|
+
]
|
|
4546
|
+
};
|
|
4547
|
+
}
|
|
4548
|
+
const output = {};
|
|
4549
|
+
for (const leaf of leaves) output[leaf.stepId] = leafValue(leaf);
|
|
4550
|
+
return {
|
|
4551
|
+
output,
|
|
4552
|
+
leafIds: leaves.map((l) => l.stepId)
|
|
4553
|
+
};
|
|
4554
|
+
}
|
|
4555
|
+
__name(deriveRunOutput, "deriveRunOutput");
|
|
4556
|
+
__name3(deriveRunOutput, "deriveRunOutput");
|
|
4557
|
+
function subrunSettledOutput(child) {
|
|
4558
|
+
if (child.output !== void 0) return child.output;
|
|
4559
|
+
return deriveRunOutput(child.steps ?? [])?.output ?? null;
|
|
4560
|
+
}
|
|
4561
|
+
__name(subrunSettledOutput, "subrunSettledOutput");
|
|
4562
|
+
__name3(subrunSettledOutput, "subrunSettledOutput");
|
|
3862
4563
|
function seedLedgerFromRun(run, steps, targetPlan, opts = {}) {
|
|
3863
4564
|
const byId = /* @__PURE__ */ new Map();
|
|
3864
4565
|
for (const s of steps) {
|
|
@@ -4027,6 +4728,15 @@ function replayLedger(g, ledger) {
|
|
|
4027
4728
|
local,
|
|
4028
4729
|
diverged: recordedCount !== local
|
|
4029
4730
|
});
|
|
4731
|
+
} else if (node.kind === "subrun" && recorded.status === "completed" && recorded.child) {
|
|
4732
|
+
const local = subrunSettledOutput(recorded.child);
|
|
4733
|
+
verdicts.push({
|
|
4734
|
+
stepId: id,
|
|
4735
|
+
kind: "subrun",
|
|
4736
|
+
recorded: recorded.output,
|
|
4737
|
+
local,
|
|
4738
|
+
diverged: canonical(recorded.output) !== canonical(local)
|
|
4739
|
+
});
|
|
4030
4740
|
}
|
|
4031
4741
|
}
|
|
4032
4742
|
return {
|
|
@@ -4198,10 +4908,57 @@ function runCounts(counts) {
|
|
|
4198
4908
|
}
|
|
4199
4909
|
__name(runCounts, "runCounts");
|
|
4200
4910
|
__name3(runCounts, "runCounts");
|
|
4201
|
-
function
|
|
4911
|
+
function isPricedStepReceipt(receipt) {
|
|
4912
|
+
return typeof receipt?.multiplier === "number" && Number.isFinite(receipt.multiplier);
|
|
4913
|
+
}
|
|
4914
|
+
__name(isPricedStepReceipt, "isPricedStepReceipt");
|
|
4915
|
+
__name3(isPricedStepReceipt, "isPricedStepReceipt");
|
|
4916
|
+
function receiptEngine(engine) {
|
|
4917
|
+
if (engine === "actions") return "seat";
|
|
4918
|
+
if (engine === "credits") return "legacy";
|
|
4919
|
+
return void 0;
|
|
4920
|
+
}
|
|
4921
|
+
__name(receiptEngine, "receiptEngine");
|
|
4922
|
+
__name3(receiptEngine, "receiptEngine");
|
|
4923
|
+
function receiptTier(tier) {
|
|
4924
|
+
return tier === "light" || tier === "standard" || tier === "heavy" ? tier : void 0;
|
|
4925
|
+
}
|
|
4926
|
+
__name(receiptTier, "receiptTier");
|
|
4927
|
+
__name3(receiptTier, "receiptTier");
|
|
4928
|
+
function stepBillingView(receipt) {
|
|
4929
|
+
const engine = receiptEngine(receipt?.engine);
|
|
4930
|
+
if (!receipt || engine === void 0) return void 0;
|
|
4931
|
+
return pruneUndefined({
|
|
4932
|
+
engine,
|
|
4933
|
+
attempt: typeof receipt.attempt === "number" ? receipt.attempt : void 0,
|
|
4934
|
+
credits: typeof receipt.credits === "number" ? receipt.credits : void 0,
|
|
4935
|
+
actions: typeof receipt.actionsEstimate === "number" ? receipt.actionsEstimate : void 0,
|
|
4936
|
+
model: typeof receipt.model === "string" ? receipt.model : void 0,
|
|
4937
|
+
tier: receiptTier(receipt.tier),
|
|
4938
|
+
multiplier: typeof receipt.multiplier === "number" ? receipt.multiplier : void 0,
|
|
4939
|
+
byok: typeof receipt.byok === "boolean" ? receipt.byok : void 0,
|
|
4940
|
+
calibrated: typeof receipt.calibrated === "boolean" ? receipt.calibrated : void 0
|
|
4941
|
+
});
|
|
4942
|
+
}
|
|
4943
|
+
__name(stepBillingView, "stepBillingView");
|
|
4944
|
+
__name3(stepBillingView, "stepBillingView");
|
|
4945
|
+
function runUsage(run, receipts) {
|
|
4946
|
+
const actions = n(run.budget?.spent?.actionsEstimate);
|
|
4947
|
+
const stamped = run.budget?.engine;
|
|
4948
|
+
const priced = (receipts ?? []).filter(isPricedStepReceipt);
|
|
4949
|
+
const engine = stamped === "seat" || stamped === "legacy" ? stamped : actions > 0 || priced.some((r) => r.engine === "actions") ? "seat" : priced.some((r) => r.engine === "credits") ? "legacy" : void 0;
|
|
4950
|
+
const seat = engine === "seat";
|
|
4951
|
+
const metering = engine ? "priced" : "flat";
|
|
4202
4952
|
return {
|
|
4203
4953
|
creditsUsed: run.budget?.spent?.credits ?? 0,
|
|
4204
4954
|
actionsEstimate: run.budget?.spent?.actionsEstimate ?? 0,
|
|
4955
|
+
...seat ? {
|
|
4956
|
+
actionsUsed: actions
|
|
4957
|
+
} : {},
|
|
4958
|
+
metering,
|
|
4959
|
+
...engine ? {
|
|
4960
|
+
engine
|
|
4961
|
+
} : {},
|
|
4205
4962
|
steps: run.budget?.spent?.steps ?? 0,
|
|
4206
4963
|
inputTokens: run.usage?.inputTokens ?? 0,
|
|
4207
4964
|
outputTokens: run.usage?.outputTokens ?? 0
|
|
@@ -4209,12 +4966,42 @@ function runUsage(run) {
|
|
|
4209
4966
|
}
|
|
4210
4967
|
__name(runUsage, "runUsage");
|
|
4211
4968
|
__name3(runUsage, "runUsage");
|
|
4969
|
+
function runBudgetCap(budget) {
|
|
4970
|
+
const cap = budget?.maxCredits;
|
|
4971
|
+
return typeof cap === "number" && Number.isFinite(cap) && cap > 0 ? cap : void 0;
|
|
4972
|
+
}
|
|
4973
|
+
__name(runBudgetCap, "runBudgetCap");
|
|
4974
|
+
__name3(runBudgetCap, "runBudgetCap");
|
|
4975
|
+
function runBudgetRemaining(budget) {
|
|
4976
|
+
const cap = runBudgetCap(budget);
|
|
4977
|
+
if (cap === void 0) return void 0;
|
|
4978
|
+
const spent = budget?.spent;
|
|
4979
|
+
return Math.max(0, cap - n(spent?.credits) - n(spent?.actionsEstimate) - n(budget?.reserved));
|
|
4980
|
+
}
|
|
4981
|
+
__name(runBudgetRemaining, "runBudgetRemaining");
|
|
4982
|
+
__name3(runBudgetRemaining, "runBudgetRemaining");
|
|
4212
4983
|
function runCancelView(cancel) {
|
|
4213
4984
|
if (!cancel) return void 0;
|
|
4214
4985
|
return {
|
|
4215
4986
|
requestedAt: cancel.requestedAt,
|
|
4216
4987
|
requestedBy: cancel.requestedBy ?? "",
|
|
4217
|
-
forceAvailableAt: cancel.forceAfter ?? cancel.requestedAt + FORCE_CANCEL_STALE_MS
|
|
4988
|
+
forceAvailableAt: cancel.forceAfter ?? cancel.requestedAt + FORCE_CANCEL_STALE_MS,
|
|
4989
|
+
// LUA-686: the wall's own request (LUA-683 stamps `wall:true` from a system actor only) rides the wire, so a
|
|
4990
|
+
// client can tell a wall-ended `timed_out` run's audit block from a cancel it should chip. Absent, never false.
|
|
4991
|
+
...cancel.wall === true ? {
|
|
4992
|
+
wall: true
|
|
4993
|
+
} : {},
|
|
4994
|
+
// LUA-704: a forced terminal's audit — who forced it, when, and a human's own reason text (the run's `reason`
|
|
4995
|
+
// is the terminal's). Absent on an unforced terminal, never null.
|
|
4996
|
+
...typeof cancel.forcedAt === "number" ? {
|
|
4997
|
+
forcedAt: cancel.forcedAt
|
|
4998
|
+
} : {},
|
|
4999
|
+
...typeof cancel.forcedBy === "string" && cancel.forcedBy ? {
|
|
5000
|
+
forcedBy: cancel.forcedBy
|
|
5001
|
+
} : {},
|
|
5002
|
+
...typeof cancel.forceReason === "string" && cancel.forceReason ? {
|
|
5003
|
+
forceReason: cancel.forceReason
|
|
5004
|
+
} : {}
|
|
4218
5005
|
};
|
|
4219
5006
|
}
|
|
4220
5007
|
__name(runCancelView, "runCancelView");
|
|
@@ -4237,7 +5024,6 @@ __name3(runWorkspaceView, "runWorkspaceView");
|
|
|
4237
5024
|
function toWorkflowRunSummary(run) {
|
|
4238
5025
|
const status = run.status;
|
|
4239
5026
|
const principal = run.principal?.principal;
|
|
4240
|
-
const gated = status === "gated" || status === "suspended";
|
|
4241
5027
|
return pruneUndefined({
|
|
4242
5028
|
runId: run.id,
|
|
4243
5029
|
workflowId: run.workflowId,
|
|
@@ -4249,7 +5035,14 @@ function toWorkflowRunSummary(run) {
|
|
|
4249
5035
|
orgId: run.orgId,
|
|
4250
5036
|
spaceAgentId: run.spaceAgentId,
|
|
4251
5037
|
status,
|
|
4252
|
-
|
|
5038
|
+
// LUA-702 (pass-3B D6): the gate rides the wire whenever a NON-terminal doc carries one. In the LUA-681 window
|
|
5039
|
+
// (an approval resolved beside an open exception park) the run is `running` AND still holds `gate{exception}`
|
|
5040
|
+
// until the tick tail parks it back; projecting it only on gated|suspended hid that park from R4 / the CLI /
|
|
5041
|
+
// the desktop (prod 2026-09-05: `status: running, gate: null`). A terminal doc carries no gate by contract
|
|
5042
|
+
// (`terminalizeRun` drops `gate` / `suspendedFor` in every terminal write), but a row terminalized before that
|
|
5043
|
+
// held — pre-LUA-677/694 docs, a script-tier backstop that passed no `unset` — may still carry a stale one:
|
|
5044
|
+
// hidden here, so a `failed` run never reads "Needs a decision" on R3/R4 or the CLI (#2476 review).
|
|
5045
|
+
gate: run.gate && !isTerminalRunStatus(status) ? run.gate : void 0,
|
|
4253
5046
|
batchId: run.batchId,
|
|
4254
5047
|
goalId: run.goalId,
|
|
4255
5048
|
foreachOverflow: run.foreachOverflow,
|
|
@@ -4272,9 +5065,11 @@ function toWorkflowRunSummary(run) {
|
|
|
4272
5065
|
principalKind: run.principalKind ?? "user",
|
|
4273
5066
|
cancel: runCancelView(run.cancel),
|
|
4274
5067
|
usage: runUsage(run),
|
|
5068
|
+
// LUA-697: a row persisted before the write seams (#2406 / #2465 / the script tier) leaves scrubbed here too —
|
|
5069
|
+
// idempotent on a scrubbed message, bounded input; an empty message falls back to the code.
|
|
4275
5070
|
error: run.error ? {
|
|
4276
5071
|
code: run.error.code ?? "error",
|
|
4277
|
-
message: run.error.message ?? "",
|
|
5072
|
+
message: scrubStepErrorMessage(run.error.message) ?? run.error.code ?? "error",
|
|
4278
5073
|
stepId: run.error.stepId
|
|
4279
5074
|
} : void 0,
|
|
4280
5075
|
kind: "run",
|
|
@@ -4295,6 +5090,86 @@ function toWorkflowRunSummary(run) {
|
|
|
4295
5090
|
}
|
|
4296
5091
|
__name(toWorkflowRunSummary, "toWorkflowRunSummary");
|
|
4297
5092
|
__name3(toWorkflowRunSummary, "toWorkflowRunSummary");
|
|
5093
|
+
var STEP_ERROR_DETAIL_KEYS = [
|
|
5094
|
+
"reason",
|
|
5095
|
+
"key",
|
|
5096
|
+
"integrationType",
|
|
5097
|
+
"candidates",
|
|
5098
|
+
"connectionId",
|
|
5099
|
+
"status",
|
|
5100
|
+
"code",
|
|
5101
|
+
"providerStatus",
|
|
5102
|
+
"model",
|
|
5103
|
+
"turnIndex",
|
|
5104
|
+
"message",
|
|
5105
|
+
// LUA-655: `output_schema_invalid` — the Ajv issues ({path, message}, ≤ 20, scrubbed at the source too) and the
|
|
5106
|
+
// in-session repair rounds the attempt spent.
|
|
5107
|
+
"issues",
|
|
5108
|
+
"repairRounds",
|
|
5109
|
+
// LUA-669 (#2446 review 4): the subrun failures — `subrun_<status>` names the child run and how it ended
|
|
5110
|
+
// (`childStatus`, `childReason: 'max_duration'` under `subrun_timed_out`), `subrun_depth_exceeded` its `depth` /
|
|
5111
|
+
// `max`, and every refusal the target `workflowId`. Short scalars only: the child's whole `childError` and the
|
|
5112
|
+
// cycle walk's `ancestors` stay off the wire — the child run's own R4 carries its error.
|
|
5113
|
+
"childRunId",
|
|
5114
|
+
"childStatus",
|
|
5115
|
+
"childReason",
|
|
5116
|
+
"max",
|
|
5117
|
+
"depth",
|
|
5118
|
+
"workflowId",
|
|
5119
|
+
// LUA-696 (review 2): the `ctx.once` key of an `effect_in_doubt` park — the step site stamps it here (scrubbed)
|
|
5120
|
+
// beside `park.effectKey`; a key is user text and leaves scrubbed like every other string leaf.
|
|
5121
|
+
"effectKey"
|
|
5122
|
+
];
|
|
5123
|
+
var STEP_ERROR_DETAIL_MAX_BYTES = 8 * 1024;
|
|
5124
|
+
var DETAIL_MAX_DEPTH = 4;
|
|
5125
|
+
var DETAIL_MAX_ITEMS = 100;
|
|
5126
|
+
function scrubDetailValue(value22, depth) {
|
|
5127
|
+
if (typeof value22 === "string") return scrubSecretText(value22);
|
|
5128
|
+
if (typeof value22 === "number" || typeof value22 === "boolean" || value22 === null) return value22;
|
|
5129
|
+
if (depth >= DETAIL_MAX_DEPTH) return void 0;
|
|
5130
|
+
if (Array.isArray(value22)) {
|
|
5131
|
+
return value22.slice(0, DETAIL_MAX_ITEMS).map((v) => scrubDetailValue(v, depth + 1)).filter((v) => v !== void 0);
|
|
5132
|
+
}
|
|
5133
|
+
if (typeof value22 === "object") {
|
|
5134
|
+
const out = {};
|
|
5135
|
+
for (const [k, v] of Object.entries(value22)) {
|
|
5136
|
+
const s = scrubDetailValue(v, depth + 1);
|
|
5137
|
+
if (s !== void 0) out[k] = s;
|
|
5138
|
+
}
|
|
5139
|
+
return out;
|
|
5140
|
+
}
|
|
5141
|
+
return void 0;
|
|
5142
|
+
}
|
|
5143
|
+
__name(scrubDetailValue, "scrubDetailValue");
|
|
5144
|
+
__name3(scrubDetailValue, "scrubDetailValue");
|
|
5145
|
+
function stepErrorDetail(error) {
|
|
5146
|
+
if (!error || typeof error !== "object") return void 0;
|
|
5147
|
+
const d = error.detail;
|
|
5148
|
+
if (!d || typeof d !== "object" || Array.isArray(d)) return void 0;
|
|
5149
|
+
const bag = d;
|
|
5150
|
+
const out = {};
|
|
5151
|
+
for (const k of STEP_ERROR_DETAIL_KEYS) {
|
|
5152
|
+
if (!(k in bag)) continue;
|
|
5153
|
+
const v = scrubDetailValue(bag[k], 1);
|
|
5154
|
+
if (v !== void 0) out[k] = v;
|
|
5155
|
+
}
|
|
5156
|
+
if (!Object.keys(out).length) return void 0;
|
|
5157
|
+
let bytes;
|
|
5158
|
+
try {
|
|
5159
|
+
bytes = new TextEncoder().encode(JSON.stringify(out)).length;
|
|
5160
|
+
} catch {
|
|
5161
|
+
return void 0;
|
|
5162
|
+
}
|
|
5163
|
+
if (bytes <= STEP_ERROR_DETAIL_MAX_BYTES) return out;
|
|
5164
|
+
const scalars = Object.fromEntries(Object.entries(out).filter(([, v]) => v === null || typeof v !== "object"));
|
|
5165
|
+
return {
|
|
5166
|
+
...scalars,
|
|
5167
|
+
__truncated: true,
|
|
5168
|
+
bytes
|
|
5169
|
+
};
|
|
5170
|
+
}
|
|
5171
|
+
__name(stepErrorDetail, "stepErrorDetail");
|
|
5172
|
+
__name3(stepErrorDetail, "stepErrorDetail");
|
|
4298
5173
|
var MAX_HOLIDAYS = 366;
|
|
4299
5174
|
var MAX_WALK_DAYS = 400;
|
|
4300
5175
|
var HHMM = /^([01]\d|2[0-3]):([0-5]\d)$/;
|
|
@@ -4903,6 +5778,34 @@ var ApprovalOnTimeoutSchema = z22.union([
|
|
|
4903
5778
|
EscalationHopSchema
|
|
4904
5779
|
])).min(1).max(ESCALATION_MAX_HOPS + 1)
|
|
4905
5780
|
]);
|
|
5781
|
+
var APPROVER_SPEC_SHAPES = [
|
|
5782
|
+
"'creator'",
|
|
5783
|
+
"'org-admins'",
|
|
5784
|
+
"{users:[userId, \u2026]}",
|
|
5785
|
+
"{role:roleName}",
|
|
5786
|
+
"{group:groupName}",
|
|
5787
|
+
"{governance:{policyId}}"
|
|
5788
|
+
];
|
|
5789
|
+
var APPROVER_WRITTEN_MAX = 120;
|
|
5790
|
+
var USER_ID_SHAPED_RE = /^[^\s@]{1,128}$/;
|
|
5791
|
+
function describeApproverSpecRefusal(spec) {
|
|
5792
|
+
const raw = spec === void 0 ? "undefined" : JSON.stringify(spec) ?? String(spec);
|
|
5793
|
+
const written = raw.length > APPROVER_WRITTEN_MAX ? `${raw.slice(0, APPROVER_WRITTEN_MAX - 1)}\u2026` : raw;
|
|
5794
|
+
const users = typeof spec === "object" && spec !== null ? spec.users : void 0;
|
|
5795
|
+
const approver = typeof users === "string" && USER_ID_SHAPED_RE.test(users) ? {
|
|
5796
|
+
users: [
|
|
5797
|
+
users
|
|
5798
|
+
]
|
|
5799
|
+
} : "creator";
|
|
5800
|
+
const message = `approver ${written} is not an approver \u2014 legal: ${APPROVER_SPEC_SHAPES.join(" | ")}. 'creator' is the person who started the run: write approver:'creator' for "ask me" / "I approve"; {users:[\u2026]} takes user ids, never emails, names or {type:'user'}` + (approver === "creator" ? "" : `; here: approver:${JSON.stringify(approver)}`);
|
|
5801
|
+
return {
|
|
5802
|
+
approver,
|
|
5803
|
+
written,
|
|
5804
|
+
message
|
|
5805
|
+
};
|
|
5806
|
+
}
|
|
5807
|
+
__name(describeApproverSpecRefusal, "describeApproverSpecRefusal");
|
|
5808
|
+
__name3(describeApproverSpecRefusal, "describeApproverSpecRefusal");
|
|
4906
5809
|
var BINDING_ROOTS = [
|
|
4907
5810
|
"initData",
|
|
4908
5811
|
"stepResults",
|
|
@@ -4937,7 +5840,19 @@ function validateApproverBlock(node, opts = {
|
|
|
4937
5840
|
if (!r.success) {
|
|
4938
5841
|
const users = spec?.users;
|
|
4939
5842
|
if (Array.isArray(users) && users.length > APPROVER_SPEC_MAX_USERS) push("cap-exceeded", path, `at most ${APPROVER_SPEC_MAX_USERS} users`);
|
|
4940
|
-
else
|
|
5843
|
+
else {
|
|
5844
|
+
const refusal = describeApproverSpecRefusal(spec);
|
|
5845
|
+
issues.push({
|
|
5846
|
+
code: "approver-invalid",
|
|
5847
|
+
path,
|
|
5848
|
+
severity: "error",
|
|
5849
|
+
message: refusal.message,
|
|
5850
|
+
repair: {
|
|
5851
|
+
approver: refusal.approver,
|
|
5852
|
+
written: refusal.written
|
|
5853
|
+
}
|
|
5854
|
+
});
|
|
5855
|
+
}
|
|
4941
5856
|
return;
|
|
4942
5857
|
}
|
|
4943
5858
|
const s = r.data;
|
|
@@ -5449,7 +6364,8 @@ var assertPredicate = /* @__PURE__ */ __name((p, where) => {
|
|
|
5449
6364
|
}, "assertPredicate");
|
|
5450
6365
|
var assertRetry = /* @__PURE__ */ __name((r, id) => {
|
|
5451
6366
|
if (!r) return;
|
|
5452
|
-
if (
|
|
6367
|
+
if (typeof r.maxAttempts === "number" && r.maxAttempts > WORKFLOW_RETRY_MAX_ATTEMPTS) throw new LuaWorkflowBuildError("cap-exceeded", `"${id}": ${workflowRetryMaxAttemptsMessage(r.maxAttempts)}`);
|
|
6368
|
+
if (r.backoff !== void 0 && !WORKFLOW_RETRY_BACKOFFS.includes(r.backoff)) throw new LuaWorkflowBuildError("backoff-invalid", `"${id}": retry.backoff must be ${WORKFLOW_RETRY_BACKOFFS.map((b) => `'${b}'`).join(" | ")}`);
|
|
5453
6369
|
if (r.maxBackoffSeconds !== void 0) {
|
|
5454
6370
|
if (r.backoff !== "exponential") throw new LuaWorkflowBuildError("backoff-invalid", `"${id}": retry.maxBackoffSeconds is only meaningful with backoff:'exponential'`);
|
|
5455
6371
|
if (r.maxBackoffSeconds <= 0 || r.backoffSeconds !== void 0 && r.maxBackoffSeconds < r.backoffSeconds) throw new LuaWorkflowBuildError("backoff-invalid", `"${id}": retry.maxBackoffSeconds must be > 0 and \u2265 backoffSeconds`);
|
|
@@ -5637,8 +6553,14 @@ function materializeEntry(entry, steps) {
|
|
|
5637
6553
|
}
|
|
5638
6554
|
}
|
|
5639
6555
|
__name(materializeEntry, "materializeEntry");
|
|
6556
|
+
var isHitlEntry = /* @__PURE__ */ __name((n2) => isWorkflowHitlEntryType(n2?.type), "isHitlEntry");
|
|
5640
6557
|
function graphHasHitl(graph, steps) {
|
|
5641
|
-
|
|
6558
|
+
for (const e of graph) {
|
|
6559
|
+
if (isHitlEntry(e)) return true;
|
|
6560
|
+
if (e.type === "parallel" && e.steps.some(isHitlEntry)) return true;
|
|
6561
|
+
if (e.type === "conditional" && (e.steps.some(isHitlEntry) || isHitlEntry(e.otherwise))) return true;
|
|
6562
|
+
if ((e.type === "foreach" || e.type === "loop") && isHitlEntry(e.step)) return true;
|
|
6563
|
+
}
|
|
5642
6564
|
return Object.values(steps).some((s) => s.suspendSchema !== void 0);
|
|
5643
6565
|
}
|
|
5644
6566
|
__name(graphHasHitl, "graphHasHitl");
|
|
@@ -5693,7 +6615,6 @@ var WorkflowBuilderImpl = class WorkflowBuilderImpl2 {
|
|
|
5693
6615
|
const [mapping, target] = arm;
|
|
5694
6616
|
if (target === void 0 || arm.length < 2) throw new LuaWorkflowBuildError("container-arm-empty", `${where}: a bare mapping arm has nothing to run`);
|
|
5695
6617
|
if (!mapping || typeof mapping !== "object" || Array.isArray(mapping)) throw new LuaWorkflowBuildError("mapping-placement", `${where}: the arm head must be a map config object`);
|
|
5696
|
-
if (mapping.type === "approval" || target.type === "approval") throw new LuaWorkflowBuildError("approval-inside-container", `${where}: approval / waitForSignal are top-level only in v1`);
|
|
5697
6618
|
assertNoClosure(mapping, `${where} arm map`);
|
|
5698
6619
|
this.recordEnvRefs(mapping);
|
|
5699
6620
|
const inner = this.armRef(target, where);
|
|
@@ -5711,8 +6632,9 @@ var WorkflowBuilderImpl = class WorkflowBuilderImpl2 {
|
|
|
5711
6632
|
if (typeof arm === "string") return {
|
|
5712
6633
|
ref: arm
|
|
5713
6634
|
};
|
|
5714
|
-
if (arm && typeof arm === "object" && arm
|
|
5715
|
-
|
|
6635
|
+
if (arm && typeof arm === "object" && isHitlEntry(arm)) {
|
|
6636
|
+
const id = arm.id;
|
|
6637
|
+
throw new LuaWorkflowBuildError("invalid-step", `${where}: an approval / waitForSignal arm is placed by id \u2014 declare it with .approval(${JSON.stringify(id ?? "id")}, \u2026) / .waitForSignal(\u2026) and pass the id string`);
|
|
5716
6638
|
}
|
|
5717
6639
|
return {
|
|
5718
6640
|
node: this.registerStep(arm, where)
|
|
@@ -5913,17 +6835,13 @@ var WorkflowBuilderImpl = class WorkflowBuilderImpl2 {
|
|
|
5913
6835
|
if (opts.workspace && opts.tier !== void 0 && opts.tier !== "job") throw new LuaWorkflowBuildError("workspace-requires-job-tier", `"${id}": a step mounting a workspace must be tier:'job'`);
|
|
5914
6836
|
if (opts.harness !== void 0 && tier !== "job") throw new LuaWorkflowBuildError("harness-requires-job-tier", `"${id}": harness is only legal on a tier:'job' agent step`);
|
|
5915
6837
|
if (opts.toolScope?.jobTools && tier !== "job") throw new LuaWorkflowBuildError("cap-exceeded", `"${id}": toolScope.jobTools require tier:'job' (job-tools-require-job-tier)`);
|
|
5916
|
-
|
|
5917
|
-
if (
|
|
5918
|
-
if (
|
|
5919
|
-
|
|
5920
|
-
|
|
5921
|
-
|
|
5922
|
-
|
|
5923
|
-
}
|
|
5924
|
-
if (opts.maxInputTokens !== void 0) {
|
|
5925
|
-
if (tier !== "job") throw new LuaWorkflowBuildError("max-turns-requires-job-tier", `"${id}": maxInputTokens is only legal on a tier:'job' agent step`);
|
|
5926
|
-
if (!Number.isInteger(opts.maxInputTokens) || opts.maxInputTokens < 1e6 || opts.maxInputTokens > 5e8) throw new LuaWorkflowBuildError("max-turns-invalid", `"${id}": maxInputTokens must be an integer 1000000..500000000`);
|
|
6838
|
+
for (const m of WORKFLOW_JOB_RANGE_MEMBERS) {
|
|
6839
|
+
if (opts[m] === void 0) continue;
|
|
6840
|
+
if (tier !== "job") throw new LuaWorkflowBuildError("max-turns-requires-job-tier", `"${id}": ${m} is only legal on a tier:'job' agent step`);
|
|
6841
|
+
if (!isWithinWorkflowJobRange(m, opts[m])) {
|
|
6842
|
+
const { min, max } = WORKFLOW_JOB_RANGES[m];
|
|
6843
|
+
throw new LuaWorkflowBuildError("max-turns-invalid", `"${id}": ${m} must be an integer ${min}..${max}`);
|
|
6844
|
+
}
|
|
5927
6845
|
}
|
|
5928
6846
|
assertTimeout({
|
|
5929
6847
|
id,
|
|
@@ -6075,8 +6993,8 @@ var WorkflowBuilderImpl = class WorkflowBuilderImpl2 {
|
|
|
6075
6993
|
itemTimeout: opts.itemTimeout
|
|
6076
6994
|
});
|
|
6077
6995
|
return this.push({
|
|
6078
|
-
kind: "
|
|
6079
|
-
|
|
6996
|
+
kind: "declare",
|
|
6997
|
+
node
|
|
6080
6998
|
});
|
|
6081
6999
|
}
|
|
6082
7000
|
waitForSignal(id, opts) {
|
|
@@ -6094,12 +7012,13 @@ var WorkflowBuilderImpl = class WorkflowBuilderImpl2 {
|
|
|
6094
7012
|
acceptedSources: opts.acceptedSources
|
|
6095
7013
|
});
|
|
6096
7014
|
return this.push({
|
|
6097
|
-
kind: "
|
|
6098
|
-
|
|
7015
|
+
kind: "declare",
|
|
7016
|
+
node
|
|
6099
7017
|
});
|
|
6100
7018
|
}
|
|
6101
7019
|
workflow(id, ref, input, opts) {
|
|
6102
7020
|
this.assertId(id, "workflow()");
|
|
7021
|
+
assertRetry(opts?.retry, id);
|
|
6103
7022
|
const name = typeof ref === "string" ? ref : ref instanceof LuaWorkflow ? ref.getName() : void 0;
|
|
6104
7023
|
if (!name) throw new LuaWorkflowBuildError("invalid-envelope", `workflow("${id}") needs a LuaWorkflow or a workflow name`);
|
|
6105
7024
|
if (opts?.workspace === "inherit") {
|
|
@@ -6121,7 +7040,8 @@ var WorkflowBuilderImpl = class WorkflowBuilderImpl2 {
|
|
|
6121
7040
|
id,
|
|
6122
7041
|
workflowId: name,
|
|
6123
7042
|
input,
|
|
6124
|
-
workspace: opts?.workspace
|
|
7043
|
+
workspace: opts?.workspace,
|
|
7044
|
+
retry: opts?.retry
|
|
6125
7045
|
});
|
|
6126
7046
|
return this.push({
|
|
6127
7047
|
kind: "declare",
|
|
@@ -6135,7 +7055,7 @@ var WorkflowBuilderImpl = class WorkflowBuilderImpl2 {
|
|
|
6135
7055
|
const { graph, issues } = resolvePlacements(this.calls);
|
|
6136
7056
|
const fatal = issues[0];
|
|
6137
7057
|
if (fatal) {
|
|
6138
|
-
const hint = fatal.code === "unknown-step-ref" ? "a string StepRef must name an entry declared by agentStep/specialistStep/toolStep/map(\u2026, { id })/workflow(\u2026) somewhere in the chain \u2014 before OR after the reference" : void 0;
|
|
7058
|
+
const hint = fatal.code === "unknown-step-ref" ? "a string StepRef must name an entry declared by agentStep/specialistStep/toolStep/map(\u2026, { id })/workflow(\u2026)/approval(\u2026)/waitForSignal(\u2026) somewhere in the chain \u2014 before OR after the reference" : void 0;
|
|
6139
7059
|
throw new LuaWorkflowBuildError(fatal.code, fatal.message, hint);
|
|
6140
7060
|
}
|
|
6141
7061
|
if (graph.length === 0) throw new LuaWorkflowBuildError("empty-graph", `workflow "${this.config.name}" has no entries`);
|