agent-contracts 0.12.1 → 0.12.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/cli.js CHANGED
@@ -50479,7 +50479,8 @@ var AgentSchema = z.object({
50479
50479
  rules: z.array(RuleSchema).optional(),
50480
50480
  anti_patterns: z.array(z.string()).optional(),
50481
50481
  escalation_criteria: z.array(EscalationCriterionSchema).optional(),
50482
- prerequisites: z.array(PrerequisiteSchema).optional()
50482
+ prerequisites: z.array(PrerequisiteSchema).optional(),
50483
+ guardrails: z.array(z.string()).optional()
50483
50484
  }).passthrough();
50484
50485
 
50485
50486
  // src/schema/artifact.ts
@@ -50493,7 +50494,8 @@ var ArtifactSchema = z2.object({
50493
50494
  consumers: z2.array(z2.string()),
50494
50495
  states: z2.array(z2.string()),
50495
50496
  required_validations: z2.array(z2.string()).default([]),
50496
- visibility: z2.string().optional()
50497
+ visibility: z2.string().optional(),
50498
+ guardrails: z2.array(z2.string()).optional()
50497
50499
  }).passthrough();
50498
50500
 
50499
50501
  // src/schema/binding.ts
@@ -50657,7 +50659,8 @@ var TaskSchema = z8.object({
50657
50659
  rules: z8.array(RuleSchema).optional(),
50658
50660
  anti_patterns: z8.array(z8.string()).optional(),
50659
50661
  escalation_criteria: z8.array(EscalationCriterionSchema).optional(),
50660
- validations: z8.array(z8.string()).default([])
50662
+ validations: z8.array(z8.string()).default([]),
50663
+ guardrails: z8.array(z8.string()).optional()
50661
50664
  }).passthrough();
50662
50665
 
50663
50666
  // src/schema/tool.ts
@@ -50676,7 +50679,8 @@ var ToolSchema = z9.object({
50676
50679
  output_artifacts: z9.array(z9.string()).default([]),
50677
50680
  invokable_by: z9.array(z9.string()),
50678
50681
  side_effects: z9.array(z9.string()).default([]),
50679
- commands: z9.array(CommandSchema).default([])
50682
+ commands: z9.array(CommandSchema).default([]),
50683
+ guardrails: z9.array(z9.string()).optional()
50680
50684
  }).passthrough();
50681
50685
 
50682
50686
  // src/schema/validation.ts
@@ -52139,6 +52143,34 @@ function checkReferences(dsl) {
52139
52143
  }
52140
52144
  }
52141
52145
  }
