@vaudience/aigentflow-flow-validator 0.27.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/dist/index.cjs CHANGED
@@ -451,7 +451,7 @@ function validateBasicStructure(flow, issues) {
451
451
 
452
452
  // src/spec/aigentflow-spec.json
453
453
  var aigentflow_spec_default = {
454
- specVersion: "2.833.0",
454
+ specVersion: "2.837.0",
455
455
  inputSchemaVersion: 1,
456
456
  executorSchemes: [
457
457
  "a2a",
@@ -482,6 +482,7 @@ var aigentflow_spec_default = {
482
482
  "messenger",
483
483
  "mock",
484
484
  "mqtt",
485
+ "nexus",
485
486
  "opencorporates",
486
487
  "openmeteo",
487
488
  "overpass",
@@ -546,12 +547,9 @@ var aigentflow_spec_default = {
546
547
  "step_failed",
547
548
  "mission_started",
548
549
  "mission_completed",
549
- "dfm_suggestion",
550
550
  "timer",
551
551
  "request_turn",
552
552
  "mission_recovered",
553
- "campaign_child_completed",
554
- "campaign_child_failed",
555
553
  "human_response",
556
554
  "human_input"
557
555
  ],
@@ -567,15 +565,6 @@ var aigentflow_spec_default = {
567
565
  "aif_ask_human",
568
566
  "aif_flow_list",
569
567
  "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
568
  "aif_memory_plan",
580
569
  "aif_memory_record",
581
570
  "aif_memory_recall",
@@ -747,20 +736,10 @@ var aigentflow_spec_default = {
747
736
  orchestratorToolAllow: {
748
737
  warningField: "orchestrator.exons",
749
738
  askHumanTool: "aif_ask_human",
750
- enableSignalsDefault: true,
751
- lifecycleTools: ["aif_mission_complete", "aif_mission_fail", "aif_request_turn"],
752
- signalTools: [
753
- "aif_signal_complete",
754
- "aif_signal_need_human",
755
- "aif_signal_delegate",
756
- "aif_signal_need_tool",
757
- "aif_signal_modify_flow"
758
- ],
759
- campaignTools: [
760
- "aif_campaign_cancel",
761
- "aif_campaign_results",
762
- "aif_campaign_spawn",
763
- "aif_campaign_status"
739
+ lifecycleTools: [
740
+ "aif_mission_complete",
741
+ "aif_mission_fail",
742
+ "aif_request_turn"
764
743
  ]
765
744
  },
766
745
  exons: {
@@ -790,7 +769,54 @@ var aigentflow_spec_default = {
790
769
  schemeMessageFormat: "step %q uses %s://, which AIgentFlow no longer runs: its own agent chains were removed",
791
770
  paramsMessageFormat: "step %q sets %s on ai://: AIgentFlow's own agent loop (agentic mode) was removed, so these parameters no longer exist",
792
771
  flowKeyMessageFormat: "the flow-level key %q belonged to a removed agent surface and is no longer read",
793
- suggestion: 'Rebuild the step: a tool-using agent becomes atlas://agent/run (agent: "@org/name", prompt, capabilities); one tool becomes atlas://capability/<ref>; a plain prompt becomes ai://<provider>/chat or a prompt-only aiv://<org>/<name>. A flow that cannot be converted (started by a webhook, a schedule, a share link, a campaign or a flow:// sub-flow, none of which has a person for atlas to act for; or one that needs an inline .exons spec, an arbitrary MCP server URL or signals) has no replacement here: start it from a person, or use a routine in atlas'
772
+ 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`
773
+ },
774
+ removedSignalSurfaces: {
775
+ signalRemovedCode: "signal_removed",
776
+ flowModificationRemovedCode: "flow_modification_removed",
777
+ removedKeyIgnoredCode: "removed_key_ignored",
778
+ tools: [
779
+ "aif_signal_complete",
780
+ "aif_signal_need_human",
781
+ "aif_signal_delegate",
782
+ "aif_signal_need_tool",
783
+ "aif_signal_modify_flow"
784
+ ],
785
+ triggers: [
786
+ "dfm_suggestion"
787
+ ],
788
+ stepKey: "enable_signals",
789
+ stepKeyScheme: "aiv",
790
+ flowModificationStepKey: "flow_modification_allowed",
791
+ stepSkipSchemes: [
792
+ "flow"
793
+ ],
794
+ 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",
795
+ toolNamesMessageFormat: "%s names %s: AIgentFlow's agent signal tools were removed in 2.834.0",
796
+ stepKeyMessageFormat: "step %q sets enable_signals: AIgentFlow's agent signals were removed in 2.834.0, so the parameter no longer exists",
797
+ triggersMessage: "orchestrator.triggers names dfm_suggestion: dynamic flow modification was removed in 2.834.0, so nothing raises that trigger",
798
+ flowModificationStepMessageFormat: "step %q sets flow_modification_allowed: dynamic flow modification was removed in 2.834.0",
799
+ 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",
800
+ ignoredKeySuggestion: "Remove the key; nothing reads it",
801
+ 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"
802
+ },
803
+ removedCampaignSurfaces: {
804
+ code: "campaign_removed",
805
+ flowKey: "campaign",
806
+ tools: [
807
+ "aif_campaign_spawn",
808
+ "aif_campaign_status",
809
+ "aif_campaign_results",
810
+ "aif_campaign_cancel"
811
+ ],
812
+ triggers: [
813
+ "campaign_child_completed",
814
+ "campaign_child_failed"
815
+ ],
816
+ blockMessage: "the flow declares a campaign: block: campaigns were removed in 2.836.0, so nothing would spawn or track its child missions",
817
+ toolNamesMessageFormat: "%s names %s: AIgentFlow's campaign tools were removed in 2.836.0",
818
+ triggersMessageFormat: "orchestrator.triggers names %s: campaigns were removed in 2.836.0, so no child mission raises that trigger",
819
+ 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"
794
820
  },
795
821
  executorConfigEnvScopes: {
796
822
  referencePrefix: "${",
@@ -1014,19 +1040,20 @@ var aigentflow_spec_default = {
1014
1040
  ]
1015
1041
  },
1016
1042
  atlasExecutor: {
1017
- scheme: "atlas",
1043
+ scheme: "nexus",
1044
+ aliases: ["atlas"],
1018
1045
  providerAgent: "agent",
1019
1046
  providerCapability: "capability",
1020
1047
  agentResource: "run",
1021
1048
  capabilityRefPattern: "^[A-Za-z0-9][A-Za-z0-9_-]{0,127}$",
1022
1049
  operationUnknown: {
1023
1050
  code: "atlas_operation_unknown",
1024
- messageFormat: "step %s uses %s, which is not an Atlas operation. The providers are agent (resource run) and capability (resource: a capability reference).",
1025
- suggestion: "Use atlas://agent/run or atlas://capability/<capability-ref>."
1051
+ messageFormat: "step %s uses %s, which is not a Nexus operation. The providers are agent (resource run) and capability (resource: a capability reference).",
1052
+ suggestion: "Use nexus://agent/run or nexus://capability/<capability-ref>."
1026
1053
  },
1027
1054
  agentMissing: {
1028
1055
  code: "atlas_agent_missing",
1029
- messageFormat: "step %s runs an Atlas agent but query.agent is missing, empty or not a string.",
1056
+ messageFormat: "step %s runs a Nexus agent but query.agent is missing, empty or not a string.",
1030
1057
  suggestion: "Set query.agent to the agent to run, written out as a literal such as @acme/reporter."
1031
1058
  },
1032
1059
  agentNotLiteral: {
@@ -1041,7 +1068,7 @@ var aigentflow_spec_default = {
1041
1068
  },
1042
1069
  promptMissing: {
1043
1070
  code: "atlas_prompt_missing",
1044
- messageFormat: "step %s runs an Atlas agent with neither query.prompt nor query.prompt_template.",
1071
+ messageFormat: "step %s runs a Nexus agent with neither query.prompt nor query.prompt_template.",
1045
1072
  suggestion: "Set exactly one of query.prompt or query.prompt_template."
1046
1073
  },
1047
1074
  promptBoth: {
@@ -1051,7 +1078,7 @@ var aigentflow_spec_default = {
1051
1078
  },
1052
1079
  capabilityRefInvalid: {
1053
1080
  code: "atlas_capability_ref_invalid",
1054
- messageFormat: "step %s uses atlas://capability/%s, which is not a valid capability reference.",
1081
+ messageFormat: "step %s uses nexus://capability/%s, which is not a valid capability reference.",
1055
1082
  suggestion: "A capability reference starts with a letter or digit and continues with letters, digits, _ and - up to 128 characters in all."
1056
1083
  },
1057
1084
  modelNotLiteral: {
@@ -1578,20 +1605,6 @@ var aigentflow_spec_default = {
1578
1605
  BillingConfig: {
1579
1606
  max_credits: "scalar"
1580
1607
  },
1581
- CampaignChildFlowDef: {
1582
- alias: "scalar",
1583
- flow_id: "scalar",
1584
- flow_name: "scalar"
1585
- },
1586
- CampaignConfig: {
1587
- child_flows: "list<CampaignChildFlowDef>",
1588
- max_concurrent: "scalar",
1589
- max_credits_per_child: "scalar",
1590
- max_depth: "scalar",
1591
- max_total_children: "scalar",
1592
- on_children_complete: "scalar",
1593
- shared_memory: "scalar"
1594
- },
1595
1608
  Checkpoint: {
1596
1609
  exact: "map<any>",
1597
1610
  fields: "map<FieldMatcher>",
@@ -1725,7 +1738,7 @@ var aigentflow_spec_default = {
1725
1738
  Flow: {
1726
1739
  aigentflow_version: "scalar",
1727
1740
  billing: "BillingConfig",
1728
- campaign: "CampaignConfig",
1741
+ campaign: "any",
1729
1742
  checkpoint: "CheckpointConfig",
1730
1743
  classification: "FlowClassification",
1731
1744
  compliance: "FlowCompliance",
@@ -2035,10 +2048,7 @@ var KNOWN_KEYS = aigentflow_spec_default.knownKeys;
2035
2048
  var ORCHESTRATOR_TOOL_ALLOW = {
2036
2049
  warningField: aigentflow_spec_default.orchestratorToolAllow.warningField,
2037
2050
  askHumanTool: aigentflow_spec_default.orchestratorToolAllow.askHumanTool,
2038
- enableSignalsDefault: aigentflow_spec_default.orchestratorToolAllow.enableSignalsDefault,
2039
- lifecycleTools: aigentflow_spec_default.orchestratorToolAllow.lifecycleTools,
2040
- signalTools: aigentflow_spec_default.orchestratorToolAllow.signalTools,
2041
- campaignTools: aigentflow_spec_default.orchestratorToolAllow.campaignTools
2051
+ lifecycleTools: aigentflow_spec_default.orchestratorToolAllow.lifecycleTools
2042
2052
  };
2043
2053
  var EXONS = {
2044
2054
  /** The YAML frontmatter delimiter line. */
@@ -2057,6 +2067,45 @@ var REMOVED_AGENT_SURFACES = {
2057
2067
  flowKeyMessageFormat: removed.flowKeyMessageFormat,
2058
2068
  suggestion: removed.suggestion
2059
2069
  };
2070
+ var signal = aigentflow_spec_default.removedSignalSurfaces;
2071
+ var REMOVED_SIGNAL_SURFACES = {
2072
+ signalRemovedCode: signal.signalRemovedCode,
2073
+ flowModificationRemovedCode: signal.flowModificationRemovedCode,
2074
+ removedKeyIgnoredCode: signal.removedKeyIgnoredCode,
2075
+ tools: signal.tools,
2076
+ triggers: signal.triggers,
2077
+ stepKey: signal.stepKey,
2078
+ stepKeyScheme: signal.stepKeyScheme,
2079
+ flowModificationStepKey: signal.flowModificationStepKey,
2080
+ stepSkipSchemes: new Set(signal.stepSkipSchemes),
2081
+ enableSignalsMessage: signal.enableSignalsMessage,
2082
+ toolNamesMessageFormat: signal.toolNamesMessageFormat,
2083
+ stepKeyMessageFormat: signal.stepKeyMessageFormat,
2084
+ triggersMessage: signal.triggersMessage,
2085
+ flowModificationStepMessageFormat: signal.flowModificationStepMessageFormat,
2086
+ ignoredKeyMessageFormat: signal.ignoredKeyMessageFormat,
2087
+ ignoredKeySuggestion: signal.ignoredKeySuggestion,
2088
+ suggestion: signal.suggestion
2089
+ };
2090
+ var campaign = aigentflow_spec_default.removedCampaignSurfaces;
2091
+ var REMOVED_CAMPAIGN_SURFACES = {
2092
+ code: campaign.code,
2093
+ flowKey: campaign.flowKey,
2094
+ tools: campaign.tools,
2095
+ triggers: campaign.triggers,
2096
+ blockMessage: campaign.blockMessage,
2097
+ toolNamesMessageFormat: campaign.toolNamesMessageFormat,
2098
+ triggersMessageFormat: campaign.triggersMessageFormat,
2099
+ suggestion: campaign.suggestion
2100
+ };
2101
+ var REMOVED_ORCHESTRATOR_TOOLS = /* @__PURE__ */ new Set([
2102
+ ...signal.tools,
2103
+ ...campaign.tools
2104
+ ]);
2105
+ var REMOVED_ORCHESTRATOR_TRIGGERS = /* @__PURE__ */ new Set([
2106
+ ...signal.triggers,
2107
+ ...campaign.triggers
2108
+ ]);
2060
2109
  var EXECUTOR_CONFIG_ENV_SCOPES = {
2061
2110
  referencePrefix: aigentflow_spec_default.executorConfigEnvScopes.referencePrefix,
2062
2111
  referenceSuffix: aigentflow_spec_default.executorConfigEnvScopes.referenceSuffix,
@@ -2149,7 +2198,8 @@ var FUNCTION_OPERATIONS = {
2149
2198
  };
2150
2199
  var atlas = aigentflow_spec_default.atlasExecutor;
2151
2200
  var ATLAS_EXECUTOR = {
2152
- scheme: atlas.scheme,
2201
+ /** The canonical scheme (nexus) and its aliases (atlas): one set of rules. */
2202
+ schemes: /* @__PURE__ */ new Set([atlas.scheme, ...atlas.aliases]),
2153
2203
  providerAgent: atlas.providerAgent,
2154
2204
  providerCapability: atlas.providerCapability,
2155
2205
  agentResource: atlas.agentResource,
@@ -2361,16 +2411,14 @@ function validateOrchestratorExons(flow, issues) {
2361
2411
  suggestion: "Remove requirements.resources, and narrow the agent with tools.mcp_servers and tools.allow"
2362
2412
  });
2363
2413
  }
2364
- warnOrchestratorToolWithheld(flow, orch, report, issues);
2414
+ warnOrchestratorToolWithheld(orch, report, issues);
2365
2415
  }
2366
- function warnOrchestratorToolWithheld(flow, orch, report, issues) {
2416
+ function warnOrchestratorToolWithheld(orch, report, issues) {
2367
2417
  if (!report.toolsAllowDeclared) return;
2368
2418
  const cfg = ORCHESTRATOR_TOOL_ALLOW;
2369
2419
  const exempt = new Set(cfg.lifecycleTools);
2370
- const signals = typeof orch.enable_signals === "boolean" ? orch.enable_signals : cfg.enableSignalsDefault;
2371
- if (signals) for (const t of cfg.signalTools) exempt.add(t);
2372
2420
  const allow = new Set(report.toolsAllow);
2373
- const withheld = (name) => !allow.has(name) && !exempt.has(name);
2421
+ const withheld = (name) => !allow.has(name) && !exempt.has(name) && !REMOVED_ORCHESTRATOR_TOOLS.has(name);
2374
2422
  const warn = (message) => issues.warn({ field: cfg.warningField, code: CODE_TOOL_WITHHELD, message });
2375
2423
  const named = [];
2376
2424
  if (isArray(orch.tools)) {
@@ -2393,11 +2441,6 @@ function warnOrchestratorToolWithheld(flow, orch, report, issues) {
2393
2441
  `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.`
2394
2442
  );
2395
2443
  }
2396
- if (isRecord(flow.campaign) && !cfg.campaignTools.some((name) => !withheld(name))) {
2397
- warn(
2398
- `this flow declares a campaign, but the orchestrator's exons definition has a tools.allow list that names none of the campaign tools (${cfg.campaignTools.join(", ")}), so no child mission can be spawned or tracked. Add the campaign tools the orchestrator needs to tools.allow.`
2399
- );
2400
- }
2401
2444
  }
2402
2445
 
2403
2446
  // src/validators/executors.ts
@@ -2514,9 +2557,9 @@ function validateRemovedFlowKeys(flow, issues) {
2514
2557
  }
2515
2558
  function checkAtlasStep(executor, query, stepField, stepID, issues) {
2516
2559
  if (executor.includes(TEMPLATE_ACTION_OPEN)) return;
2517
- const prefix = `${ATLAS_EXECUTOR.scheme}://`;
2518
- if (!executor.startsWith(prefix)) return;
2519
- const rest = executor.slice(prefix.length);
2560
+ const sep = executor.indexOf(SCHEME_SEPARATOR);
2561
+ if (sep < 0 || !ATLAS_EXECUTOR.schemes.has(executor.slice(0, sep))) return;
2562
+ const rest = executor.slice(sep + SCHEME_SEPARATOR.length);
2520
2563
  const slash = rest.indexOf("/");
2521
2564
  const provider = slash < 0 ? rest : rest.slice(0, slash);
2522
2565
  const resource = slash < 0 ? "" : rest.slice(slash + 1);
@@ -3729,49 +3772,6 @@ function flowHasOrchestratorYieldEdge(flow) {
3729
3772
  }
3730
3773
  return false;
3731
3774
  }
3732
- var GO_INT64_FLOAT_LIMIT = 2 ** 63;
3733
- function decodeGoInt(v) {
3734
- if (typeof v !== "number" || Number.isNaN(v)) return null;
3735
- if (v >= GO_INT64_FLOAT_LIMIT) return null;
3736
- if (v === -Infinity) return -GO_INT64_FLOAT_LIMIT;
3737
- return Math.trunc(v);
3738
- }
3739
- function validateCampaignChildFlows(campaign, issues) {
3740
- const field = "campaign.child_flows";
3741
- const raw = campaign.child_flows;
3742
- if (raw !== void 0 && raw !== null && !Array.isArray(raw)) {
3743
- issues.error({ field, message: "campaign.child_flows must be a list", code: "invalid_type" });
3744
- return;
3745
- }
3746
- const entries = (Array.isArray(raw) ? raw : []).map((entry, i) => ({ entry, i })).filter(({ entry }) => entry !== null);
3747
- if (entries.length === 0) {
3748
- issues.error({
3749
- field,
3750
- message: "campaign requires at least one entry in child_flows",
3751
- code: "campaign_no_child_flows"
3752
- });
3753
- return;
3754
- }
3755
- for (const { entry, i } of entries) {
3756
- if (!isRecord(entry)) {
3757
- issues.error({
3758
- field: `${field}[${i}]`,
3759
- message: "each campaign.child_flows entry must be a mapping",
3760
- code: "invalid_type"
3761
- });
3762
- continue;
3763
- }
3764
- const id = issues.stringOf(entry, "flow_id", `${field}[${i}]`);
3765
- const name = issues.stringOf(entry, "flow_name", `${field}[${i}]`);
3766
- if (id !== null && id !== "" || name !== null && name !== "") continue;
3767
- issues.error({
3768
- field: `${field}[${i}]`,
3769
- message: `campaign.child_flows[${i}] needs a flow_id or a flow_name`,
3770
- code: "campaign_child_flow_no_id",
3771
- suggestion: "Name the child flow with flow_name, or pin it with flow_id"
3772
- });
3773
- }
3774
- }
3775
3775
  function validateOrchestratorCampaign(flow, issues, opts) {
3776
3776
  const hasOrchestrator = isRecord(flow.orchestrator);
3777
3777
  if (hasOrchestrator) {
@@ -3827,6 +3827,7 @@ function validateOrchestratorCampaign(flow, issues, opts) {
3827
3827
  const trigger = rawTrigger;
3828
3828
  const base = `orchestrator.triggers[${i}]`;
3829
3829
  const type = issues.stringOf(trigger, "type", base);
3830
+ if (type !== null && REMOVED_ORCHESTRATOR_TRIGGERS.has(type)) return;
3830
3831
  if (type === null || !ORCHESTRATOR_TRIGGERS.has(type)) {
3831
3832
  issues.error({
3832
3833
  field: `${base}.type`,
@@ -3857,7 +3858,9 @@ function validateOrchestratorCampaign(flow, issues, opts) {
3857
3858
  if (Array.isArray(orch.tools)) {
3858
3859
  orch.tools.forEach((raw, i) => {
3859
3860
  const tool = issues.stringAt(raw, `orchestrator.tools[${i}]`);
3860
- if (tool === null || ORCHESTRATOR_TOOLS.has(tool)) return;
3861
+ if (tool === null || ORCHESTRATOR_TOOLS.has(tool) || REMOVED_ORCHESTRATOR_TOOLS.has(tool)) {
3862
+ return;
3863
+ }
3861
3864
  const finding = {
3862
3865
  field: `orchestrator.tools[${i}]`,
3863
3866
  message: `Unrecognised orchestrator tool name '${tool}'`,
@@ -3878,47 +3881,6 @@ function validateOrchestratorCampaign(flow, issues, opts) {
3878
3881
  });
3879
3882
  }
3880
3883
  }
3881
- if (flow.campaign !== void 0 && flow.campaign !== null) {
3882
- if (!hasOrchestrator) {
3883
- issues.error({
3884
- field: "campaign",
3885
- message: "campaign requires an orchestrator block",
3886
- code: "campaign_requires_orchestrator"
3887
- });
3888
- }
3889
- const campaign = flow.campaign;
3890
- if (isRecord(campaign)) {
3891
- const cap = campaign.max_credits_per_child;
3892
- if (cap !== void 0 && cap !== null) {
3893
- const decoded = decodeGoInt(cap);
3894
- if (decoded === null) {
3895
- issues.error({
3896
- field: "campaign.max_credits_per_child",
3897
- message: `campaign.max_credits_per_child must be a number of credits, got '${String(cap)}'`,
3898
- code: "invalid_type"
3899
- });
3900
- } else if (decoded < 0) {
3901
- issues.error({
3902
- field: "campaign.max_credits_per_child",
3903
- message: "campaign: max_credits_per_child must be >= 0",
3904
- code: "campaign_invalid_max_credits_per_child"
3905
- });
3906
- }
3907
- }
3908
- validateCampaignChildFlows(campaign, issues);
3909
- }
3910
- const target = isRecord(campaign) ? issues.stringOf(campaign, "on_children_complete", "campaign") : null;
3911
- if (target !== null && target !== "") {
3912
- const steps = isRecord(flow.steps) ? flow.steps : {};
3913
- if (!(target in steps)) {
3914
- issues.error({
3915
- field: "campaign.on_children_complete",
3916
- message: `campaign.on_children_complete references unknown step '${target}'`,
3917
- code: "campaign_handoff_step_unknown"
3918
- });
3919
- }
3920
- }
3921
- }
3922
3884
  }
3923
3885
 
3924
3886
  // src/validators/credentialBindings.ts
@@ -5044,10 +5006,6 @@ var CODE_UNKNOWN_YAML_KEY = "unknown_yaml_key";
5044
5006
  var KEY_BUDGET = "budget";
5045
5007
  var KEY_MAX_RETRIES = "max_retries";
5046
5008
  var REMOVED_IN = "v2.721.0";
5047
- var KEY_BUDGET_MAX_PER_CHILD = "budget_max_per_child";
5048
- var BUDGET_MAX_PER_CHILD_REMOVED_IN = "v2.728.0";
5049
- 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.`;
5050
- 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`.";
5051
5009
  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.`;
5052
5010
  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.";
5053
5011
  function maxRetriesMessage(owner) {
@@ -5075,15 +5033,6 @@ function validateRetiredKeys(flow, issues) {
5075
5033
  suggestion: MAX_RETRIES_SUGGESTION
5076
5034
  });
5077
5035
  }
5078
- const campaign = root.campaign;
5079
- if (isRecord(campaign) && declares(campaign, KEY_BUDGET_MAX_PER_CHILD)) {
5080
- issues.error({
5081
- field: `campaign.${KEY_BUDGET_MAX_PER_CHILD}`,
5082
- message: BUDGET_MAX_PER_CHILD_MESSAGE,
5083
- code: CODE_UNKNOWN_YAML_KEY,
5084
- suggestion: BUDGET_MAX_PER_CHILD_SUGGESTION
5085
- });
5086
- }
5087
5036
  const steps = flow.steps;
5088
5037
  if (!isRecord(steps)) return;
5089
5038
  for (const [stepID, rawStep] of Object.entries(steps)) {
@@ -5909,6 +5858,167 @@ function validateFamilies(flow, steps, issues) {
5909
5858
  }
5910
5859
  }
5911
5860
 
5861
+ // src/validators/removedSignalCampaign.ts
5862
+ var TEMPLATE_ACTION_OPEN3 = "{{";
5863
+ function fill(format, ...args) {
5864
+ let i = 0;
5865
+ return format.replace(/%[qs]/g, () => args[i++] ?? "");
5866
+ }
5867
+ function stringEntries(m, key) {
5868
+ const raw = m[key];
5869
+ return Array.isArray(raw) ? raw.filter((v) => typeof v === "string") : [];
5870
+ }
5871
+ function triggerTypes(orch) {
5872
+ const raw = orch.triggers;
5873
+ if (!Array.isArray(raw)) return [];
5874
+ const out = [];
5875
+ for (const t of raw) {
5876
+ if (isRecord(t) && typeof t.type === "string") out.push(t.type);
5877
+ }
5878
+ return out;
5879
+ }
5880
+ function namesIn(names, removed2) {
5881
+ const found = [];
5882
+ for (const name of names) {
5883
+ if (removed2.includes(name) && !found.includes(name)) found.push(name);
5884
+ }
5885
+ return found;
5886
+ }
5887
+ function orchestratorToolsAllow(orch) {
5888
+ const source = orch.exons;
5889
+ if (typeof source !== "string" || source === "") return [];
5890
+ const report = inspectExonsFrontmatter(source);
5891
+ if (report.parseError !== null || !report.specRead || !report.toolsAllowDeclared) return [];
5892
+ return [...report.toolsAllow];
5893
+ }
5894
+ function validateRemovedOrchestratorSurfaces(flow, issues) {
5895
+ const sig = REMOVED_SIGNAL_SURFACES;
5896
+ const camp = REMOVED_CAMPAIGN_SURFACES;
5897
+ const orch = isRecord(flow.orchestrator) ? flow.orchestrator : null;
5898
+ const lists = orch === null ? [] : [
5899
+ ...["tools", "deny_tools", "require_approval_for"].map((key) => ({
5900
+ field: `orchestrator.${key}`,
5901
+ names: stringEntries(orch, key)
5902
+ })),
5903
+ { field: "orchestrator.exons", names: orchestratorToolsAllow(orch) }
5904
+ ];
5905
+ if (orch !== null) {
5906
+ if (orch.enable_signals === true) {
5907
+ issues.error({
5908
+ field: "orchestrator.enable_signals",
5909
+ code: sig.signalRemovedCode,
5910
+ message: sig.enableSignalsMessage,
5911
+ suggestion: sig.suggestion
5912
+ });
5913
+ }
5914
+ for (const list of lists) {
5915
+ const named = namesIn(list.names, sig.tools);
5916
+ if (named.length === 0) continue;
5917
+ issues.error({
5918
+ field: list.field,
5919
+ code: sig.signalRemovedCode,
5920
+ message: fill(sig.toolNamesMessageFormat, list.field, named.join(", ")),
5921
+ suggestion: sig.suggestion
5922
+ });
5923
+ }
5924
+ if (namesIn(triggerTypes(orch), sig.triggers).length > 0) {
5925
+ issues.error({
5926
+ field: "orchestrator.triggers",
5927
+ code: sig.flowModificationRemovedCode,
5928
+ message: sig.triggersMessage,
5929
+ suggestion: sig.suggestion
5930
+ });
5931
+ }
5932
+ }
5933
+ const block = flow[camp.flowKey];
5934
+ if (block !== void 0 && block !== null) {
5935
+ issues.error({
5936
+ field: camp.flowKey,
5937
+ code: camp.code,
5938
+ message: camp.blockMessage,
5939
+ suggestion: camp.suggestion
5940
+ });
5941
+ }
5942
+ if (orch !== null) {
5943
+ for (const list of lists) {
5944
+ const named = namesIn(list.names, camp.tools);
5945
+ if (named.length === 0) continue;
5946
+ issues.error({
5947
+ field: list.field,
5948
+ code: camp.code,
5949
+ message: fill(camp.toolNamesMessageFormat, list.field, named.join(", ")),
5950
+ suggestion: camp.suggestion
5951
+ });
5952
+ }
5953
+ const triggers = namesIn(triggerTypes(orch), camp.triggers);
5954
+ if (triggers.length > 0) {
5955
+ issues.error({
5956
+ field: "orchestrator.triggers",
5957
+ code: camp.code,
5958
+ message: fill(camp.triggersMessageFormat, triggers.join(", ")),
5959
+ suggestion: camp.suggestion
5960
+ });
5961
+ }
5962
+ }
5963
+ const judgeStep = (executor, query, field, stepID) => {
5964
+ if (typeof executor !== "string" || executor === "") return;
5965
+ if (executor.includes(TEMPLATE_ACTION_OPEN3)) return;
5966
+ const scheme = removedExecutorScheme(executor);
5967
+ if (REMOVED_AGENT_SURFACES.schemes.has(scheme) || sig.stepSkipSchemes.has(scheme)) return;
5968
+ if (!isRecord(query)) return;
5969
+ const quoted = JSON.stringify(stepID);
5970
+ if (Object.prototype.hasOwnProperty.call(query, sig.flowModificationStepKey)) {
5971
+ issues.error({
5972
+ field,
5973
+ code: sig.flowModificationRemovedCode,
5974
+ stepId: stepID,
5975
+ message: fill(sig.flowModificationStepMessageFormat, quoted),
5976
+ suggestion: sig.suggestion
5977
+ });
5978
+ }
5979
+ if (scheme === sig.stepKeyScheme && Object.prototype.hasOwnProperty.call(query, sig.stepKey)) {
5980
+ issues.error({
5981
+ field,
5982
+ code: sig.signalRemovedCode,
5983
+ stepId: stepID,
5984
+ message: fill(sig.stepKeyMessageFormat, quoted),
5985
+ suggestion: sig.suggestion
5986
+ });
5987
+ }
5988
+ };
5989
+ const steps = flow.steps;
5990
+ if (isRecord(steps)) {
5991
+ for (const stepID of Object.keys(steps).sort()) {
5992
+ const step = steps[stepID];
5993
+ if (!isRecord(step)) continue;
5994
+ judgeStep(step.executor, step.query, `steps.${stepID}`, stepID);
5995
+ const loop = step.loop;
5996
+ if (!isRecord(loop) || !Array.isArray(loop.steps)) continue;
5997
+ loop.steps.forEach((sub, i) => {
5998
+ if (!isRecord(sub)) return;
5999
+ const subID = issues.stringOf(sub, "id", `steps.${stepID}.loop.steps[${i}]`) ?? String(i);
6000
+ judgeStep(
6001
+ sub.executor,
6002
+ sub.query,
6003
+ `steps.${stepID}.loop.steps[${i}]`,
6004
+ `${stepID}.${subID}`
6005
+ );
6006
+ });
6007
+ }
6008
+ }
6009
+ const ignored = (field) => issues.warn({
6010
+ field,
6011
+ code: sig.removedKeyIgnoredCode,
6012
+ message: fill(sig.ignoredKeyMessageFormat, field),
6013
+ suggestion: sig.ignoredKeySuggestion
6014
+ });
6015
+ if (orch !== null && orch.enable_signals === false) ignored("orchestrator.enable_signals");
6016
+ const checkpoint = flow.checkpoint;
6017
+ if (isRecord(checkpoint) && checkpoint.pre_dfm !== void 0 && checkpoint.pre_dfm !== null) {
6018
+ ignored("checkpoint.pre_dfm");
6019
+ }
6020
+ }
6021
+
5912
6022
  // src/validators/complianceResidency.ts
5913
6023
  function own2(m, key) {
5914
6024
  if (!isRecord(m) || !Object.prototype.hasOwnProperty.call(m, key)) return void 0;
@@ -7389,6 +7499,7 @@ function validateParsed(flow, opts, sources) {
7389
7499
  validateCredentialEndpointPairing(f, issues);
7390
7500
  validateExamples(f, issues);
7391
7501
  validateOrchestratorExons(f, issues);
7502
+ validateRemovedOrchestratorSurfaces(f, issues);
7392
7503
  validateResidencyEnforcement(f, issues);
7393
7504
  validateUnknownKeys(f, issues);
7394
7505
  const templateStats = validateTemplates(f, issues, opts);