@mnemom/agent-alignment-protocol 0.6.0 → 0.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -747,6 +747,13 @@ function hasRoleKeyword(agentId) {
747
747
  const lower = agentId.toLowerCase();
748
748
  return ROLE_KEYWORDS.some((kw) => lower.includes(kw));
749
749
  }
750
+ function getClpiRole(card) {
751
+ const ext = card.extensions;
752
+ if (!ext) return null;
753
+ const clpi = ext["clpi"];
754
+ if (!clpi || typeof clpi["role"] !== "string") return null;
755
+ return clpi["role"] || null;
756
+ }
750
757
  function analyzeFaultLines(coherenceResult, cards, options) {
751
758
  const reputationScores = options?.reputationScores;
752
759
  const agentBoundedActions = /* @__PURE__ */ new Map();
@@ -757,6 +764,10 @@ function analyzeFaultLines(coherenceResult, cards, options) {
757
764
  for (const { agentId, card } of cards) {
758
765
  agentConflictMap.set(agentId, new Set(card.values.conflicts_with ?? []));
759
766
  }
767
+ const agentRoleMap = /* @__PURE__ */ new Map();
768
+ for (const { agentId, card } of cards) {
769
+ agentRoleMap.set(agentId, getClpiRole(card));
770
+ }
760
771
  const faultLines = [];
761
772
  for (const divergence of coherenceResult.divergence_report) {
762
773
  const {
@@ -789,6 +800,13 @@ function analyzeFaultLines(coherenceResult, cards, options) {
789
800
  })()) {
790
801
  classification = "priority_mismatch";
791
802
  } else if (agents_declaring.length >= 1 && agents_missing.length >= 1 && (() => {
803
+ const declaringRoles = new Set(agents_declaring.map((id2) => agentRoleMap.get(id2) ?? null).filter(Boolean));
804
+ const missingRoles = new Set(agents_missing.map((id2) => agentRoleMap.get(id2) ?? null).filter(Boolean));
805
+ if (declaringRoles.size > 0) {
806
+ const declaringRoleArr = [...declaringRoles];
807
+ const isRoleExclusive = declaringRoleArr.every((role) => !missingRoles.has(role));
808
+ if (isRoleExclusive) return true;
809
+ }
792
810
  const allInvolved = [...agents_declaring, ...agents_missing];
793
811
  return allInvolved.some((id2) => hasRoleKeyword(id2));
794
812
  })()) {
package/dist/index.mjs CHANGED
@@ -690,6 +690,13 @@ function hasRoleKeyword(agentId) {
690
690
  const lower = agentId.toLowerCase();
691
691
  return ROLE_KEYWORDS.some((kw) => lower.includes(kw));
692
692
  }
693
+ function getClpiRole(card) {
694
+ const ext = card.extensions;
695
+ if (!ext) return null;
696
+ const clpi = ext["clpi"];
697
+ if (!clpi || typeof clpi["role"] !== "string") return null;
698
+ return clpi["role"] || null;
699
+ }
693
700
  function analyzeFaultLines(coherenceResult, cards, options) {
694
701
  const reputationScores = options?.reputationScores;
695
702
  const agentBoundedActions = /* @__PURE__ */ new Map();
@@ -700,6 +707,10 @@ function analyzeFaultLines(coherenceResult, cards, options) {
700
707
  for (const { agentId, card } of cards) {
701
708
  agentConflictMap.set(agentId, new Set(card.values.conflicts_with ?? []));
702
709
  }
710
+ const agentRoleMap = /* @__PURE__ */ new Map();
711
+ for (const { agentId, card } of cards) {
712
+ agentRoleMap.set(agentId, getClpiRole(card));
713
+ }
703
714
  const faultLines = [];
704
715
  for (const divergence of coherenceResult.divergence_report) {
705
716
  const {
@@ -732,6 +743,13 @@ function analyzeFaultLines(coherenceResult, cards, options) {
732
743
  })()) {
733
744
  classification = "priority_mismatch";
734
745
  } else if (agents_declaring.length >= 1 && agents_missing.length >= 1 && (() => {
746
+ const declaringRoles = new Set(agents_declaring.map((id2) => agentRoleMap.get(id2) ?? null).filter(Boolean));
747
+ const missingRoles = new Set(agents_missing.map((id2) => agentRoleMap.get(id2) ?? null).filter(Boolean));
748
+ if (declaringRoles.size > 0) {
749
+ const declaringRoleArr = [...declaringRoles];
750
+ const isRoleExclusive = declaringRoleArr.every((role) => !missingRoles.has(role));
751
+ if (isRoleExclusive) return true;
752
+ }
735
753
  const allInvolved = [...agents_declaring, ...agents_missing];
736
754
  return allInvolved.some((id2) => hasRoleKeyword(id2));
737
755
  })()) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mnemom/agent-alignment-protocol",
3
- "version": "0.6.0",
3
+ "version": "0.6.1",
4
4
  "description": "Agent Alignment Protocol (AAP) - Verification and drift detection for AI agents",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
@@ -54,4 +54,4 @@
54
54
  "engines": {
55
55
  "node": ">=18.0.0"
56
56
  }
57
- }
57
+ }
@@ -788,6 +788,15 @@ function hasRoleKeyword(agentId: string): boolean {
788
788
  return ROLE_KEYWORDS.some(kw => lower.includes(kw));
789
789
  }
790
790
 
791
+ /** Extract the CLPI role from a card's extensions, if present. */
792
+ function getClpiRole(card: AlignmentCard): string | null {
793
+ const ext = (card as unknown as { extensions?: Record<string, unknown> }).extensions;
794
+ if (!ext) return null;
795
+ const clpi = ext['clpi'] as Record<string, unknown> | undefined;
796
+ if (!clpi || typeof clpi['role'] !== 'string') return null;
797
+ return clpi['role'] || null;
798
+ }
799
+
791
800
  /**
792
801
  * Analyze fault lines in a fleet based on a FleetCoherenceResult.
793
802
  *
@@ -815,6 +824,12 @@ export function analyzeFaultLines(
815
824
  agentConflictMap.set(agentId, new Set(card.values.conflicts_with ?? []));
816
825
  }
817
826
 
827
+ // Build lookup: agentId → CLPI role (from extensions.clpi.role)
828
+ const agentRoleMap = new Map<string, string | null>();
829
+ for (const { agentId, card } of cards) {
830
+ agentRoleMap.set(agentId, getClpiRole(card));
831
+ }
832
+
818
833
  const faultLines: FaultLine[] = [];
819
834
 
820
835
  for (const divergence of coherenceResult.divergence_report) {
@@ -863,7 +878,18 @@ export function analyzeFaultLines(
863
878
  agents_declaring.length >= 1 &&
864
879
  agents_missing.length >= 1 &&
865
880
  (() => {
866
- // complementary: heuristic — some agent (declaring or missing) has a role keyword
881
+ // complementary: the declaring agents all share a CLPI role that the missing
882
+ // agents do NOT share — indicating intentional role specialization, not a gap.
883
+ // Primary check: extensions.clpi.role (authoritative)
884
+ const declaringRoles = new Set(agents_declaring.map(id => agentRoleMap.get(id) ?? null).filter(Boolean));
885
+ const missingRoles = new Set(agents_missing.map(id => agentRoleMap.get(id) ?? null).filter(Boolean));
886
+ if (declaringRoles.size > 0) {
887
+ // All declaring agents share a role that none of the missing agents have
888
+ const declaringRoleArr = [...declaringRoles];
889
+ const isRoleExclusive = declaringRoleArr.every(role => !missingRoles.has(role));
890
+ if (isRoleExclusive) return true;
891
+ }
892
+ // Fallback: agent ID contains a role keyword (original heuristic)
867
893
  const allInvolved = [...agents_declaring, ...agents_missing];
868
894
  return allInvolved.some(id => hasRoleKeyword(id));
869
895
  })()