52146
+ for (const [id, agent] of Object.entries(dsl.agents)) {
52147
+ if (agent.guardrails) {
52148
+ for (const ref of agent.guardrails) {
52149
+ checkExists(ref, guardrailIds, "guardrails", `agents.${id}.guardrails`, "entity-guardrail-ref-not-found");
52150
+ }
52151
+ }
52152
+ }
52153
+ for (const [id, task] of Object.entries(dsl.tasks)) {
52154
+ if (task.guardrails) {
52155
+ for (const ref of task.guardrails) {
52156
+ checkExists(ref, guardrailIds, "guardrails", `tasks.${id}.guardrails`, "entity-guardrail-ref-not-found");
52157
+ }
52158
+ }
52159
+ }
52160
+ for (const [id, tool] of Object.entries(dsl.tools)) {
52161
+ if (tool.guardrails) {
52162
+ for (const ref of tool.guardrails) {
52163
+ checkExists(ref, guardrailIds, "guardrails", `tools.${id}.guardrails`, "entity-guardrail-ref-not-found");
52164
+ }
52165
+ }
52166
+ }
52167
+ for (const [id, art] of Object.entries(dsl.artifacts)) {
52168
+ if (art.guardrails) {
52169
+ for (const ref of art.guardrails) {
52170
+ checkExists(ref, guardrailIds, "guardrails", `artifacts.${id}.guardrails`, "entity-guardrail-ref-not-found");
52171
+ }
52172
+ }
52173
+ }
52142
52174
  for (const [id, guardrail] of Object.entries(dsl.guardrails)) {
52143
52175
  if (guardrail.scope.agents) {
52144
52176
  for (const ref of guardrail.scope.agents) {
@@ -52869,6 +52901,114 @@ var semanticValidationPhaseCoverageRule = {
52869
52901
  }
52870
52902
  };
52871
52903
 
52904
+ // src/linter/rules/entity-guardrail-binding.ts
52905
+ var entityGuardrailUndefinedRule = {
52906
+ id: "entity-guardrail-undefined",
52907
+ description: "Entity references a guardrail ID not defined in guardrails",
52908
+ run(dsl) {
52909
+ const diagnostics = [];
52910
+ const guardrailIds = new Set(Object.keys(dsl.guardrails));
52911
+ const sections = [
52912
+ { name: "agents", entities: dsl.agents },
52913
+ { name: "tasks", entities: dsl.tasks },
52914
+ { name: "tools", entities: dsl.tools },
52915
+ { name: "artifacts", entities: dsl.artifacts }
52916
+ ];
52917
+ for (const { name, entities } of sections) {
52918
+ for (const [entityId, entity] of Object.entries(entities)) {
52919
+ for (const ref of entity.guardrails ?? []) {
52920
+ if (!guardrailIds.has(ref)) {
52921
+ diagnostics.push({
52922
+ ruleId: "entity-guardrail-undefined",
52923
+ severity: "error",
52924
+ path: `${name}.${entityId}.guardrails`,
52925
+ message: `${name.slice(0, -1)} "${entityId}" references guardrail "${ref}" which is not defined in guardrails`
52926
+ });
52927
+ }
52928
+ }
52929
+ }
52930
+ }
52931
+ return diagnostics;
52932
+ }
52933
+ };
52934
+ var entityNoGuardrailsRule = {
52935
+ id: "entity-no-guardrails",
52936
+ description: "Entity has no effective guardrails (neither entity-side nor scope-side)",
52937
+ run(dsl) {
52938
+ const diagnostics = [];
52939
+ const scopeBindings = {
52940
+ agents: /* @__PURE__ */ new Set(),
52941
+ tasks: /* @__PURE__ */ new Set(),
52942
+ tools: /* @__PURE__ */ new Set(),
52943
+ artifacts: /* @__PURE__ */ new Set()
52944
+ };
52945
+ for (const guardrail of Object.values(dsl.guardrails)) {
52946
+ for (const key of Object.keys(scopeBindings)) {
52947
+ const ids = guardrail.scope[key];
52948
+ if (ids) {
52949
+ for (const id of ids) scopeBindings[key].add(id);
52950
+ }
52951
+ }
52952
+ }
52953
+ const sections = [
52954
+ { name: "agents", entities: dsl.agents },
52955
+ { name: "tasks", entities: dsl.tasks },
52956
+ { name: "tools", entities: dsl.tools },
52957
+ { name: "artifacts", entities: dsl.artifacts }
52958
+ ];
52959
+ for (const { name, entities } of sections) {
52960
+ for (const [entityId, entity] of Object.entries(entities)) {
52961
+ const hasEntitySide = (entity.guardrails ?? []).length > 0;
52962
+ const hasScopeSide = scopeBindings[name].has(entityId);
52963
+ if (!hasEntitySide && !hasScopeSide) {
52964
+ diagnostics.push({
52965
+ ruleId: "entity-no-guardrails",
52966
+ severity: "info",
52967
+ path: `${name}.${entityId}`,
52968
+ message: `${name.slice(0, -1)} "${entityId}" has no effective guardrails`
52969
+ });
52970
+ }
52971
+ }
52972
+ }
52973
+ return diagnostics;
52974
+ }
52975
+ };
52976
+ var guardrailOrphanedRule = {
52977
+ id: "guardrail-orphaned",
52978
+ description: "Guardrail is not referenced by any entity and not bound to any entity via scope",
52979
+ run(dsl) {
52980
+ const diagnostics = [];
52981
+ const referencedByEntities = /* @__PURE__ */ new Set();
52982
+ const sections = [
52983
+ dsl.agents,
52984
+ dsl.tasks,
52985
+ dsl.tools,
52986
+ dsl.artifacts
52987
+ ];
52988
+ for (const entities of sections) {
52989
+ for (const entity of Object.values(entities)) {
52990
+ for (const ref of entity.guardrails ?? []) {
52991
+ referencedByEntities.add(ref);
52992
+ }
52993
+ }
52994
+ }
52995
+ for (const [guardrailId, guardrail] of Object.entries(dsl.guardrails)) {
52996
+ const hasEntityRef = referencedByEntities.has(guardrailId);
52997
+ const scope = guardrail.scope;
52998
+ const hasScopeBinding = (scope.agents?.length ?? 0) > 0 || (scope.tasks?.length ?? 0) > 0 || (scope.tools?.length ?? 0) > 0 || (scope.artifacts?.length ?? 0) > 0 || (scope.workflows?.length ?? 0) > 0;
52999
+ if (!hasEntityRef && !hasScopeBinding) {
53000
+ diagnostics.push({
53001
+ ruleId: "guardrail-orphaned",
53002
+ severity: "warning",
53003
+ path: `guardrails.${guardrailId}`,
53004
+ message: `Guardrail "${guardrailId}" is not referenced by any entity and has no scope bindings`
53005
+ });
53006
+ }
53007
+ }
53008
+ return diagnostics;
53009
+ }
53010
+ };
53011
+
52872
53012
  // src/linter/linter.ts
52873
53013
  var builtinRules = [
52874
53014
  validationCoverageRule,
@@ -52881,7 +53021,10 @@ var builtinRules = [
52881
53021
  yamlReservedKeySafetyRule,
52882
53022
  artifactRequiredValidationWiringRule,
52883
53023
  taskOutputValidationCompletenessRule,
52884
- semanticValidationPhaseCoverageRule
53024
+ semanticValidationPhaseCoverageRule,
53025
+ entityGuardrailUndefinedRule,
53026
+ entityNoGuardrailsRule,
53027
+ guardrailOrphanedRule
52885
53028
  ];
52886
53029
  function lint(dsl, rules = builtinRules) {
52887
53030
  const diagnostics = [];
@@ -53628,12 +53771,55 @@ function buildGuardrailEnforcement(dsl, policy, loadedBindings) {
53628
53771
  }
53629
53772
  return entries;
53630
53773
  }
53774
+ function resolveEffectiveGuardrails(dsl, entityType, entityId) {
53775
+ const entityDef = dsl[entityType][entityId];
53776
+ const entitySide = new Set(entityDef?.guardrails ?? []);
53777
+ const scopeSide = /* @__PURE__ */ new Set();
53778
+ for (const [guardrailId, guardrail] of Object.entries(dsl.guardrails)) {
53779
+ const scopeIds = guardrail.scope[entityType];
53780
+ if (scopeIds?.includes(entityId)) {
53781
+ scopeSide.add(guardrailId);
53782
+ }
53783
+ }
53784
+ const allIds = /* @__PURE__ */ new Set([...entitySide, ...scopeSide]);
53785
+ const activePolicyRules = /* @__PURE__ */ new Map();
53786
+ for (const policy of Object.values(dsl.guardrail_policies)) {
53787
+ for (const rule of policy.rules) {
53788
+ if (!activePolicyRules.has(rule.guardrail)) {
53789
+ activePolicyRules.set(rule.guardrail, {
53790
+ severity: rule.severity,
53791
+ action: rule.action
53792
+ });
53793
+ }
53794
+ }
53795
+ }
53796
+ const entries = [];
53797
+ for (const id of allIds) {
53798
+ const guardrail = dsl.guardrails[id];
53799
+ if (!guardrail) continue;
53800
+ const fromEntity = entitySide.has(id);
53801
+ const fromScope = scopeSide.has(id);
53802
+ const source = fromEntity && fromScope ? "both" : fromEntity ? "entity" : "scope";
53803
+ const policyInfo = activePolicyRules.get(id);
53804
+ entries.push({
53805
+ guardrail_id: id,
53806
+ description: guardrail.description,
53807
+ rationale: guardrail.rationale,
53808
+ tags: guardrail.tags,
53809
+ source,
53810
+ severity: policyInfo?.severity,
53811
+ action: policyInfo?.action
53812
+ });
53813
+ }
53814
+ return entries;
53815
+ }
53631
53816
  function buildTaskContext(dsl, taskId) {
53632
53817
  const taskDef = dsl.tasks[taskId];
53633
53818
  const task = { ...taskDef, id: taskId };
53634
53819
  const agentDef = dsl.agents[taskDef.target_agent];
53635
53820
  const targetAgent = agentDef ? { ...agentDef, id: taskDef.target_agent } : null;
53636
- return { task, targetAgent, dsl };
53821
+ const relatedGuardrails = resolveEffectiveGuardrails(dsl, "tasks", taskId);
53822
+ return { task, targetAgent, relatedGuardrails, dsl };
53637
53823
  }
53638
53824
  function buildArtifactContext(dsl, artifactId) {
53639
53825
  const artifactDef = dsl.artifacts[artifactId];
@@ -53676,6 +53862,7 @@ function buildArtifactContext(dsl, artifactId) {
53676
53862
  }
53677
53863
  }
53678
53864
  }
53865
+ const relatedGuardrails = resolveEffectiveGuardrails(dsl, "artifacts", artifactId);
53679
53866
  return {
53680
53867
  artifact,
53681
53868
  relatedTools,
@@ -53684,6 +53871,7 @@ function buildArtifactContext(dsl, artifactId) {
53684
53871
  consumerAgents,
53685
53872
  editorAgents,
53686
53873
  createdInWorkflows,
53874
+ relatedGuardrails,
53687
53875
  dsl
53688
53876
  };
53689
53877
  }
@@ -53701,11 +53889,13 @@ function buildToolContext(dsl, toolId) {
53701
53889
  }
53702
53890
  return result;
53703
53891
  };
53892
+ const relatedGuardrails = resolveEffectiveGuardrails(dsl, "tools", toolId);
53704
53893
  return {
53705
53894
  tool,
53706
53895
  invokableAgents,
53707
53896
  inputArtifactDetails: pickArtifacts(toolDef.input_artifacts),
53708
53897
  outputArtifactDetails: pickArtifacts(toolDef.output_artifacts),
53898
+ relatedGuardrails,
53709
53899
  dsl
53710
53900
  };
53711
53901
  }
