@vaudience/aigentflow-flow-validator 0.26.0 → 0.28.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/PARITY.md +96 -4
- package/README.md +5 -2
- package/dist/cli.js +599 -398
- package/dist/index.cjs +592 -389
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +592 -389
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -449,11 +449,10 @@ function validateBasicStructure(flow, issues) {
|
|
|
449
449
|
|
|
450
450
|
// src/spec/aigentflow-spec.json
|
|
451
451
|
var aigentflow_spec_default = {
|
|
452
|
-
specVersion: "2.
|
|
452
|
+
specVersion: "2.837.0",
|
|
453
453
|
inputSchemaVersion: 1,
|
|
454
454
|
executorSchemes: [
|
|
455
455
|
"a2a",
|
|
456
|
-
"agent",
|
|
457
456
|
"ai",
|
|
458
457
|
"aiv",
|
|
459
458
|
"async",
|
|
@@ -467,7 +466,6 @@ var aigentflow_spec_default = {
|
|
|
467
466
|
"email",
|
|
468
467
|
"eurostat",
|
|
469
468
|
"eval",
|
|
470
|
-
"exons",
|
|
471
469
|
"flow",
|
|
472
470
|
"function",
|
|
473
471
|
"gdelt",
|
|
@@ -482,6 +480,7 @@ var aigentflow_spec_default = {
|
|
|
482
480
|
"messenger",
|
|
483
481
|
"mock",
|
|
484
482
|
"mqtt",
|
|
483
|
+
"nexus",
|
|
485
484
|
"opencorporates",
|
|
486
485
|
"openmeteo",
|
|
487
486
|
"overpass",
|
|
@@ -546,12 +545,9 @@ var aigentflow_spec_default = {
|
|
|
546
545
|
"step_failed",
|
|
547
546
|
"mission_started",
|
|
548
547
|
"mission_completed",
|
|
549
|
-
"dfm_suggestion",
|
|
550
548
|
"timer",
|
|
551
549
|
"request_turn",
|
|
552
550
|
"mission_recovered",
|
|
553
|
-
"campaign_child_completed",
|
|
554
|
-
"campaign_child_failed",
|
|
555
551
|
"human_response",
|
|
556
552
|
"human_input"
|
|
557
553
|
],
|
|
@@ -567,15 +563,6 @@ var aigentflow_spec_default = {
|
|
|
567
563
|
"aif_ask_human",
|
|
568
564
|
"aif_flow_list",
|
|
569
565
|
"aif_mission_reflect",
|
|
570
|
-
"aif_signal_complete",
|
|
571
|
-
"aif_signal_need_human",
|
|
572
|
-
"aif_signal_delegate",
|
|
573
|
-
"aif_signal_need_tool",
|
|
574
|
-
"aif_signal_modify_flow",
|
|
575
|
-
"aif_campaign_spawn",
|
|
576
|
-
"aif_campaign_status",
|
|
577
|
-
"aif_campaign_results",
|
|
578
|
-
"aif_campaign_cancel",
|
|
579
566
|
"aif_memory_plan",
|
|
580
567
|
"aif_memory_record",
|
|
581
568
|
"aif_memory_recall",
|
|
@@ -747,24 +734,87 @@ var aigentflow_spec_default = {
|
|
|
747
734
|
orchestratorToolAllow: {
|
|
748
735
|
warningField: "orchestrator.exons",
|
|
749
736
|
askHumanTool: "aif_ask_human",
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
737
|
+
lifecycleTools: [
|
|
738
|
+
"aif_mission_complete",
|
|
739
|
+
"aif_mission_fail",
|
|
740
|
+
"aif_request_turn"
|
|
741
|
+
]
|
|
742
|
+
},
|
|
743
|
+
exons: {
|
|
744
|
+
frontmatterDelimiter: "---"
|
|
745
|
+
},
|
|
746
|
+
removedAgentSurfaces: {
|
|
747
|
+
removedSchemes: ["exons", "agent"],
|
|
748
|
+
paramScheme: "ai",
|
|
749
|
+
aiParams: [
|
|
750
|
+
"agentic",
|
|
751
|
+
"deny_tools",
|
|
752
|
+
"discoverable_tools",
|
|
753
|
+
"enable_signals",
|
|
754
|
+
"guardrails",
|
|
755
|
+
"max_tool_calls",
|
|
756
|
+
"max_tool_turns",
|
|
757
|
+
"mcp_server_url",
|
|
758
|
+
"parallel_tool_calls",
|
|
759
|
+
"require_confirmation",
|
|
760
|
+
"timeout_seconds",
|
|
761
|
+
"tool_auth_token",
|
|
762
|
+
"tool_discovery"
|
|
763
|
+
],
|
|
764
|
+
flowKeys: ["exons_uploads"],
|
|
765
|
+
executorRemovedCode: "executor_removed",
|
|
766
|
+
agenticParamRemovedCode: "agentic_param_removed",
|
|
767
|
+
schemeMessageFormat: "step %q uses %s://, which AIgentFlow no longer runs: its own agent chains were removed",
|
|
768
|
+
paramsMessageFormat: "step %q sets %s on ai://: AIgentFlow's own agent loop (agentic mode) was removed, so these parameters no longer exist",
|
|
769
|
+
flowKeyMessageFormat: "the flow-level key %q belonged to a removed agent surface and is no longer read",
|
|
770
|
+
suggestion: `Rebuild the step: a tool-using agent becomes nexus://agent/run (agent: "@org/name", prompt, capabilities); one tool becomes nexus://capability/<ref>; a plain prompt becomes ai://<provider>/chat or a prompt-only aiv://<org>/<name>. A nexus:// step acts as the person responsible for the run: who started it, who last saved its schedule or webhook trigger, or a flow:// child's parent. What cannot be converted: a run with no person (one started by a service or key that names nobody; share links no longer exist), and a step that needs an inline .exons spec, an arbitrary MCP server URL or signals. For those, start the flow from a person, a schedule or a trigger, or use a routine in Nexus`
|
|
771
|
+
},
|
|
772
|
+
removedSignalSurfaces: {
|
|
773
|
+
signalRemovedCode: "signal_removed",
|
|
774
|
+
flowModificationRemovedCode: "flow_modification_removed",
|
|
775
|
+
removedKeyIgnoredCode: "removed_key_ignored",
|
|
776
|
+
tools: [
|
|
753
777
|
"aif_signal_complete",
|
|
754
778
|
"aif_signal_need_human",
|
|
755
779
|
"aif_signal_delegate",
|
|
756
780
|
"aif_signal_need_tool",
|
|
757
781
|
"aif_signal_modify_flow"
|
|
758
782
|
],
|
|
759
|
-
|
|
760
|
-
"
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
783
|
+
triggers: [
|
|
784
|
+
"dfm_suggestion"
|
|
785
|
+
],
|
|
786
|
+
stepKey: "enable_signals",
|
|
787
|
+
stepKeyScheme: "aiv",
|
|
788
|
+
flowModificationStepKey: "flow_modification_allowed",
|
|
789
|
+
stepSkipSchemes: [
|
|
790
|
+
"flow"
|
|
791
|
+
],
|
|
792
|
+
enableSignalsMessage: "the orchestrator sets enable_signals: true: AIgentFlow's agent signals were removed in 2.834.0, so the tools it asks for no longer exist",
|
|
793
|
+
toolNamesMessageFormat: "%s names %s: AIgentFlow's agent signal tools were removed in 2.834.0",
|
|
794
|
+
stepKeyMessageFormat: "step %q sets enable_signals: AIgentFlow's agent signals were removed in 2.834.0, so the parameter no longer exists",
|
|
795
|
+
triggersMessage: "orchestrator.triggers names dfm_suggestion: dynamic flow modification was removed in 2.834.0, so nothing raises that trigger",
|
|
796
|
+
flowModificationStepMessageFormat: "step %q sets flow_modification_allowed: dynamic flow modification was removed in 2.834.0",
|
|
797
|
+
ignoredKeyMessageFormat: "%s is ignored: it configured AIgentFlow's agent signals / dynamic flow modification, removed in 2.834.0. AIgentFlow may have written this key into the flow itself; the flow runs as if it were absent",
|
|
798
|
+
ignoredKeySuggestion: "Remove the key; nothing reads it",
|
|
799
|
+
suggestion: "Signals and dynamic flow modification were removed in 2.834.0. aif_signal_need_human: add an async://human/<operation> step where the person must answer (inside a nexus://agent/run step, the atlas approval wait asks the person). aif_signal_delegate: run the other work as a flow:// step, or route with next: conditions. aif_signal_complete: an orchestrator ends the mission with aif_mission_complete. aif_signal_need_tool: no replacement; give the agent the capability in atlas. aif_signal_modify_flow, dfm_suggestion and flow_modification_allowed: no replacement; declare every step the flow may run and choose between them with next: conditions"
|
|
765
800
|
},
|
|
766
|
-
|
|
767
|
-
|
|
801
|
+
removedCampaignSurfaces: {
|
|
802
|
+
code: "campaign_removed",
|
|
803
|
+
flowKey: "campaign",
|
|
804
|
+
tools: [
|
|
805
|
+
"aif_campaign_spawn",
|
|
806
|
+
"aif_campaign_status",
|
|
807
|
+
"aif_campaign_results",
|
|
808
|
+
"aif_campaign_cancel"
|
|
809
|
+
],
|
|
810
|
+
triggers: [
|
|
811
|
+
"campaign_child_completed",
|
|
812
|
+
"campaign_child_failed"
|
|
813
|
+
],
|
|
814
|
+
blockMessage: "the flow declares a campaign: block: campaigns were removed in 2.836.0, so nothing would spawn or track its child missions",
|
|
815
|
+
toolNamesMessageFormat: "%s names %s: AIgentFlow's campaign tools were removed in 2.836.0",
|
|
816
|
+
triggersMessageFormat: "orchestrator.triggers names %s: campaigns were removed in 2.836.0, so no child mission raises that trigger",
|
|
817
|
+
suggestion: "Campaigns were removed in 2.836.0. Fan the work out inside one flow instead: a for_each step whose executor is flow://stored/<flow_id> runs the child flow once per item and hands the next step every result (.data.<step>, in item order), so a coordinator -> workers -> synthesiser campaign becomes a plan step -> a for_each over flow:// -> a synthesis step (a fixed set of different workers is next: parallel: with a rendezvous). When each worker is an agent, make the worker a nexus://agent/run step (the for_each step itself, or a step of the child flow): it runs as the person responsible for the run, and a flow:// child inherits its parent's. Delete the campaign: block, the aif_campaign_* tool names and the campaign_child_* triggers"
|
|
768
818
|
},
|
|
769
819
|
executorConfigEnvScopes: {
|
|
770
820
|
referencePrefix: "${",
|
|
@@ -988,19 +1038,20 @@ var aigentflow_spec_default = {
|
|
|
988
1038
|
]
|
|
989
1039
|
},
|
|
990
1040
|
atlasExecutor: {
|
|
991
|
-
scheme: "
|
|
1041
|
+
scheme: "nexus",
|
|
1042
|
+
aliases: ["atlas"],
|
|
992
1043
|
providerAgent: "agent",
|
|
993
1044
|
providerCapability: "capability",
|
|
994
1045
|
agentResource: "run",
|
|
995
1046
|
capabilityRefPattern: "^[A-Za-z0-9][A-Za-z0-9_-]{0,127}$",
|
|
996
1047
|
operationUnknown: {
|
|
997
1048
|
code: "atlas_operation_unknown",
|
|
998
|
-
messageFormat: "step %s uses %s, which is not
|
|
999
|
-
suggestion: "Use
|
|
1049
|
+
messageFormat: "step %s uses %s, which is not a Nexus operation. The providers are agent (resource run) and capability (resource: a capability reference).",
|
|
1050
|
+
suggestion: "Use nexus://agent/run or nexus://capability/<capability-ref>."
|
|
1000
1051
|
},
|
|
1001
1052
|
agentMissing: {
|
|
1002
1053
|
code: "atlas_agent_missing",
|
|
1003
|
-
messageFormat: "step %s runs
|
|
1054
|
+
messageFormat: "step %s runs a Nexus agent but query.agent is missing, empty or not a string.",
|
|
1004
1055
|
suggestion: "Set query.agent to the agent to run, written out as a literal such as @acme/reporter."
|
|
1005
1056
|
},
|
|
1006
1057
|
agentNotLiteral: {
|
|
@@ -1015,7 +1066,7 @@ var aigentflow_spec_default = {
|
|
|
1015
1066
|
},
|
|
1016
1067
|
promptMissing: {
|
|
1017
1068
|
code: "atlas_prompt_missing",
|
|
1018
|
-
messageFormat: "step %s runs
|
|
1069
|
+
messageFormat: "step %s runs a Nexus agent with neither query.prompt nor query.prompt_template.",
|
|
1019
1070
|
suggestion: "Set exactly one of query.prompt or query.prompt_template."
|
|
1020
1071
|
},
|
|
1021
1072
|
promptBoth: {
|
|
@@ -1025,7 +1076,7 @@ var aigentflow_spec_default = {
|
|
|
1025
1076
|
},
|
|
1026
1077
|
capabilityRefInvalid: {
|
|
1027
1078
|
code: "atlas_capability_ref_invalid",
|
|
1028
|
-
messageFormat: "step %s uses
|
|
1079
|
+
messageFormat: "step %s uses nexus://capability/%s, which is not a valid capability reference.",
|
|
1029
1080
|
suggestion: "A capability reference starts with a letter or digit and continues with letters, digits, _ and - up to 128 characters in all."
|
|
1030
1081
|
},
|
|
1031
1082
|
modelNotLiteral: {
|
|
@@ -1552,20 +1603,6 @@ var aigentflow_spec_default = {
|
|
|
1552
1603
|
BillingConfig: {
|
|
1553
1604
|
max_credits: "scalar"
|
|
1554
1605
|
},
|
|
1555
|
-
CampaignChildFlowDef: {
|
|
1556
|
-
alias: "scalar",
|
|
1557
|
-
flow_id: "scalar",
|
|
1558
|
-
flow_name: "scalar"
|
|
1559
|
-
},
|
|
1560
|
-
CampaignConfig: {
|
|
1561
|
-
child_flows: "list<CampaignChildFlowDef>",
|
|
1562
|
-
max_concurrent: "scalar",
|
|
1563
|
-
max_credits_per_child: "scalar",
|
|
1564
|
-
max_depth: "scalar",
|
|
1565
|
-
max_total_children: "scalar",
|
|
1566
|
-
on_children_complete: "scalar",
|
|
1567
|
-
shared_memory: "scalar"
|
|
1568
|
-
},
|
|
1569
1606
|
Checkpoint: {
|
|
1570
1607
|
exact: "map<any>",
|
|
1571
1608
|
fields: "map<FieldMatcher>",
|
|
@@ -1699,7 +1736,7 @@ var aigentflow_spec_default = {
|
|
|
1699
1736
|
Flow: {
|
|
1700
1737
|
aigentflow_version: "scalar",
|
|
1701
1738
|
billing: "BillingConfig",
|
|
1702
|
-
campaign: "
|
|
1739
|
+
campaign: "any",
|
|
1703
1740
|
checkpoint: "CheckpointConfig",
|
|
1704
1741
|
classification: "FlowClassification",
|
|
1705
1742
|
compliance: "FlowCompliance",
|
|
@@ -2009,15 +2046,64 @@ var KNOWN_KEYS = aigentflow_spec_default.knownKeys;
|
|
|
2009
2046
|
var ORCHESTRATOR_TOOL_ALLOW = {
|
|
2010
2047
|
warningField: aigentflow_spec_default.orchestratorToolAllow.warningField,
|
|
2011
2048
|
askHumanTool: aigentflow_spec_default.orchestratorToolAllow.askHumanTool,
|
|
2012
|
-
|
|
2013
|
-
lifecycleTools: aigentflow_spec_default.orchestratorToolAllow.lifecycleTools,
|
|
2014
|
-
signalTools: aigentflow_spec_default.orchestratorToolAllow.signalTools,
|
|
2015
|
-
campaignTools: aigentflow_spec_default.orchestratorToolAllow.campaignTools
|
|
2049
|
+
lifecycleTools: aigentflow_spec_default.orchestratorToolAllow.lifecycleTools
|
|
2016
2050
|
};
|
|
2017
2051
|
var EXONS = {
|
|
2018
2052
|
/** The YAML frontmatter delimiter line. */
|
|
2019
2053
|
frontmatterDelimiter: aigentflow_spec_default.exons.frontmatterDelimiter
|
|
2020
2054
|
};
|
|
2055
|
+
var removed = aigentflow_spec_default.removedAgentSurfaces;
|
|
2056
|
+
var REMOVED_AGENT_SURFACES = {
|
|
2057
|
+
schemes: new Set(removed.removedSchemes),
|
|
2058
|
+
paramScheme: removed.paramScheme,
|
|
2059
|
+
aiParams: new Set(removed.aiParams),
|
|
2060
|
+
flowKeys: removed.flowKeys,
|
|
2061
|
+
executorRemovedCode: removed.executorRemovedCode,
|
|
2062
|
+
agenticParamRemovedCode: removed.agenticParamRemovedCode,
|
|
2063
|
+
schemeMessageFormat: removed.schemeMessageFormat,
|
|
2064
|
+
paramsMessageFormat: removed.paramsMessageFormat,
|
|
2065
|
+
flowKeyMessageFormat: removed.flowKeyMessageFormat,
|
|
2066
|
+
suggestion: removed.suggestion
|
|
2067
|
+
};
|
|
2068
|
+
var signal = aigentflow_spec_default.removedSignalSurfaces;
|
|
2069
|
+
var REMOVED_SIGNAL_SURFACES = {
|
|
2070
|
+
signalRemovedCode: signal.signalRemovedCode,
|
|
2071
|
+
flowModificationRemovedCode: signal.flowModificationRemovedCode,
|
|
2072
|
+
removedKeyIgnoredCode: signal.removedKeyIgnoredCode,
|
|
2073
|
+
tools: signal.tools,
|
|
2074
|
+
triggers: signal.triggers,
|
|
2075
|
+
stepKey: signal.stepKey,
|
|
2076
|
+
stepKeyScheme: signal.stepKeyScheme,
|
|
2077
|
+
flowModificationStepKey: signal.flowModificationStepKey,
|
|
2078
|
+
stepSkipSchemes: new Set(signal.stepSkipSchemes),
|
|
2079
|
+
enableSignalsMessage: signal.enableSignalsMessage,
|
|
2080
|
+
toolNamesMessageFormat: signal.toolNamesMessageFormat,
|
|
2081
|
+
stepKeyMessageFormat: signal.stepKeyMessageFormat,
|
|
2082
|
+
triggersMessage: signal.triggersMessage,
|
|
2083
|
+
flowModificationStepMessageFormat: signal.flowModificationStepMessageFormat,
|
|
2084
|
+
ignoredKeyMessageFormat: signal.ignoredKeyMessageFormat,
|
|
2085
|
+
ignoredKeySuggestion: signal.ignoredKeySuggestion,
|
|
2086
|
+
suggestion: signal.suggestion
|
|
2087
|
+
};
|
|
2088
|
+
var campaign = aigentflow_spec_default.removedCampaignSurfaces;
|
|
2089
|
+
var REMOVED_CAMPAIGN_SURFACES = {
|
|
2090
|
+
code: campaign.code,
|
|
2091
|
+
flowKey: campaign.flowKey,
|
|
2092
|
+
tools: campaign.tools,
|
|
2093
|
+
triggers: campaign.triggers,
|
|
2094
|
+
blockMessage: campaign.blockMessage,
|
|
2095
|
+
toolNamesMessageFormat: campaign.toolNamesMessageFormat,
|
|
2096
|
+
triggersMessageFormat: campaign.triggersMessageFormat,
|
|
2097
|
+
suggestion: campaign.suggestion
|
|
2098
|
+
};
|
|
2099
|
+
var REMOVED_ORCHESTRATOR_TOOLS = /* @__PURE__ */ new Set([
|
|
2100
|
+
...signal.tools,
|
|
2101
|
+
...campaign.tools
|
|
2102
|
+
]);
|
|
2103
|
+
var REMOVED_ORCHESTRATOR_TRIGGERS = /* @__PURE__ */ new Set([
|
|
2104
|
+
...signal.triggers,
|
|
2105
|
+
...campaign.triggers
|
|
2106
|
+
]);
|
|
2021
2107
|
var EXECUTOR_CONFIG_ENV_SCOPES = {
|
|
2022
2108
|
referencePrefix: aigentflow_spec_default.executorConfigEnvScopes.referencePrefix,
|
|
2023
2109
|
referenceSuffix: aigentflow_spec_default.executorConfigEnvScopes.referenceSuffix,
|
|
@@ -2110,7 +2196,8 @@ var FUNCTION_OPERATIONS = {
|
|
|
2110
2196
|
};
|
|
2111
2197
|
var atlas = aigentflow_spec_default.atlasExecutor;
|
|
2112
2198
|
var ATLAS_EXECUTOR = {
|
|
2113
|
-
scheme:
|
|
2199
|
+
/** The canonical scheme (nexus) and its aliases (atlas): one set of rules. */
|
|
2200
|
+
schemes: /* @__PURE__ */ new Set([atlas.scheme, ...atlas.aliases]),
|
|
2114
2201
|
providerAgent: atlas.providerAgent,
|
|
2115
2202
|
providerCapability: atlas.providerCapability,
|
|
2116
2203
|
agentResource: atlas.agentResource,
|
|
@@ -2139,6 +2226,220 @@ var RESERVED_INPUT_NAMES = {
|
|
|
2139
2226
|
queryFieldFormat: aigentflow_spec_default.reservedInputNames.queryFieldFormat,
|
|
2140
2227
|
schemaFieldFormat: aigentflow_spec_default.reservedInputNames.schemaFieldFormat
|
|
2141
2228
|
};
|
|
2229
|
+
var CODE_PARSE_FAILED = "orchestrator_exons_parse_failed";
|
|
2230
|
+
var CODE_NO_PROVIDER = "orchestrator_exons_no_provider";
|
|
2231
|
+
var CODE_RESOURCES = "exons_resources_unhonoured";
|
|
2232
|
+
var CODE_TOOL_WITHHELD = "orchestrator_tool_withheld";
|
|
2233
|
+
var EXONS_OPEN_DELIM = "{~";
|
|
2234
|
+
var EXONS_LEGACY_CONFIG_OPEN = "{~exons.config~}";
|
|
2235
|
+
var UTF8_BOM = "\uFEFF";
|
|
2236
|
+
var MAX_ALIAS_COUNT2 = 100;
|
|
2237
|
+
var UNREAD = {
|
|
2238
|
+
parseError: null,
|
|
2239
|
+
specRead: false,
|
|
2240
|
+
hasSpec: false,
|
|
2241
|
+
provider: "",
|
|
2242
|
+
toolsAllowDeclared: false,
|
|
2243
|
+
toolsAllow: [],
|
|
2244
|
+
resources: []
|
|
2245
|
+
};
|
|
2246
|
+
var GO_SPACE = "\\t\\n\\v\\f\\r \\u0085\\u00a0\\u1680\\u2000-\\u200a\\u2028\\u2029\\u202f\\u205f\\u3000";
|
|
2247
|
+
var GO_TRIM_SPACE = new RegExp(`^[${GO_SPACE}]+|[${GO_SPACE}]+$`, "g");
|
|
2248
|
+
function goTrimSpace(s) {
|
|
2249
|
+
return s.replace(GO_TRIM_SPACE, "");
|
|
2250
|
+
}
|
|
2251
|
+
function extractExonsFrontmatter(source) {
|
|
2252
|
+
const delim = EXONS.frontmatterDelimiter;
|
|
2253
|
+
let start = source.startsWith(UTF8_BOM) ? source.slice(UTF8_BOM.length) : source;
|
|
2254
|
+
start = start.replace(/^[ \t]+/, "");
|
|
2255
|
+
if (start.startsWith(EXONS_LEGACY_CONFIG_OPEN)) {
|
|
2256
|
+
return {
|
|
2257
|
+
frontmatter: "",
|
|
2258
|
+
hasFrontmatter: false,
|
|
2259
|
+
parseError: "legacy JSON config block detected; use YAML frontmatter"
|
|
2260
|
+
};
|
|
2261
|
+
}
|
|
2262
|
+
if (!start.startsWith(delim)) return { frontmatter: "", hasFrontmatter: false, parseError: null };
|
|
2263
|
+
let rest = start.slice(delim.length);
|
|
2264
|
+
if (rest.startsWith("\n")) rest = rest.slice(1);
|
|
2265
|
+
else if (rest.startsWith("\r\n")) rest = rest.slice(2);
|
|
2266
|
+
else return { frontmatter: "", hasFrontmatter: false, parseError: null };
|
|
2267
|
+
let pos = 0;
|
|
2268
|
+
while (pos <= rest.length) {
|
|
2269
|
+
const line = rest.slice(pos);
|
|
2270
|
+
if (line.startsWith(delim)) {
|
|
2271
|
+
const after = line.slice(delim.length);
|
|
2272
|
+
if (after === "" || after[0] === "\n" || after[0] === "\r") {
|
|
2273
|
+
return {
|
|
2274
|
+
frontmatter: goTrimSpace(rest.slice(0, pos)),
|
|
2275
|
+
hasFrontmatter: true,
|
|
2276
|
+
parseError: null
|
|
2277
|
+
};
|
|
2278
|
+
}
|
|
2279
|
+
}
|
|
2280
|
+
const nl = line.indexOf("\n");
|
|
2281
|
+
if (nl < 0) break;
|
|
2282
|
+
pos += nl + 1;
|
|
2283
|
+
}
|
|
2284
|
+
return {
|
|
2285
|
+
frontmatter: "",
|
|
2286
|
+
hasFrontmatter: true,
|
|
2287
|
+
parseError: "YAML frontmatter not properly closed"
|
|
2288
|
+
};
|
|
2289
|
+
}
|
|
2290
|
+
function retagScalars(node) {
|
|
2291
|
+
if (isMap(node)) {
|
|
2292
|
+
for (const pair of node.items) {
|
|
2293
|
+
retagScalars(pair.key);
|
|
2294
|
+
retagScalars(pair.value);
|
|
2295
|
+
}
|
|
2296
|
+
} else if (isSeq(node)) {
|
|
2297
|
+
for (const item of node.items) retagScalars(item);
|
|
2298
|
+
} else if (isScalar(node) && (typeof node.value === "number" || typeof node.value === "boolean") && typeof node.source === "string") {
|
|
2299
|
+
node.value = node.source;
|
|
2300
|
+
}
|
|
2301
|
+
}
|
|
2302
|
+
var DecodeError = class extends Error {
|
|
2303
|
+
};
|
|
2304
|
+
function goString(v) {
|
|
2305
|
+
if (v === null || v === void 0) return "";
|
|
2306
|
+
if (isString(v)) return v;
|
|
2307
|
+
throw new DecodeError("not a string");
|
|
2308
|
+
}
|
|
2309
|
+
function goStringList(v) {
|
|
2310
|
+
if (v === null || v === void 0) return null;
|
|
2311
|
+
if (!isArray(v)) throw new DecodeError("not a list");
|
|
2312
|
+
return v.filter((item) => item !== null).map(goString);
|
|
2313
|
+
}
|
|
2314
|
+
function goStruct(v) {
|
|
2315
|
+
if (v === null || v === void 0) return null;
|
|
2316
|
+
if (!isRecord(v)) throw new DecodeError("not a mapping");
|
|
2317
|
+
return v;
|
|
2318
|
+
}
|
|
2319
|
+
function decodeSpecFields(frontmatter) {
|
|
2320
|
+
let value;
|
|
2321
|
+
try {
|
|
2322
|
+
const docs = parseAllDocuments(frontmatter, { merge: true });
|
|
2323
|
+
const doc = Array.isArray(docs) ? docs[0] : void 0;
|
|
2324
|
+
if (doc === void 0) {
|
|
2325
|
+
value = null;
|
|
2326
|
+
} else {
|
|
2327
|
+
if (doc.errors.length > 0) return null;
|
|
2328
|
+
retagScalars(doc.contents);
|
|
2329
|
+
value = doc.toJS({ maxAliasCount: MAX_ALIAS_COUNT2 });
|
|
2330
|
+
}
|
|
2331
|
+
} catch {
|
|
2332
|
+
return null;
|
|
2333
|
+
}
|
|
2334
|
+
try {
|
|
2335
|
+
const root = goStruct(value) ?? {};
|
|
2336
|
+
const execution = goStruct(root.execution);
|
|
2337
|
+
const tools = goStruct(root.tools);
|
|
2338
|
+
const requirements = goStruct(root.requirements);
|
|
2339
|
+
const allow = tools === null ? null : goStringList(tools.allow);
|
|
2340
|
+
let resources = [];
|
|
2341
|
+
if (requirements !== null) {
|
|
2342
|
+
const raw = requirements.resources;
|
|
2343
|
+
if (raw !== null && raw !== void 0) {
|
|
2344
|
+
if (!isArray(raw)) throw new DecodeError("not a list");
|
|
2345
|
+
resources = raw.filter((entry) => entry !== null).map((entry) => {
|
|
2346
|
+
const r = goStruct(entry) ?? {};
|
|
2347
|
+
return { ref: goString(r.ref), kind: goString(r.kind), scope: goString(r.scope) };
|
|
2348
|
+
});
|
|
2349
|
+
}
|
|
2350
|
+
}
|
|
2351
|
+
return {
|
|
2352
|
+
provider: execution === null ? "" : goString(execution.provider),
|
|
2353
|
+
toolsAllowDeclared: allow !== null,
|
|
2354
|
+
toolsAllow: allow ?? [],
|
|
2355
|
+
resources
|
|
2356
|
+
};
|
|
2357
|
+
} catch (e) {
|
|
2358
|
+
if (e instanceof DecodeError) return null;
|
|
2359
|
+
throw e;
|
|
2360
|
+
}
|
|
2361
|
+
}
|
|
2362
|
+
function inspectExonsFrontmatter(source) {
|
|
2363
|
+
const fm = extractExonsFrontmatter(source);
|
|
2364
|
+
if (fm.parseError !== null) return { ...UNREAD, parseError: fm.parseError };
|
|
2365
|
+
if (!fm.hasFrontmatter || fm.frontmatter === "") return { ...UNREAD, specRead: true };
|
|
2366
|
+
if (fm.frontmatter.includes(EXONS_OPEN_DELIM)) return { ...UNREAD };
|
|
2367
|
+
const fields = decodeSpecFields(fm.frontmatter);
|
|
2368
|
+
if (fields === null) return { ...UNREAD };
|
|
2369
|
+
return { parseError: null, specRead: true, hasSpec: true, ...fields };
|
|
2370
|
+
}
|
|
2371
|
+
function validateOrchestratorExons(flow, issues) {
|
|
2372
|
+
const orch = flow.orchestrator;
|
|
2373
|
+
if (!isRecord(orch)) return;
|
|
2374
|
+
const source = issues.stringOf(orch, "exons", "orchestrator");
|
|
2375
|
+
if (source === null || source === "") return;
|
|
2376
|
+
const field = "orchestrator.exons";
|
|
2377
|
+
const report = inspectExonsFrontmatter(source);
|
|
2378
|
+
if (report.parseError !== null) {
|
|
2379
|
+
issues.error({
|
|
2380
|
+
field,
|
|
2381
|
+
code: CODE_PARSE_FAILED,
|
|
2382
|
+
message: `orchestrator: failed to parse exons spec: ${report.parseError}`
|
|
2383
|
+
});
|
|
2384
|
+
return;
|
|
2385
|
+
}
|
|
2386
|
+
if (!report.specRead) return;
|
|
2387
|
+
if (!report.hasSpec) {
|
|
2388
|
+
issues.error({
|
|
2389
|
+
field,
|
|
2390
|
+
code: CODE_PARSE_FAILED,
|
|
2391
|
+
message: "orchestrator: failed to parse exons spec: the document has no frontmatter spec",
|
|
2392
|
+
suggestion: "Start the document with a --- frontmatter block that sets execution.provider"
|
|
2393
|
+
});
|
|
2394
|
+
return;
|
|
2395
|
+
}
|
|
2396
|
+
if (report.provider === "") {
|
|
2397
|
+
issues.error({
|
|
2398
|
+
field,
|
|
2399
|
+
code: CODE_NO_PROVIDER,
|
|
2400
|
+
message: "orchestrator: exons spec must have execution.provider set"
|
|
2401
|
+
});
|
|
2402
|
+
}
|
|
2403
|
+
if (report.resources.length > 0) {
|
|
2404
|
+
const refs = report.resources.map((r) => `${JSON.stringify(r.ref)} (kind ${r.kind})`);
|
|
2405
|
+
issues.error({
|
|
2406
|
+
field,
|
|
2407
|
+
code: CODE_RESOURCES,
|
|
2408
|
+
message: "the orchestrator's exons spec declares requirements.resources that AIgentFlow cannot honour, so it is refused rather than run without the narrowing it asks for: " + refs.join("; "),
|
|
2409
|
+
suggestion: "Remove requirements.resources, and narrow the agent with tools.mcp_servers and tools.allow"
|
|
2410
|
+
});
|
|
2411
|
+
}
|
|
2412
|
+
warnOrchestratorToolWithheld(orch, report, issues);
|
|
2413
|
+
}
|
|
2414
|
+
function warnOrchestratorToolWithheld(orch, report, issues) {
|
|
2415
|
+
if (!report.toolsAllowDeclared) return;
|
|
2416
|
+
const cfg = ORCHESTRATOR_TOOL_ALLOW;
|
|
2417
|
+
const exempt = new Set(cfg.lifecycleTools);
|
|
2418
|
+
const allow = new Set(report.toolsAllow);
|
|
2419
|
+
const withheld = (name) => !allow.has(name) && !exempt.has(name) && !REMOVED_ORCHESTRATOR_TOOLS.has(name);
|
|
2420
|
+
const warn = (message) => issues.warn({ field: cfg.warningField, code: CODE_TOOL_WITHHELD, message });
|
|
2421
|
+
const named = [];
|
|
2422
|
+
if (isArray(orch.tools)) {
|
|
2423
|
+
orch.tools.forEach((raw, i) => {
|
|
2424
|
+
const name = issues.stringAt(raw, `orchestrator.tools[${i}]`);
|
|
2425
|
+
if (name !== null) named.push(name);
|
|
2426
|
+
});
|
|
2427
|
+
}
|
|
2428
|
+
if (named.length > 0) {
|
|
2429
|
+
for (const name of named) {
|
|
2430
|
+
if (!withheld(name)) continue;
|
|
2431
|
+
warn(
|
|
2432
|
+
`orchestrator tool '${name}' is named in orchestrator.tools but the orchestrator's exons definition's tools.allow does not name it, so it is never offered: a tool must pass both lists. Add '${name}' to tools.allow, or remove it from orchestrator.tools.`
|
|
2433
|
+
);
|
|
2434
|
+
}
|
|
2435
|
+
return;
|
|
2436
|
+
}
|
|
2437
|
+
if (withheld(cfg.askHumanTool)) {
|
|
2438
|
+
warn(
|
|
2439
|
+
`the orchestrator's exons definition has a tools.allow list that does not name ${cfg.askHumanTool}, so this orchestrator can never ask a person a question: human intervention is off. Add ${cfg.askHumanTool} to tools.allow if a human should be reachable, or ignore this if the orchestrator is meant to run unattended.`
|
|
2440
|
+
);
|
|
2441
|
+
}
|
|
2442
|
+
}
|
|
2142
2443
|
|
|
2143
2444
|
// src/validators/executors.ts
|
|
2144
2445
|
var SCHEME_SEPARATOR = "://";
|
|
@@ -2202,11 +2503,61 @@ function checkExecutor(executor, field, stepID, issues) {
|
|
|
2202
2503
|
}
|
|
2203
2504
|
checkFunctionOperation(executor, field, stepID, templated, issues);
|
|
2204
2505
|
}
|
|
2506
|
+
function removedExecutorScheme(executor) {
|
|
2507
|
+
if (executor.includes(TEMPLATE_ACTION_OPEN)) return "";
|
|
2508
|
+
const trimmed = goTrimSpace(executor);
|
|
2509
|
+
const at = trimmed.indexOf(SCHEME_SEPARATOR);
|
|
2510
|
+
return at < 0 ? "" : trimmed.slice(0, at).toLowerCase();
|
|
2511
|
+
}
|
|
2512
|
+
function checkRemovedSurfaces(executor, query, field, stepID, issues) {
|
|
2513
|
+
const cfg = REMOVED_AGENT_SURFACES;
|
|
2514
|
+
const quoted = JSON.stringify(stepID);
|
|
2515
|
+
const scheme = removedExecutorScheme(executor);
|
|
2516
|
+
if (cfg.schemes.has(scheme)) {
|
|
2517
|
+
issues.error({
|
|
2518
|
+
field,
|
|
2519
|
+
message: fillRemovedMessage(cfg.schemeMessageFormat, quoted, scheme),
|
|
2520
|
+
code: cfg.executorRemovedCode,
|
|
2521
|
+
stepId: stepID,
|
|
2522
|
+
suggestion: cfg.suggestion
|
|
2523
|
+
});
|
|
2524
|
+
return true;
|
|
2525
|
+
}
|
|
2526
|
+
if (scheme !== cfg.paramScheme || !isRecord(query)) return false;
|
|
2527
|
+
const found = Object.keys(query).filter((key) => cfg.aiParams.has(key)).sort();
|
|
2528
|
+
if (found.length > 0) {
|
|
2529
|
+
issues.error({
|
|
2530
|
+
field,
|
|
2531
|
+
message: fillRemovedMessage(cfg.paramsMessageFormat, quoted, found.join(", ")),
|
|
2532
|
+
code: cfg.agenticParamRemovedCode,
|
|
2533
|
+
stepId: stepID,
|
|
2534
|
+
suggestion: cfg.suggestion
|
|
2535
|
+
});
|
|
2536
|
+
}
|
|
2537
|
+
return false;
|
|
2538
|
+
}
|
|
2539
|
+
function fillRemovedMessage(format, ...args) {
|
|
2540
|
+
let i = 0;
|
|
2541
|
+
return format.replace(/%[qs]/g, () => args[i++] ?? "");
|
|
2542
|
+
}
|
|
2543
|
+
function validateRemovedFlowKeys(flow, issues) {
|
|
2544
|
+
const cfg = REMOVED_AGENT_SURFACES;
|
|
2545
|
+
for (const key of cfg.flowKeys) {
|
|
2546
|
+
if (Object.prototype.hasOwnProperty.call(flow, key)) {
|
|
2547
|
+
issues.error({
|
|
2548
|
+
field: key,
|
|
2549
|
+
message: fillRemovedMessage(cfg.flowKeyMessageFormat, JSON.stringify(key)),
|
|
2550
|
+
code: cfg.executorRemovedCode,
|
|
2551
|
+
suggestion: cfg.suggestion
|
|
2552
|
+
});
|
|
2553
|
+
}
|
|
2554
|
+
}
|
|
2555
|
+
}
|
|
2205
2556
|
function checkAtlasStep(executor, query, stepField, stepID, issues) {
|
|
2206
2557
|
if (executor.includes(TEMPLATE_ACTION_OPEN)) return;
|
|
2207
|
-
const
|
|
2208
|
-
if (!executor.
|
|
2209
|
-
const rest = executor.slice(
|
|
2558
|
+
const sep = executor.indexOf(SCHEME_SEPARATOR);
|
|
2559
|
+
if (sep < 0 || !ATLAS_EXECUTOR.schemes.has(executor.slice(0, sep))) return;
|
|
2560
|
+
const rest = executor.slice(sep + SCHEME_SEPARATOR.length);
|
|
2210
2561
|
const slash = rest.indexOf("/");
|
|
2211
2562
|
const provider = slash < 0 ? rest : rest.slice(0, slash);
|
|
2212
2563
|
const resource = slash < 0 ? "" : rest.slice(slash + 1);
|
|
@@ -2282,7 +2633,9 @@ function validateExecutors(flow, issues) {
|
|
|
2282
2633
|
const step = rawStep;
|
|
2283
2634
|
const executor = issues.stringOf(step, "executor", `steps.${stepID}`);
|
|
2284
2635
|
if (executor !== null && executor !== "") {
|
|
2285
|
-
|
|
2636
|
+
if (!checkRemovedSurfaces(executor, step.query, `steps.${stepID}`, stepID, issues)) {
|
|
2637
|
+
checkExecutor(executor, `steps.${stepID}.executor`, stepID, issues);
|
|
2638
|
+
}
|
|
2286
2639
|
checkAtlasStep(executor, step.query, `steps.${stepID}`, stepID, issues);
|
|
2287
2640
|
}
|
|
2288
2641
|
const loop = step.loop;
|
|
@@ -2294,12 +2647,14 @@ function validateExecutors(flow, issues) {
|
|
|
2294
2647
|
const subID = issues.stringOf(subStep, "id", subPath) ?? String(i);
|
|
2295
2648
|
const subExecutor = issues.stringOf(subStep, "executor", subPath);
|
|
2296
2649
|
if (subExecutor !== null && subExecutor !== "") {
|
|
2297
|
-
|
|
2298
|
-
|
|
2299
|
-
|
|
2300
|
-
|
|
2301
|
-
|
|
2302
|
-
|
|
2650
|
+
if (!checkRemovedSurfaces(subExecutor, subStep.query, subPath, `${stepID}.${subID}`, issues)) {
|
|
2651
|
+
checkExecutor(
|
|
2652
|
+
subExecutor,
|
|
2653
|
+
`steps.${stepID}.loop.steps[${i}].executor`,
|
|
2654
|
+
`${stepID}.${subID}`,
|
|
2655
|
+
issues
|
|
2656
|
+
);
|
|
2657
|
+
}
|
|
2303
2658
|
checkAtlasStep(subExecutor, subStep.query, subPath, `${stepID}.${subID}`, issues);
|
|
2304
2659
|
}
|
|
2305
2660
|
});
|
|
@@ -3415,49 +3770,6 @@ function flowHasOrchestratorYieldEdge(flow) {
|
|
|
3415
3770
|
}
|
|
3416
3771
|
return false;
|
|
3417
3772
|
}
|
|
3418
|
-
var GO_INT64_FLOAT_LIMIT = 2 ** 63;
|
|
3419
|
-
function decodeGoInt(v) {
|
|
3420
|
-
if (typeof v !== "number" || Number.isNaN(v)) return null;
|
|
3421
|
-
if (v >= GO_INT64_FLOAT_LIMIT) return null;
|
|
3422
|
-
if (v === -Infinity) return -GO_INT64_FLOAT_LIMIT;
|
|
3423
|
-
return Math.trunc(v);
|
|
3424
|
-
}
|
|
3425
|
-
function validateCampaignChildFlows(campaign, issues) {
|
|
3426
|
-
const field = "campaign.child_flows";
|
|
3427
|
-
const raw = campaign.child_flows;
|
|
3428
|
-
if (raw !== void 0 && raw !== null && !Array.isArray(raw)) {
|
|
3429
|
-
issues.error({ field, message: "campaign.child_flows must be a list", code: "invalid_type" });
|
|
3430
|
-
return;
|
|
3431
|
-
}
|
|
3432
|
-
const entries = (Array.isArray(raw) ? raw : []).map((entry, i) => ({ entry, i })).filter(({ entry }) => entry !== null);
|
|
3433
|
-
if (entries.length === 0) {
|
|
3434
|
-
issues.error({
|
|
3435
|
-
field,
|
|
3436
|
-
message: "campaign requires at least one entry in child_flows",
|
|
3437
|
-
code: "campaign_no_child_flows"
|
|
3438
|
-
});
|
|
3439
|
-
return;
|
|
3440
|
-
}
|
|
3441
|
-
for (const { entry, i } of entries) {
|
|
3442
|
-
if (!isRecord(entry)) {
|
|
3443
|
-
issues.error({
|
|
3444
|
-
field: `${field}[${i}]`,
|
|
3445
|
-
message: "each campaign.child_flows entry must be a mapping",
|
|
3446
|
-
code: "invalid_type"
|
|
3447
|
-
});
|
|
3448
|
-
continue;
|
|
3449
|
-
}
|
|
3450
|
-
const id = issues.stringOf(entry, "flow_id", `${field}[${i}]`);
|
|
3451
|
-
const name = issues.stringOf(entry, "flow_name", `${field}[${i}]`);
|
|
3452
|
-
if (id !== null && id !== "" || name !== null && name !== "") continue;
|
|
3453
|
-
issues.error({
|
|
3454
|
-
field: `${field}[${i}]`,
|
|
3455
|
-
message: `campaign.child_flows[${i}] needs a flow_id or a flow_name`,
|
|
3456
|
-
code: "campaign_child_flow_no_id",
|
|
3457
|
-
suggestion: "Name the child flow with flow_name, or pin it with flow_id"
|
|
3458
|
-
});
|
|
3459
|
-
}
|
|
3460
|
-
}
|
|
3461
3773
|
function validateOrchestratorCampaign(flow, issues, opts) {
|
|
3462
3774
|
const hasOrchestrator = isRecord(flow.orchestrator);
|
|
3463
3775
|
if (hasOrchestrator) {
|
|
@@ -3513,6 +3825,7 @@ function validateOrchestratorCampaign(flow, issues, opts) {
|
|
|
3513
3825
|
const trigger = rawTrigger;
|
|
3514
3826
|
const base = `orchestrator.triggers[${i}]`;
|
|
3515
3827
|
const type = issues.stringOf(trigger, "type", base);
|
|
3828
|
+
if (type !== null && REMOVED_ORCHESTRATOR_TRIGGERS.has(type)) return;
|
|
3516
3829
|
if (type === null || !ORCHESTRATOR_TRIGGERS.has(type)) {
|
|
3517
3830
|
issues.error({
|
|
3518
3831
|
field: `${base}.type`,
|
|
@@ -3543,66 +3856,27 @@ function validateOrchestratorCampaign(flow, issues, opts) {
|
|
|
3543
3856
|
if (Array.isArray(orch.tools)) {
|
|
3544
3857
|
orch.tools.forEach((raw, i) => {
|
|
3545
3858
|
const tool = issues.stringAt(raw, `orchestrator.tools[${i}]`);
|
|
3546
|
-
if (tool === null || ORCHESTRATOR_TOOLS.has(tool))
|
|
3859
|
+
if (tool === null || ORCHESTRATOR_TOOLS.has(tool) || REMOVED_ORCHESTRATOR_TOOLS.has(tool)) {
|
|
3860
|
+
return;
|
|
3861
|
+
}
|
|
3547
3862
|
const finding = {
|
|
3548
3863
|
field: `orchestrator.tools[${i}]`,
|
|
3549
3864
|
message: `Unrecognised orchestrator tool name '${tool}'`,
|
|
3550
3865
|
code: "orchestrator_tool_unknown"
|
|
3551
3866
|
};
|
|
3552
3867
|
if (opts.strictRegistries) {
|
|
3553
|
-
issues.error(finding);
|
|
3554
|
-
} else {
|
|
3555
|
-
issues.warn(finding);
|
|
3556
|
-
}
|
|
3557
|
-
});
|
|
3558
|
-
}
|
|
3559
|
-
if (orch.agentic === false) {
|
|
3560
|
-
issues.warn({
|
|
3561
|
-
field: "orchestrator.agentic",
|
|
3562
|
-
message: "orchestrator is most useful with agentic: true",
|
|
3563
|
-
code: "orchestrator_not_agentic"
|
|
3564
|
-
});
|
|
3565
|
-
}
|
|
3566
|
-
}
|
|
3567
|
-
if (flow.campaign !== void 0 && flow.campaign !== null) {
|
|
3568
|
-
if (!hasOrchestrator) {
|
|
3569
|
-
issues.error({
|
|
3570
|
-
field: "campaign",
|
|
3571
|
-
message: "campaign requires an orchestrator block",
|
|
3572
|
-
code: "campaign_requires_orchestrator"
|
|
3573
|
-
});
|
|
3574
|
-
}
|
|
3575
|
-
const campaign = flow.campaign;
|
|
3576
|
-
if (isRecord(campaign)) {
|
|
3577
|
-
const cap = campaign.max_credits_per_child;
|
|
3578
|
-
if (cap !== void 0 && cap !== null) {
|
|
3579
|
-
const decoded = decodeGoInt(cap);
|
|
3580
|
-
if (decoded === null) {
|
|
3581
|
-
issues.error({
|
|
3582
|
-
field: "campaign.max_credits_per_child",
|
|
3583
|
-
message: `campaign.max_credits_per_child must be a number of credits, got '${String(cap)}'`,
|
|
3584
|
-
code: "invalid_type"
|
|
3585
|
-
});
|
|
3586
|
-
} else if (decoded < 0) {
|
|
3587
|
-
issues.error({
|
|
3588
|
-
field: "campaign.max_credits_per_child",
|
|
3589
|
-
message: "campaign: max_credits_per_child must be >= 0",
|
|
3590
|
-
code: "campaign_invalid_max_credits_per_child"
|
|
3591
|
-
});
|
|
3868
|
+
issues.error(finding);
|
|
3869
|
+
} else {
|
|
3870
|
+
issues.warn(finding);
|
|
3592
3871
|
}
|
|
3593
|
-
}
|
|
3594
|
-
validateCampaignChildFlows(campaign, issues);
|
|
3872
|
+
});
|
|
3595
3873
|
}
|
|
3596
|
-
|
|
3597
|
-
|
|
3598
|
-
|
|
3599
|
-
|
|
3600
|
-
|
|
3601
|
-
|
|
3602
|
-
message: `campaign.on_children_complete references unknown step '${target}'`,
|
|
3603
|
-
code: "campaign_handoff_step_unknown"
|
|
3604
|
-
});
|
|
3605
|
-
}
|
|
3874
|
+
if (orch.agentic === false) {
|
|
3875
|
+
issues.warn({
|
|
3876
|
+
field: "orchestrator.agentic",
|
|
3877
|
+
message: "orchestrator is most useful with agentic: true",
|
|
3878
|
+
code: "orchestrator_not_agentic"
|
|
3879
|
+
});
|
|
3606
3880
|
}
|
|
3607
3881
|
}
|
|
3608
3882
|
}
|
|
@@ -4730,10 +5004,6 @@ var CODE_UNKNOWN_YAML_KEY = "unknown_yaml_key";
|
|
|
4730
5004
|
var KEY_BUDGET = "budget";
|
|
4731
5005
|
var KEY_MAX_RETRIES = "max_retries";
|
|
4732
5006
|
var REMOVED_IN = "v2.721.0";
|
|
4733
|
-
var KEY_BUDGET_MAX_PER_CHILD = "budget_max_per_child";
|
|
4734
|
-
var BUDGET_MAX_PER_CHILD_REMOVED_IN = "v2.728.0";
|
|
4735
|
-
var BUDGET_MAX_PER_CHILD_MESSAGE = `\`campaign.budget_max_per_child\` (USD) was removed from the grammar in AIgentFlow ${BUDGET_MAX_PER_CHILD_REMOVED_IN} because it capped nothing, and AIgentFlow refuses to save a flow that declares it.`;
|
|
4736
|
-
var BUDGET_MAX_PER_CHILD_SUGGESTION = "Use `campaign.max_credits_per_child: N` (a whole number of credits) \u2014 it is checked before each agentic turn of a child, and a spawn may lower it with `max_credits`.";
|
|
4737
5007
|
var BUDGET_MESSAGE = `The flow-level \`budget:\` key was removed from the grammar in AIgentFlow ${REMOVED_IN} because nothing read it (it limited no spend), and AIgentFlow refuses to save a flow that declares it.`;
|
|
4738
5008
|
var BUDGET_SUGGESTION = "Delete it. To cap spend use `billing: { max_credits: N }` \u2014 it caps the credit reservation and refuses further agentic turns (agentic ai://, exons://, the orchestrator); plain chat steps and flow:// sub-flows are not checked against it.";
|
|
4739
5009
|
function maxRetriesMessage(owner) {
|
|
@@ -4761,15 +5031,6 @@ function validateRetiredKeys(flow, issues) {
|
|
|
4761
5031
|
suggestion: MAX_RETRIES_SUGGESTION
|
|
4762
5032
|
});
|
|
4763
5033
|
}
|
|
4764
|
-
const campaign = root.campaign;
|
|
4765
|
-
if (isRecord(campaign) && declares(campaign, KEY_BUDGET_MAX_PER_CHILD)) {
|
|
4766
|
-
issues.error({
|
|
4767
|
-
field: `campaign.${KEY_BUDGET_MAX_PER_CHILD}`,
|
|
4768
|
-
message: BUDGET_MAX_PER_CHILD_MESSAGE,
|
|
4769
|
-
code: CODE_UNKNOWN_YAML_KEY,
|
|
4770
|
-
suggestion: BUDGET_MAX_PER_CHILD_SUGGESTION
|
|
4771
|
-
});
|
|
4772
|
-
}
|
|
4773
5034
|
const steps = flow.steps;
|
|
4774
5035
|
if (!isRecord(steps)) return;
|
|
4775
5036
|
for (const [stepID, rawStep] of Object.entries(steps)) {
|
|
@@ -5137,9 +5398,9 @@ function refuse(issues, stepId, key, field) {
|
|
|
5137
5398
|
}
|
|
5138
5399
|
|
|
5139
5400
|
// src/validators/goUrl.ts
|
|
5140
|
-
var
|
|
5141
|
-
var GO_TRIM_SPACE_RE = new RegExp(`^[${
|
|
5142
|
-
function
|
|
5401
|
+
var GO_SPACE2 = "\\t\\n\\v\\f\\r \\u0085\\u00A0\\u1680\\u2000-\\u200A\\u2028\\u2029\\u202F\\u205F\\u3000";
|
|
5402
|
+
var GO_TRIM_SPACE_RE = new RegExp(`^[${GO_SPACE2}]+|[${GO_SPACE2}]+$`, "g");
|
|
5403
|
+
function goTrimSpace2(s) {
|
|
5143
5404
|
return s.replace(GO_TRIM_SPACE_RE, "");
|
|
5144
5405
|
}
|
|
5145
5406
|
function goToLower(s) {
|
|
@@ -5360,7 +5621,7 @@ function goQueryKeys(rawQuery) {
|
|
|
5360
5621
|
return keys;
|
|
5361
5622
|
}
|
|
5362
5623
|
function goEndpointOrigin(raw, defaultPorts, protocolSeparator) {
|
|
5363
|
-
const trimmed =
|
|
5624
|
+
const trimmed = goTrimSpace2(raw);
|
|
5364
5625
|
const u = goParseSchemeHost(trimmed);
|
|
5365
5626
|
if (u === null || u.scheme === "" || u.host === "") {
|
|
5366
5627
|
return goToLower(trimmed.replace(/\/+$/, ""));
|
|
@@ -5594,225 +5855,165 @@ function validateFamilies(flow, steps, issues) {
|
|
|
5594
5855
|
});
|
|
5595
5856
|
}
|
|
5596
5857
|
}
|
|
5597
|
-
|
|
5598
|
-
|
|
5599
|
-
var
|
|
5600
|
-
|
|
5601
|
-
|
|
5602
|
-
|
|
5603
|
-
var UTF8_BOM = "\uFEFF";
|
|
5604
|
-
var MAX_ALIAS_COUNT2 = 100;
|
|
5605
|
-
var UNREAD = {
|
|
5606
|
-
parseError: null,
|
|
5607
|
-
specRead: false,
|
|
5608
|
-
hasSpec: false,
|
|
5609
|
-
provider: "",
|
|
5610
|
-
toolsAllowDeclared: false,
|
|
5611
|
-
toolsAllow: [],
|
|
5612
|
-
resources: []
|
|
5613
|
-
};
|
|
5614
|
-
var GO_SPACE2 = "\\t\\n\\v\\f\\r \\u0085\\u00a0\\u1680\\u2000-\\u200a\\u2028\\u2029\\u202f\\u205f\\u3000";
|
|
5615
|
-
var GO_TRIM_SPACE = new RegExp(`^[${GO_SPACE2}]+|[${GO_SPACE2}]+$`, "g");
|
|
5616
|
-
function goTrimSpace2(s) {
|
|
5617
|
-
return s.replace(GO_TRIM_SPACE, "");
|
|
5858
|
+
|
|
5859
|
+
// src/validators/removedSignalCampaign.ts
|
|
5860
|
+
var TEMPLATE_ACTION_OPEN3 = "{{";
|
|
5861
|
+
function fill(format, ...args) {
|
|
5862
|
+
let i = 0;
|
|
5863
|
+
return format.replace(/%[qs]/g, () => args[i++] ?? "");
|
|
5618
5864
|
}
|
|
5619
|
-
function
|
|
5620
|
-
const
|
|
5621
|
-
|
|
5622
|
-
start = start.replace(/^[ \t]+/, "");
|
|
5623
|
-
if (start.startsWith(EXONS_LEGACY_CONFIG_OPEN)) {
|
|
5624
|
-
return {
|
|
5625
|
-
frontmatter: "",
|
|
5626
|
-
hasFrontmatter: false,
|
|
5627
|
-
parseError: "legacy JSON config block detected; use YAML frontmatter"
|
|
5628
|
-
};
|
|
5629
|
-
}
|
|
5630
|
-
if (!start.startsWith(delim)) return { frontmatter: "", hasFrontmatter: false, parseError: null };
|
|
5631
|
-
let rest = start.slice(delim.length);
|
|
5632
|
-
if (rest.startsWith("\n")) rest = rest.slice(1);
|
|
5633
|
-
else if (rest.startsWith("\r\n")) rest = rest.slice(2);
|
|
5634
|
-
else return { frontmatter: "", hasFrontmatter: false, parseError: null };
|
|
5635
|
-
let pos = 0;
|
|
5636
|
-
while (pos <= rest.length) {
|
|
5637
|
-
const line = rest.slice(pos);
|
|
5638
|
-
if (line.startsWith(delim)) {
|
|
5639
|
-
const after = line.slice(delim.length);
|
|
5640
|
-
if (after === "" || after[0] === "\n" || after[0] === "\r") {
|
|
5641
|
-
return {
|
|
5642
|
-
frontmatter: goTrimSpace2(rest.slice(0, pos)),
|
|
5643
|
-
hasFrontmatter: true,
|
|
5644
|
-
parseError: null
|
|
5645
|
-
};
|
|
5646
|
-
}
|
|
5647
|
-
}
|
|
5648
|
-
const nl = line.indexOf("\n");
|
|
5649
|
-
if (nl < 0) break;
|
|
5650
|
-
pos += nl + 1;
|
|
5651
|
-
}
|
|
5652
|
-
return {
|
|
5653
|
-
frontmatter: "",
|
|
5654
|
-
hasFrontmatter: true,
|
|
5655
|
-
parseError: "YAML frontmatter not properly closed"
|
|
5656
|
-
};
|
|
5865
|
+
function stringEntries(m, key) {
|
|
5866
|
+
const raw = m[key];
|
|
5867
|
+
return Array.isArray(raw) ? raw.filter((v) => typeof v === "string") : [];
|
|
5657
5868
|
}
|
|
5658
|
-
function
|
|
5659
|
-
|
|
5660
|
-
|
|
5661
|
-
|
|
5662
|
-
|
|
5663
|
-
|
|
5664
|
-
} else if (isSeq(node)) {
|
|
5665
|
-
for (const item of node.items) retagScalars(item);
|
|
5666
|
-
} else if (isScalar(node) && (typeof node.value === "number" || typeof node.value === "boolean") && typeof node.source === "string") {
|
|
5667
|
-
node.value = node.source;
|
|
5869
|
+
function triggerTypes(orch) {
|
|
5870
|
+
const raw = orch.triggers;
|
|
5871
|
+
if (!Array.isArray(raw)) return [];
|
|
5872
|
+
const out = [];
|
|
5873
|
+
for (const t of raw) {
|
|
5874
|
+
if (isRecord(t) && typeof t.type === "string") out.push(t.type);
|
|
5668
5875
|
}
|
|
5876
|
+
return out;
|
|
5669
5877
|
}
|
|
5670
|
-
|
|
5671
|
-
|
|
5672
|
-
|
|
5673
|
-
|
|
5674
|
-
if (isString(v)) return v;
|
|
5675
|
-
throw new DecodeError("not a string");
|
|
5676
|
-
}
|
|
5677
|
-
function goStringList(v) {
|
|
5678
|
-
if (v === null || v === void 0) return null;
|
|
5679
|
-
if (!isArray(v)) throw new DecodeError("not a list");
|
|
5680
|
-
return v.filter((item) => item !== null).map(goString);
|
|
5681
|
-
}
|
|
5682
|
-
function goStruct(v) {
|
|
5683
|
-
if (v === null || v === void 0) return null;
|
|
5684
|
-
if (!isRecord(v)) throw new DecodeError("not a mapping");
|
|
5685
|
-
return v;
|
|
5686
|
-
}
|
|
5687
|
-
function decodeSpecFields(frontmatter) {
|
|
5688
|
-
let value;
|
|
5689
|
-
try {
|
|
5690
|
-
const docs = parseAllDocuments(frontmatter, { merge: true });
|
|
5691
|
-
const doc = Array.isArray(docs) ? docs[0] : void 0;
|
|
5692
|
-
if (doc === void 0) {
|
|
5693
|
-
value = null;
|
|
5694
|
-
} else {
|
|
5695
|
-
if (doc.errors.length > 0) return null;
|
|
5696
|
-
retagScalars(doc.contents);
|
|
5697
|
-
value = doc.toJS({ maxAliasCount: MAX_ALIAS_COUNT2 });
|
|
5698
|
-
}
|
|
5699
|
-
} catch {
|
|
5700
|
-
return null;
|
|
5701
|
-
}
|
|
5702
|
-
try {
|
|
5703
|
-
const root = goStruct(value) ?? {};
|
|
5704
|
-
const execution = goStruct(root.execution);
|
|
5705
|
-
const tools = goStruct(root.tools);
|
|
5706
|
-
const requirements = goStruct(root.requirements);
|
|
5707
|
-
const allow = tools === null ? null : goStringList(tools.allow);
|
|
5708
|
-
let resources = [];
|
|
5709
|
-
if (requirements !== null) {
|
|
5710
|
-
const raw = requirements.resources;
|
|
5711
|
-
if (raw !== null && raw !== void 0) {
|
|
5712
|
-
if (!isArray(raw)) throw new DecodeError("not a list");
|
|
5713
|
-
resources = raw.filter((entry) => entry !== null).map((entry) => {
|
|
5714
|
-
const r = goStruct(entry) ?? {};
|
|
5715
|
-
return { ref: goString(r.ref), kind: goString(r.kind), scope: goString(r.scope) };
|
|
5716
|
-
});
|
|
5717
|
-
}
|
|
5718
|
-
}
|
|
5719
|
-
return {
|
|
5720
|
-
provider: execution === null ? "" : goString(execution.provider),
|
|
5721
|
-
toolsAllowDeclared: allow !== null,
|
|
5722
|
-
toolsAllow: allow ?? [],
|
|
5723
|
-
resources
|
|
5724
|
-
};
|
|
5725
|
-
} catch (e) {
|
|
5726
|
-
if (e instanceof DecodeError) return null;
|
|
5727
|
-
throw e;
|
|
5878
|
+
function namesIn(names, removed2) {
|
|
5879
|
+
const found = [];
|
|
5880
|
+
for (const name of names) {
|
|
5881
|
+
if (removed2.includes(name) && !found.includes(name)) found.push(name);
|
|
5728
5882
|
}
|
|
5883
|
+
return found;
|
|
5729
5884
|
}
|
|
5730
|
-
function
|
|
5731
|
-
const
|
|
5732
|
-
if (
|
|
5733
|
-
if (!fm.hasFrontmatter || fm.frontmatter === "") return { ...UNREAD, specRead: true };
|
|
5734
|
-
if (fm.frontmatter.includes(EXONS_OPEN_DELIM)) return { ...UNREAD };
|
|
5735
|
-
const fields = decodeSpecFields(fm.frontmatter);
|
|
5736
|
-
if (fields === null) return { ...UNREAD };
|
|
5737
|
-
return { parseError: null, specRead: true, hasSpec: true, ...fields };
|
|
5738
|
-
}
|
|
5739
|
-
function validateOrchestratorExons(flow, issues) {
|
|
5740
|
-
const orch = flow.orchestrator;
|
|
5741
|
-
if (!isRecord(orch)) return;
|
|
5742
|
-
const source = issues.stringOf(orch, "exons", "orchestrator");
|
|
5743
|
-
if (source === null || source === "") return;
|
|
5744
|
-
const field = "orchestrator.exons";
|
|
5885
|
+
function orchestratorToolsAllow(orch) {
|
|
5886
|
+
const source = orch.exons;
|
|
5887
|
+
if (typeof source !== "string" || source === "") return [];
|
|
5745
5888
|
const report = inspectExonsFrontmatter(source);
|
|
5746
|
-
if (report.parseError !== null)
|
|
5747
|
-
|
|
5748
|
-
|
|
5749
|
-
|
|
5750
|
-
|
|
5751
|
-
|
|
5752
|
-
|
|
5753
|
-
|
|
5754
|
-
|
|
5755
|
-
|
|
5756
|
-
|
|
5757
|
-
|
|
5758
|
-
|
|
5759
|
-
|
|
5760
|
-
|
|
5761
|
-
|
|
5762
|
-
|
|
5763
|
-
|
|
5764
|
-
|
|
5765
|
-
|
|
5766
|
-
|
|
5767
|
-
|
|
5768
|
-
|
|
5769
|
-
|
|
5889
|
+
if (report.parseError !== null || !report.specRead || !report.toolsAllowDeclared) return [];
|
|
5890
|
+
return [...report.toolsAllow];
|
|
5891
|
+
}
|
|
5892
|
+
function validateRemovedOrchestratorSurfaces(flow, issues) {
|
|
5893
|
+
const sig = REMOVED_SIGNAL_SURFACES;
|
|
5894
|
+
const camp = REMOVED_CAMPAIGN_SURFACES;
|
|
5895
|
+
const orch = isRecord(flow.orchestrator) ? flow.orchestrator : null;
|
|
5896
|
+
const lists = orch === null ? [] : [
|
|
5897
|
+
...["tools", "deny_tools", "require_approval_for"].map((key) => ({
|
|
5898
|
+
field: `orchestrator.${key}`,
|
|
5899
|
+
names: stringEntries(orch, key)
|
|
5900
|
+
})),
|
|
5901
|
+
{ field: "orchestrator.exons", names: orchestratorToolsAllow(orch) }
|
|
5902
|
+
];
|
|
5903
|
+
if (orch !== null) {
|
|
5904
|
+
if (orch.enable_signals === true) {
|
|
5905
|
+
issues.error({
|
|
5906
|
+
field: "orchestrator.enable_signals",
|
|
5907
|
+
code: sig.signalRemovedCode,
|
|
5908
|
+
message: sig.enableSignalsMessage,
|
|
5909
|
+
suggestion: sig.suggestion
|
|
5910
|
+
});
|
|
5911
|
+
}
|
|
5912
|
+
for (const list of lists) {
|
|
5913
|
+
const named = namesIn(list.names, sig.tools);
|
|
5914
|
+
if (named.length === 0) continue;
|
|
5915
|
+
issues.error({
|
|
5916
|
+
field: list.field,
|
|
5917
|
+
code: sig.signalRemovedCode,
|
|
5918
|
+
message: fill(sig.toolNamesMessageFormat, list.field, named.join(", ")),
|
|
5919
|
+
suggestion: sig.suggestion
|
|
5920
|
+
});
|
|
5921
|
+
}
|
|
5922
|
+
if (namesIn(triggerTypes(orch), sig.triggers).length > 0) {
|
|
5923
|
+
issues.error({
|
|
5924
|
+
field: "orchestrator.triggers",
|
|
5925
|
+
code: sig.flowModificationRemovedCode,
|
|
5926
|
+
message: sig.triggersMessage,
|
|
5927
|
+
suggestion: sig.suggestion
|
|
5928
|
+
});
|
|
5929
|
+
}
|
|
5770
5930
|
}
|
|
5771
|
-
|
|
5772
|
-
|
|
5931
|
+
const block = flow[camp.flowKey];
|
|
5932
|
+
if (block !== void 0 && block !== null) {
|
|
5773
5933
|
issues.error({
|
|
5774
|
-
field,
|
|
5775
|
-
code:
|
|
5776
|
-
message:
|
|
5777
|
-
suggestion:
|
|
5778
|
-
});
|
|
5779
|
-
}
|
|
5780
|
-
warnOrchestratorToolWithheld(flow, orch, report, issues);
|
|
5781
|
-
}
|
|
5782
|
-
function warnOrchestratorToolWithheld(flow, orch, report, issues) {
|
|
5783
|
-
if (!report.toolsAllowDeclared) return;
|
|
5784
|
-
const cfg = ORCHESTRATOR_TOOL_ALLOW;
|
|
5785
|
-
const exempt = new Set(cfg.lifecycleTools);
|
|
5786
|
-
const signals = typeof orch.enable_signals === "boolean" ? orch.enable_signals : cfg.enableSignalsDefault;
|
|
5787
|
-
if (signals) for (const t of cfg.signalTools) exempt.add(t);
|
|
5788
|
-
const allow = new Set(report.toolsAllow);
|
|
5789
|
-
const withheld = (name) => !allow.has(name) && !exempt.has(name);
|
|
5790
|
-
const warn = (message) => issues.warn({ field: cfg.warningField, code: CODE_TOOL_WITHHELD, message });
|
|
5791
|
-
const named = [];
|
|
5792
|
-
if (isArray(orch.tools)) {
|
|
5793
|
-
orch.tools.forEach((raw, i) => {
|
|
5794
|
-
const name = issues.stringAt(raw, `orchestrator.tools[${i}]`);
|
|
5795
|
-
if (name !== null) named.push(name);
|
|
5934
|
+
field: camp.flowKey,
|
|
5935
|
+
code: camp.code,
|
|
5936
|
+
message: camp.blockMessage,
|
|
5937
|
+
suggestion: camp.suggestion
|
|
5796
5938
|
});
|
|
5797
5939
|
}
|
|
5798
|
-
if (
|
|
5799
|
-
for (const
|
|
5800
|
-
|
|
5801
|
-
|
|
5802
|
-
|
|
5803
|
-
|
|
5940
|
+
if (orch !== null) {
|
|
5941
|
+
for (const list of lists) {
|
|
5942
|
+
const named = namesIn(list.names, camp.tools);
|
|
5943
|
+
if (named.length === 0) continue;
|
|
5944
|
+
issues.error({
|
|
5945
|
+
field: list.field,
|
|
5946
|
+
code: camp.code,
|
|
5947
|
+
message: fill(camp.toolNamesMessageFormat, list.field, named.join(", ")),
|
|
5948
|
+
suggestion: camp.suggestion
|
|
5949
|
+
});
|
|
5950
|
+
}
|
|
5951
|
+
const triggers = namesIn(triggerTypes(orch), camp.triggers);
|
|
5952
|
+
if (triggers.length > 0) {
|
|
5953
|
+
issues.error({
|
|
5954
|
+
field: "orchestrator.triggers",
|
|
5955
|
+
code: camp.code,
|
|
5956
|
+
message: fill(camp.triggersMessageFormat, triggers.join(", ")),
|
|
5957
|
+
suggestion: camp.suggestion
|
|
5958
|
+
});
|
|
5804
5959
|
}
|
|
5805
|
-
return;
|
|
5806
5960
|
}
|
|
5807
|
-
|
|
5808
|
-
|
|
5809
|
-
|
|
5810
|
-
);
|
|
5961
|
+
const judgeStep = (executor, query, field, stepID) => {
|
|
5962
|
+
if (typeof executor !== "string" || executor === "") return;
|
|
5963
|
+
if (executor.includes(TEMPLATE_ACTION_OPEN3)) return;
|
|
5964
|
+
const scheme = removedExecutorScheme(executor);
|
|
5965
|
+
if (REMOVED_AGENT_SURFACES.schemes.has(scheme) || sig.stepSkipSchemes.has(scheme)) return;
|
|
5966
|
+
if (!isRecord(query)) return;
|
|
5967
|
+
const quoted = JSON.stringify(stepID);
|
|
5968
|
+
if (Object.prototype.hasOwnProperty.call(query, sig.flowModificationStepKey)) {
|
|
5969
|
+
issues.error({
|
|
5970
|
+
field,
|
|
5971
|
+
code: sig.flowModificationRemovedCode,
|
|
5972
|
+
stepId: stepID,
|
|
5973
|
+
message: fill(sig.flowModificationStepMessageFormat, quoted),
|
|
5974
|
+
suggestion: sig.suggestion
|
|
5975
|
+
});
|
|
5976
|
+
}
|
|
5977
|
+
if (scheme === sig.stepKeyScheme && Object.prototype.hasOwnProperty.call(query, sig.stepKey)) {
|
|
5978
|
+
issues.error({
|
|
5979
|
+
field,
|
|
5980
|
+
code: sig.signalRemovedCode,
|
|
5981
|
+
stepId: stepID,
|
|
5982
|
+
message: fill(sig.stepKeyMessageFormat, quoted),
|
|
5983
|
+
suggestion: sig.suggestion
|
|
5984
|
+
});
|
|
5985
|
+
}
|
|
5986
|
+
};
|
|
5987
|
+
const steps = flow.steps;
|
|
5988
|
+
if (isRecord(steps)) {
|
|
5989
|
+
for (const stepID of Object.keys(steps).sort()) {
|
|
5990
|
+
const step = steps[stepID];
|
|
5991
|
+
if (!isRecord(step)) continue;
|
|
5992
|
+
judgeStep(step.executor, step.query, `steps.${stepID}`, stepID);
|
|
5993
|
+
const loop = step.loop;
|
|
5994
|
+
if (!isRecord(loop) || !Array.isArray(loop.steps)) continue;
|
|
5995
|
+
loop.steps.forEach((sub, i) => {
|
|
5996
|
+
if (!isRecord(sub)) return;
|
|
5997
|
+
const subID = issues.stringOf(sub, "id", `steps.${stepID}.loop.steps[${i}]`) ?? String(i);
|
|
5998
|
+
judgeStep(
|
|
5999
|
+
sub.executor,
|
|
6000
|
+
sub.query,
|
|
6001
|
+
`steps.${stepID}.loop.steps[${i}]`,
|
|
6002
|
+
`${stepID}.${subID}`
|
|
6003
|
+
);
|
|
6004
|
+
});
|
|
6005
|
+
}
|
|
5811
6006
|
}
|
|
5812
|
-
|
|
5813
|
-
|
|
5814
|
-
|
|
5815
|
-
)
|
|
6007
|
+
const ignored = (field) => issues.warn({
|
|
6008
|
+
field,
|
|
6009
|
+
code: sig.removedKeyIgnoredCode,
|
|
6010
|
+
message: fill(sig.ignoredKeyMessageFormat, field),
|
|
6011
|
+
suggestion: sig.ignoredKeySuggestion
|
|
6012
|
+
});
|
|
6013
|
+
if (orch !== null && orch.enable_signals === false) ignored("orchestrator.enable_signals");
|
|
6014
|
+
const checkpoint = flow.checkpoint;
|
|
6015
|
+
if (isRecord(checkpoint) && checkpoint.pre_dfm !== void 0 && checkpoint.pre_dfm !== null) {
|
|
6016
|
+
ignored("checkpoint.pre_dfm");
|
|
5816
6017
|
}
|
|
5817
6018
|
}
|
|
5818
6019
|
|
|
@@ -5829,7 +6030,7 @@ function sprintf(format, ...args) {
|
|
|
5829
6030
|
});
|
|
5830
6031
|
}
|
|
5831
6032
|
function literalOrEmpty(s) {
|
|
5832
|
-
const t =
|
|
6033
|
+
const t = goTrimSpace(s);
|
|
5833
6034
|
return t.includes(TEMPLATE_ACTION_OPEN) ? "" : t;
|
|
5834
6035
|
}
|
|
5835
6036
|
function euOnlyResidency(flow, issues) {
|
|
@@ -5844,7 +6045,7 @@ function euOnlyResidency(flow, issues) {
|
|
|
5844
6045
|
}
|
|
5845
6046
|
if (codes.length === 0) return null;
|
|
5846
6047
|
const eu = new Set(COMPLIANCE_RESIDENCY.euResidencyCodes);
|
|
5847
|
-
return codes.every((c) => eu.has(
|
|
6048
|
+
return codes.every((c) => eu.has(goTrimSpace(c).toUpperCase())) ? codes : null;
|
|
5848
6049
|
}
|
|
5849
6050
|
function aiProvider(executor) {
|
|
5850
6051
|
const prefix = COMPLIANCE_RESIDENCY.aiProtocol + COMPLIANCE_RESIDENCY.protocolSeparator;
|
|
@@ -5860,7 +6061,7 @@ function isRegionLane(provider) {
|
|
|
5860
6061
|
}
|
|
5861
6062
|
function nonBlankString(m, key) {
|
|
5862
6063
|
const v = own2(m, key);
|
|
5863
|
-
return typeof v === "string" &&
|
|
6064
|
+
return typeof v === "string" && goTrimSpace(v) !== "";
|
|
5864
6065
|
}
|
|
5865
6066
|
function queryEnforcesRegion(query) {
|
|
5866
6067
|
const v = own2(query, COMPLIANCE_RESIDENCY.enforceRegionParam);
|
|
@@ -5872,7 +6073,7 @@ function flowDirectsEndpoint(flow, provider, issues) {
|
|
|
5872
6073
|
const inst = own2(own2(flow, "executor_config"), key);
|
|
5873
6074
|
if (!isRecord(inst)) return false;
|
|
5874
6075
|
const baseUrl = issues.stringOf(inst, "base_url", `executor_config.${key}`);
|
|
5875
|
-
return baseUrl !== null &&
|
|
6076
|
+
return baseUrl !== null && goTrimSpace(baseUrl) !== "";
|
|
5876
6077
|
}
|
|
5877
6078
|
function callPinsEndpoint(flow, provider, query, issues) {
|
|
5878
6079
|
if (nonBlankString(query, COMPLIANCE_RESIDENCY.regionParam)) return true;
|
|
@@ -5945,7 +6146,7 @@ function warnOrchestrator(flow, issues, warn) {
|
|
|
5945
6146
|
const provider = literalOrEmpty(report.provider);
|
|
5946
6147
|
if (!isRegionLane(provider)) return;
|
|
5947
6148
|
const region = issues.stringOf(orch, "region", "orchestrator");
|
|
5948
|
-
if (region !== null &&
|
|
6149
|
+
if (region !== null && goTrimSpace(region) !== "") return;
|
|
5949
6150
|
if (orch.enforce_region === true) return;
|
|
5950
6151
|
if (flowDirectsEndpoint(flow, provider, issues)) return;
|
|
5951
6152
|
warn(COMPLIANCE_RESIDENCY.siteOrchestrator, COMPLIANCE_RESIDENCY.orchestratorField, void 0, provider);
|
|
@@ -6111,7 +6312,7 @@ function asFileRef(v) {
|
|
|
6111
6312
|
};
|
|
6112
6313
|
}
|
|
6113
6314
|
function isTextualMediaType(mediaType) {
|
|
6114
|
-
const base = goToLower(
|
|
6315
|
+
const base = goToLower(goTrimSpace2((mediaType.split(";")[0] ?? "").toString()));
|
|
6115
6316
|
if (base.startsWith("text/")) return true;
|
|
6116
6317
|
if (base.endsWith("+json") || base.endsWith("+xml")) return true;
|
|
6117
6318
|
return TEXTUAL_MEDIA_BASES.has(base);
|
|
@@ -6215,7 +6416,7 @@ var Walker = class _Walker {
|
|
|
6215
6416
|
}
|
|
6216
6417
|
}
|
|
6217
6418
|
const title = this.s(ex, "title", path);
|
|
6218
|
-
if (
|
|
6419
|
+
if (goTrimSpace2(title) === "") {
|
|
6219
6420
|
this.err(
|
|
6220
6421
|
"example_title_missing",
|
|
6221
6422
|
`${path}.title`,
|
|
@@ -6232,7 +6433,7 @@ var Walker = class _Walker {
|
|
|
6232
6433
|
}
|
|
6233
6434
|
}
|
|
6234
6435
|
const guidance = this.s(ex, "guidance", path);
|
|
6235
|
-
if (
|
|
6436
|
+
if (goTrimSpace2(guidance) === "") {
|
|
6236
6437
|
this.warn(
|
|
6237
6438
|
"example_guidance_missing",
|
|
6238
6439
|
`${path}.guidance`,
|
|
@@ -6659,7 +6860,7 @@ var Walker = class _Walker {
|
|
|
6659
6860
|
}
|
|
6660
6861
|
const rubric = this.s(e, "rubric", path);
|
|
6661
6862
|
if (rubric !== "") {
|
|
6662
|
-
if (
|
|
6863
|
+
if (goTrimSpace2(rubric) === "") {
|
|
6663
6864
|
this.err(
|
|
6664
6865
|
"example_rubric_empty",
|
|
6665
6866
|
`${path}.rubric`,
|
|
@@ -6714,7 +6915,7 @@ var Walker = class _Walker {
|
|
|
6714
6915
|
this.err("example_must_not_invalid", `${path}.must_not`, mustNotMsg);
|
|
6715
6916
|
}
|
|
6716
6917
|
mustNot.forEach((item, j) => {
|
|
6717
|
-
if (
|
|
6918
|
+
if (goTrimSpace2(item) === "" || runeCount(item) > L.maxMustNotRunes) {
|
|
6718
6919
|
this.err("example_must_not_invalid", `${path}.must_not[${j}]`, mustNotMsg);
|
|
6719
6920
|
}
|
|
6720
6921
|
});
|
|
@@ -7272,6 +7473,7 @@ function validateParsed(flow, opts, sources) {
|
|
|
7272
7473
|
const f = flow;
|
|
7273
7474
|
validateBasicStructure(f, issues);
|
|
7274
7475
|
validateRetiredKeys(f, issues);
|
|
7476
|
+
validateRemovedFlowKeys(f, issues);
|
|
7275
7477
|
validateExecutors(f, issues);
|
|
7276
7478
|
validateQuerySchema(f, issues);
|
|
7277
7479
|
validateResponseExpectations(f, issues);
|
|
@@ -7295,6 +7497,7 @@ function validateParsed(flow, opts, sources) {
|
|
|
7295
7497
|
validateCredentialEndpointPairing(f, issues);
|
|
7296
7498
|
validateExamples(f, issues);
|
|
7297
7499
|
validateOrchestratorExons(f, issues);
|
|
7500
|
+
validateRemovedOrchestratorSurfaces(f, issues);
|
|
7298
7501
|
validateResidencyEnforcement(f, issues);
|
|
7299
7502
|
validateUnknownKeys(f, issues);
|
|
7300
7503
|
const templateStats = validateTemplates(f, issues, opts);
|