@@ -53937,6 +54127,7 @@ function buildPerAgentContext(dsl, agent) {
53937
54127
  }
53938
54128
  const rawReceivableTasks = receivableTasks.map(({ id: _id, ...rest }) => rest);
53939
54129
  const mergedBehavior = mergeBehavioralSpec(agent, rawReceivableTasks);
54130
+ const relatedGuardrails = resolveEffectiveGuardrails(dsl, "agents", agentId);
53940
54131
  return {
53941
54132
  agent,
53942
54133
  tasks: receivableTasks,
@@ -53946,6 +54137,7 @@ function buildPerAgentContext(dsl, agent) {
53946
54137
  relatedTools,
53947
54138
  relatedHandoffTypes,
53948
54139
  mergedBehavior,
54140
+ relatedGuardrails,
53949
54141
  dsl
53950
54142
  };
53951
54143
  }
@@ -54993,9 +55185,18 @@ var checkCommand = new Command5("check").description("Run full pipeline: resolve
54993
55185
  hasErrors = true;
54994
55186
  }
54995
55187
  }
55188
+ let renderOptions;
55189
+ if (config.bindings.length > 0) {
55190
+ const loadedBindings = await loadBindings(config.bindings);
55191
+ renderOptions = {
55192
+ loadedBindings,
55193
+ activeGuardrailPolicy: config.activeGuardrailPolicy
55194
+ };
55195
+ }
54996
55196
  const drift = await checkDriftFromConfig(
54997
55197
  schemaResult.data,
54998
- config.renders
55198
+ config.renders,
55199
+ renderOptions
54999
55200
  );
55000
55201
  if (drift.hasDrift) {
55001
55202
  process.stderr.write("Drift detected in:\n");
@@ -55667,6 +55868,52 @@ function crossReferenceBidirectionality(dsl) {
55667
55868
  recommendations: issues.length > 0 ? [`${issues.length} unreciprocated cross-references: ${issues.slice(0, 5).join(", ")}${issues.length > 5 ? `, ... (${issues.length - 5} more)` : ""}`] : []
55668
55869
  };
55669
55870
  }
55871
+ function entityGuardrailCoverage(dsl) {
55872
+ const entitySections = [
55873
+ { name: "agents", entities: dsl.agents },
55874
+ { name: "tasks", entities: dsl.tasks },
55875
+ { name: "tools", entities: dsl.tools },
55876
+ { name: "artifacts", entities: dsl.artifacts }
55877
+ ];
55878
+ const scopeBindings = {
55879
+ agents: /* @__PURE__ */ new Set(),
55880
+ tasks: /* @__PURE__ */ new Set(),
55881
+ tools: /* @__PURE__ */ new Set(),
55882
+ artifacts: /* @__PURE__ */ new Set()
55883
+ };
55884
+ for (const guardrail of Object.values(dsl.guardrails)) {
55885
+ for (const key of Object.keys(scopeBindings)) {
55886
+ const ids = guardrail.scope[key];
55887
+ if (ids) {
55888
+ for (const id of ids) scopeBindings[key].add(id);
55889
+ }
55890
+ }
55891
+ }
55892
+ let total = 0;
55893
+ let covered = 0;
55894
+ const missing = [];
55895
+ for (const { name, entities } of entitySections) {
55896
+ for (const [entityId, entity] of Object.entries(entities)) {
55897
+ total++;
55898
+ const hasEntitySide = (entity.guardrails ?? []).length > 0;
55899
+ const hasScopeSide = scopeBindings[name].has(entityId);
55900
+ if (hasEntitySide || hasScopeSide) {
55901
+ covered++;
55902
+ } else {
55903
+ missing.push(`${name}.${entityId}`);
55904
+ }
55905
+ }
55906
+ }
55907
+ return {
55908
+ id: "entity-guardrail-coverage",
55909
+ label: "Entity guardrail coverage",
55910
+ score: covered,
55911
+ total,
55912
+ percent: pct(covered, total),
55913
+ weight: 1,
55914
+ recommendations: missing.length > 0 ? [`${missing.length} entities without guardrails: ${missing.slice(0, 5).join(", ")}${missing.length > 5 ? `, ... (${missing.length - 5} more)` : ""}`] : []
55915
+ };
55916
+ }
55670
55917
  function guardrailScopeResolution(dsl) {
55671
55918
  let totalRefs = 0;
55672
55919
  let resolvedRefs = 0;
@@ -55712,7 +55959,8 @@ function score(dsl) {
55712
55959
  workflowValidationIntegration(dsl),
55713
55960
  schemaCompleteness(dsl),
55714
55961
  crossReferenceBidirectionality(dsl),
55715
- guardrailScopeResolution(dsl)
55962
+ guardrailScopeResolution(dsl),
55963
+ entityGuardrailCoverage(dsl)
55716
55964
  ];
55717
55965
  const totalWeight = dimensions.reduce((s2, d2) => s2 + d2.weight, 0);
55718
55966
  const weightedSum = dimensions.reduce(