@holoscript/framework 6.0.3 → 6.0.4
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/CHANGELOG.md +1 -2
- package/ROADMAP.md +68 -66
- package/dist/{InvisibleWallet-BB6tFvRA.d.cts → InvisibleWallet-EFiuaLn3.d.cts} +1 -1
- package/dist/{OrchestratorAgent-BvWgf9uw.d.cts → OrchestratorAgent-CrLDGNL6.d.cts} +1 -1
- package/dist/agents/index.cjs +11 -10
- package/dist/agents/index.d.cts +4 -16
- package/dist/ai/index.cjs +2 -2
- package/dist/behavior.cjs +10 -0
- package/dist/economy/index.cjs +4 -4
- package/dist/economy/index.d.cts +2 -2
- package/dist/index.cjs +33 -11
- package/dist/index.d.cts +3 -3
- package/dist/swarm/index.cjs +3 -0
- package/package.json +14 -9
- package/src/__tests__/bounty-marketplace.test.ts +53 -21
- package/src/__tests__/delegation.test.ts +1 -4
- package/src/__tests__/done-log-audit.test.ts +38 -46
- package/src/__tests__/framework.test.ts +172 -53
- package/src/__tests__/goal-synthesizer.test.ts +9 -6
- package/src/__tests__/presence.test.ts +1 -1
- package/src/__tests__/protocol-agent.test.ts +12 -11
- package/src/__tests__/revenue-splitter.test.ts +22 -15
- package/src/__tests__/scenario-driven-todo.test.ts +55 -35
- package/src/__tests__/self-improve.test.ts +28 -9
- package/src/__tests__/service-lifecycle.test.ts +9 -3
- package/src/__tests__/skill-router.test.ts +3 -3
- package/src/agents/CulturalMemory.ts +6 -6
- package/src/agents/DelegationTraceHooks.ts +560 -0
- package/src/agents/FederatedRegistryAdapter.ts +1 -1
- package/src/agents/NormEngine.ts +3 -8
- package/src/agents/OrchestratorAgent.ts +1 -1
- package/src/agents/TaskDelegationService.ts +5 -9
- package/src/agents/__tests__/AgentWalletRegistry.test.ts +5 -4
- package/src/agents/__tests__/CrossRealityHandoff.test.ts +9 -3
- package/src/agents/__tests__/DelegationTraceHooks.test.ts +390 -0
- package/src/agents/__tests__/TaskDelegationService.test.ts +4 -2
- package/src/agents/spatial-comms/Layer1RealTime.ts +36 -19
- package/src/agents/spatial-comms/Layer2A2A.ts +1 -3
- package/src/agents/spatial-comms/Layer3MCP.ts +13 -4
- package/src/agents/spatial-comms/ProtocolTypes.ts +5 -2
- package/src/agents/spatial-comms/examples/multi-agent-world-creation.ts +2 -2
- package/src/ai/HoloScriptGenerator.ts +2 -2
- package/src/ai/__tests__/PerceptionSystem.prod.test.ts +1 -1
- package/src/ai/__tests__/PerceptionSystem.test.ts +14 -14
- package/src/ai/__tests__/SteeringBehaviors.prod.test.ts +1 -1
- package/src/ai/index.ts +5 -1
- package/src/board/audit.ts +17 -6
- package/src/board/board-ops.ts +45 -15
- package/src/board/board-types.ts +94 -20
- package/src/delegation.ts +5 -3
- package/src/distributed-claimer.ts +13 -2
- package/src/economy/BountyManager.ts +40 -18
- package/src/economy/KnowledgeMarketplace.ts +27 -8
- package/src/economy/PaymentWebhookService.ts +0 -1
- package/src/economy/RevenueSplitter.ts +2 -4
- package/src/economy/UnifiedBudgetOptimizer.ts +8 -9
- package/src/economy/_core-stubs.ts +1 -1
- package/src/economy/x402-facilitator.ts +17 -8
- package/src/index.ts +16 -12
- package/src/knowledge/__tests__/knowledge-consolidator.test.ts +138 -89
- package/src/knowledge/__tests__/knowledge-store-vector.test.ts +59 -16
- package/src/knowledge/brain.ts +7 -7
- package/src/knowledge/consolidation.ts +16 -16
- package/src/knowledge/knowledge-consolidator.ts +60 -30
- package/src/knowledge/knowledge-store.ts +83 -45
- package/src/learning/ProceduralCompiler.ts +6 -1
- package/src/learning/learning/MemoryConsolidator.ts +102 -0
- package/src/learning/learning/MemoryScorer.ts +69 -0
- package/src/learning/learning/ProceduralCompiler.ts +45 -0
- package/src/learning/learning/SemanticClusterer.ts +66 -0
- package/src/llm/llm-adapter.ts +24 -10
- package/src/mesh/index.ts +37 -17
- package/src/protocol/goal-synthesizer.ts +24 -34
- package/src/protocol/implementations.ts +91 -22
- package/src/protocol/micro-phase-decomposer.ts +25 -17
- package/src/protocol/micro-step-decomposer.test.ts +104 -39
- package/src/protocol-agent.test.ts +17 -7
- package/src/protocol-agent.ts +45 -42
- package/src/self-improve/absorb-scanner.ts +9 -6
- package/src/self-improve/evolution-engine.ts +36 -18
- package/src/self-improve/framework-absorber.ts +21 -16
- package/src/self-improve/index.ts +2 -10
- package/src/self-improve/prompt-optimizer.ts +31 -19
- package/src/self-improve/test-generator.ts +16 -12
- package/src/skill-router.ts +7 -6
- package/src/swarm/messaging/GossipProtocol.ts +1 -1
- package/src/swarm/messaging/__tests__/BroadcastChannel.prod.test.ts +31 -9
- package/src/swarm/messaging/__tests__/GossipProtocol.prod.test.ts +21 -7
- package/src/swarm/messaging/__tests__/SwarmEventBus.prod.test.ts +24 -8
- package/src/swarm/messaging/__tests__/SwarmEventBus.test.ts +6 -2
- package/src/team.ts +277 -122
- package/src/training/scripts/generate-spatial-dataset.ts +1 -1
- package/src/training/training/LRScheduler.ts +377 -0
- package/src/training/training/QualityScoringPipeline.ts +139 -0
- package/src/training/training/SoftDedup.ts +461 -0
- package/src/training/training/SparsityMonitor.ts +685 -0
- package/src/training/training/SparsityMonitorTypes.ts +209 -0
- package/src/training/training/SpatialTrainingDataGenerator.ts +1526 -0
- package/src/training/training/SpatialTrainingDataTypes.ts +216 -0
- package/src/training/training/TrainingPipelineConfig.ts +215 -0
- package/src/training/training/__tests__/CorpusValidation.test.ts +87 -0
- package/src/training/training/__tests__/LRScheduler.test.ts +592 -0
- package/src/training/training/__tests__/SoftDedup.test.ts +415 -0
- package/src/training/training/__tests__/SparsityMonitor.test.ts +1623 -0
- package/src/training/training/__tests__/SpatialCorpusValidation.test.ts +72 -0
- package/src/training/training/__tests__/SpatialTrainingDataGenerator.test.ts +1244 -0
- package/src/training/training/__tests__/TrainingMonkeyIntegration.test.ts +897 -0
- package/src/training/training/__tests__/TrainingPipelineConfig.test.ts +202 -0
- package/src/training/training/__tests__/schema.test.ts +72 -0
- package/src/training/training/__tests__/training-constants.test.ts +106 -0
- package/src/training/training/__tests__/trait-mappings.test.ts +81 -0
- package/src/training/training/constants.ts +94 -0
- package/src/training/training/index.ts +17 -0
- package/src/training/training/schema.ts +147 -0
- package/src/training/training/scripts/generate-novel-use-cases-dataset.ts +272 -0
- package/src/training/training/scripts/generate-spatial-dataset.ts +521 -0
- package/src/training/training/trainingmonkey/TrainingMonkeyIntegration.ts +477 -0
- package/src/training/training/trainingmonkey/TrainingMonkeyTypes.ts +230 -0
- package/src/training/training/trainingmonkey/index.ts +26 -0
- package/src/training/training/trait-mappings.ts +157 -0
- package/src/types.ts +2 -7
- package/ALL-test-results.json +0 -1
- package/LICENSE +0 -21
- package/dist/AgentManifest-CB4xM-Ma.d.ts +0 -704
- package/dist/BehaviorTree-BrBFECv5.d.ts +0 -103
- package/dist/InvisibleWallet-rtRrBOA8.d.ts +0 -1732
- package/dist/OrchestratorAgent-Q_CbVTmO.d.ts +0 -798
- package/dist/agents/index.d.ts +0 -1788
- package/dist/agents/index.js +0 -4695
- package/dist/ai/index.d.ts +0 -1753
- package/dist/ai/index.js +0 -5244
- package/dist/behavior.d.ts +0 -130
- package/dist/behavior.js +0 -407
- package/dist/economy/index.d.ts +0 -747
- package/dist/economy/index.js +0 -3617
- package/dist/implementations-D9T3un9D.d.ts +0 -236
- package/dist/index.d.ts +0 -1729
- package/dist/index.js +0 -24277
- package/dist/learning/index.d.ts +0 -104
- package/dist/learning/index.js +0 -189
- package/dist/negotiation/index.d.ts +0 -610
- package/dist/negotiation/index.js +0 -931
- package/dist/skills/index.d.ts +0 -289
- package/dist/skills/index.js +0 -1079
- package/dist/swarm/index.d.ts +0 -2433
- package/dist/swarm/index.js +0 -5221
- package/dist/training/index.d.ts +0 -1734
- package/dist/training/index.js +0 -2687
- package/extract-failures.js +0 -10
- package/src/training/training/data/novel-use-cases.jsonl +0 -153
- package/src/training/training/data/spatial-reasoning-10k.jsonl +0 -9354
- package/src/types/core-stubs.d.ts +0 -113
- package/test-output.txt +0 -0
- package/test-result.json +0 -1
- package/tsc-errors.txt +0 -4
- package/tsc_output.txt +0 -0
- package/typescript-errors-2.txt +0 -0
- package/typescript-errors.txt +0 -22
- package/vitest-log-utf8.txt +0 -268
- package/vitest-log.txt +0 -0
|
@@ -1,931 +0,0 @@
|
|
|
1
|
-
// src/negotiation/VotingMechanisms.ts
|
|
2
|
-
function getTotalWeight(votes) {
|
|
3
|
-
return votes.reduce((sum, v) => sum + v.weight, 0);
|
|
4
|
-
}
|
|
5
|
-
function initializeTallies(proposals) {
|
|
6
|
-
const tallies = /* @__PURE__ */ new Map();
|
|
7
|
-
for (const p of proposals) {
|
|
8
|
-
tallies.set(p.id, {
|
|
9
|
-
proposalId: p.id,
|
|
10
|
-
voteCount: 0,
|
|
11
|
-
weightedScore: 0,
|
|
12
|
-
approvalCount: 0,
|
|
13
|
-
bordaPoints: 0,
|
|
14
|
-
percentage: 0
|
|
15
|
-
});
|
|
16
|
-
}
|
|
17
|
-
return tallies;
|
|
18
|
-
}
|
|
19
|
-
function talliesToArray(tallies, totalWeight) {
|
|
20
|
-
const arr = Array.from(tallies.values());
|
|
21
|
-
for (const t of arr) {
|
|
22
|
-
t.percentage = totalWeight > 0 ? t.weightedScore / totalWeight * 100 : 0;
|
|
23
|
-
}
|
|
24
|
-
return arr.sort((a, b) => b.weightedScore - a.weightedScore);
|
|
25
|
-
}
|
|
26
|
-
function findTies(tallies) {
|
|
27
|
-
if (tallies.length < 2) return [];
|
|
28
|
-
const topScore = tallies[0].weightedScore;
|
|
29
|
-
return tallies.filter((t) => t.weightedScore === topScore);
|
|
30
|
-
}
|
|
31
|
-
function breakTie(tied, proposals, config) {
|
|
32
|
-
if (tied.length === 0) return void 0;
|
|
33
|
-
if (tied.length === 1) return tied[0].proposalId;
|
|
34
|
-
switch (config.tieBreaker) {
|
|
35
|
-
case "random":
|
|
36
|
-
return tied[Math.floor(Math.random() * tied.length)].proposalId;
|
|
37
|
-
case "seniority": {
|
|
38
|
-
const proposalMap = new Map(proposals.map((p) => [p.id, p]));
|
|
39
|
-
const sorted = [...tied].sort((a, b) => {
|
|
40
|
-
const pa = proposalMap.get(a.proposalId);
|
|
41
|
-
const pb = proposalMap.get(b.proposalId);
|
|
42
|
-
return (pa?.submittedAt || 0) - (pb?.submittedAt || 0);
|
|
43
|
-
});
|
|
44
|
-
return sorted[0].proposalId;
|
|
45
|
-
}
|
|
46
|
-
case "priority": {
|
|
47
|
-
const proposalMap = new Map(proposals.map((p) => [p.id, p]));
|
|
48
|
-
const sorted = [...tied].sort((a, b) => {
|
|
49
|
-
const pa = proposalMap.get(a.proposalId);
|
|
50
|
-
const pb = proposalMap.get(b.proposalId);
|
|
51
|
-
return (pb?.priority || 0) - (pa?.priority || 0);
|
|
52
|
-
});
|
|
53
|
-
return sorted[0].proposalId;
|
|
54
|
-
}
|
|
55
|
-
case "proposer":
|
|
56
|
-
return tied[0].proposalId;
|
|
57
|
-
case "escalate":
|
|
58
|
-
default:
|
|
59
|
-
return void 0;
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
var majorityHandler = {
|
|
63
|
-
count(votes, proposals, config, _round) {
|
|
64
|
-
const tallies = initializeTallies(proposals);
|
|
65
|
-
const totalWeight = getTotalWeight(votes);
|
|
66
|
-
for (const vote of votes) {
|
|
67
|
-
if (vote.ranking.length > 0) {
|
|
68
|
-
const firstChoice = vote.ranking[0];
|
|
69
|
-
const tally = tallies.get(firstChoice);
|
|
70
|
-
if (tally) {
|
|
71
|
-
tally.voteCount++;
|
|
72
|
-
tally.weightedScore += vote.weight;
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
const sorted = talliesToArray(tallies, totalWeight);
|
|
77
|
-
const ties = findTies(sorted);
|
|
78
|
-
if (sorted.length > 0 && sorted[0].percentage > 50) {
|
|
79
|
-
return {
|
|
80
|
-
tallies: sorted,
|
|
81
|
-
winnerId: sorted[0].proposalId,
|
|
82
|
-
resolved: true,
|
|
83
|
-
outcome: "winner_declared",
|
|
84
|
-
consensusLevel: sorted[0].percentage / 100
|
|
85
|
-
};
|
|
86
|
-
}
|
|
87
|
-
if (ties.length > 1) {
|
|
88
|
-
const tieBreakWinner = breakTie(ties, proposals, config);
|
|
89
|
-
if (tieBreakWinner) {
|
|
90
|
-
return {
|
|
91
|
-
tallies: sorted,
|
|
92
|
-
winnerId: tieBreakWinner,
|
|
93
|
-
resolved: true,
|
|
94
|
-
outcome: "tie_broken",
|
|
95
|
-
tie: true
|
|
96
|
-
};
|
|
97
|
-
}
|
|
98
|
-
return {
|
|
99
|
-
tallies: sorted,
|
|
100
|
-
resolved: false,
|
|
101
|
-
outcome: "deadlock",
|
|
102
|
-
tie: true
|
|
103
|
-
};
|
|
104
|
-
}
|
|
105
|
-
if (sorted.length > 0) {
|
|
106
|
-
return {
|
|
107
|
-
tallies: sorted,
|
|
108
|
-
winnerId: sorted[0].proposalId,
|
|
109
|
-
resolved: true,
|
|
110
|
-
outcome: "winner_declared",
|
|
111
|
-
consensusLevel: sorted[0].percentage / 100
|
|
112
|
-
};
|
|
113
|
-
}
|
|
114
|
-
return {
|
|
115
|
-
tallies: sorted,
|
|
116
|
-
resolved: false,
|
|
117
|
-
outcome: "deadlock"
|
|
118
|
-
};
|
|
119
|
-
},
|
|
120
|
-
validateVote(vote, proposals) {
|
|
121
|
-
if (vote.ranking.length === 0) return false;
|
|
122
|
-
const proposalIds = new Set(proposals.map((p) => p.id));
|
|
123
|
-
return proposalIds.has(vote.ranking[0]);
|
|
124
|
-
},
|
|
125
|
-
getRequiredQuorum(config) {
|
|
126
|
-
return config.quorum || 0.5;
|
|
127
|
-
}
|
|
128
|
-
};
|
|
129
|
-
var supermajorityHandler = {
|
|
130
|
-
count(votes, proposals, _config, _round) {
|
|
131
|
-
const tallies = initializeTallies(proposals);
|
|
132
|
-
const totalWeight = getTotalWeight(votes);
|
|
133
|
-
for (const vote of votes) {
|
|
134
|
-
if (vote.ranking.length > 0) {
|
|
135
|
-
const firstChoice = vote.ranking[0];
|
|
136
|
-
const tally = tallies.get(firstChoice);
|
|
137
|
-
if (tally) {
|
|
138
|
-
tally.voteCount++;
|
|
139
|
-
tally.weightedScore += vote.weight;
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
const sorted = talliesToArray(tallies, totalWeight);
|
|
144
|
-
const threshold = 66.67;
|
|
145
|
-
if (sorted.length > 0 && sorted[0].percentage >= threshold) {
|
|
146
|
-
return {
|
|
147
|
-
tallies: sorted,
|
|
148
|
-
winnerId: sorted[0].proposalId,
|
|
149
|
-
resolved: true,
|
|
150
|
-
outcome: "winner_declared",
|
|
151
|
-
consensusLevel: sorted[0].percentage / 100
|
|
152
|
-
};
|
|
153
|
-
}
|
|
154
|
-
return {
|
|
155
|
-
tallies: sorted,
|
|
156
|
-
resolved: false,
|
|
157
|
-
outcome: "deadlock"
|
|
158
|
-
};
|
|
159
|
-
},
|
|
160
|
-
validateVote(vote, proposals) {
|
|
161
|
-
return majorityHandler.validateVote(vote, proposals);
|
|
162
|
-
},
|
|
163
|
-
getRequiredQuorum(config) {
|
|
164
|
-
return config.quorum || 0.67;
|
|
165
|
-
}
|
|
166
|
-
};
|
|
167
|
-
var weightedHandler = {
|
|
168
|
-
count(votes, proposals, config, round) {
|
|
169
|
-
return majorityHandler.count(votes, proposals, config, round);
|
|
170
|
-
},
|
|
171
|
-
validateVote(vote, proposals) {
|
|
172
|
-
return majorityHandler.validateVote(vote, proposals);
|
|
173
|
-
},
|
|
174
|
-
getRequiredQuorum(config) {
|
|
175
|
-
return config.quorum || 0.5;
|
|
176
|
-
}
|
|
177
|
-
};
|
|
178
|
-
var consensusHandler = {
|
|
179
|
-
count(votes, proposals, _config, _round) {
|
|
180
|
-
if (votes.length === 0) {
|
|
181
|
-
return {
|
|
182
|
-
tallies: [],
|
|
183
|
-
resolved: false,
|
|
184
|
-
outcome: "deadlock"
|
|
185
|
-
};
|
|
186
|
-
}
|
|
187
|
-
const tallies = initializeTallies(proposals);
|
|
188
|
-
const totalWeight = getTotalWeight(votes);
|
|
189
|
-
const firstChoices = /* @__PURE__ */ new Map();
|
|
190
|
-
for (const vote of votes) {
|
|
191
|
-
if (vote.ranking.length > 0) {
|
|
192
|
-
const choice = vote.ranking[0];
|
|
193
|
-
const tally = tallies.get(choice);
|
|
194
|
-
if (tally) {
|
|
195
|
-
tally.voteCount++;
|
|
196
|
-
tally.weightedScore += vote.weight;
|
|
197
|
-
}
|
|
198
|
-
if (!firstChoices.has(choice)) {
|
|
199
|
-
firstChoices.set(choice, []);
|
|
200
|
-
}
|
|
201
|
-
firstChoices.get(choice).push(vote.agentId);
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
const sorted = talliesToArray(tallies, totalWeight);
|
|
205
|
-
if (firstChoices.size === 1) {
|
|
206
|
-
const winnerId = Array.from(firstChoices.keys())[0];
|
|
207
|
-
return {
|
|
208
|
-
tallies: sorted,
|
|
209
|
-
winnerId,
|
|
210
|
-
resolved: true,
|
|
211
|
-
outcome: "consensus_reached",
|
|
212
|
-
consensusLevel: 1
|
|
213
|
-
};
|
|
214
|
-
}
|
|
215
|
-
const leader = sorted[0];
|
|
216
|
-
const leaderVoters = new Set(firstChoices.get(leader.proposalId) || []);
|
|
217
|
-
const dissenters = votes.filter((v) => !leaderVoters.has(v.agentId)).map((v) => v.agentId);
|
|
218
|
-
return {
|
|
219
|
-
tallies: sorted,
|
|
220
|
-
resolved: false,
|
|
221
|
-
outcome: "deadlock",
|
|
222
|
-
consensusLevel: leader.percentage / 100,
|
|
223
|
-
dissenters
|
|
224
|
-
};
|
|
225
|
-
},
|
|
226
|
-
validateVote(vote, proposals) {
|
|
227
|
-
return majorityHandler.validateVote(vote, proposals);
|
|
228
|
-
},
|
|
229
|
-
getRequiredQuorum() {
|
|
230
|
-
return 1;
|
|
231
|
-
}
|
|
232
|
-
};
|
|
233
|
-
var rankedHandler = {
|
|
234
|
-
count(votes, proposals, _config, _round) {
|
|
235
|
-
const eliminated = /* @__PURE__ */ new Set();
|
|
236
|
-
const runoffVotes = votes.map((v) => ({
|
|
237
|
-
...v,
|
|
238
|
-
currentRanking: [...v.ranking]
|
|
239
|
-
}));
|
|
240
|
-
const totalWeight = getTotalWeight(votes);
|
|
241
|
-
let rounds = 0;
|
|
242
|
-
const maxRounds = proposals.length;
|
|
243
|
-
while (rounds < maxRounds) {
|
|
244
|
-
rounds++;
|
|
245
|
-
const tallies = initializeTallies(proposals.filter((p) => !eliminated.has(p.id)));
|
|
246
|
-
for (const vote of runoffVotes) {
|
|
247
|
-
const validChoice = vote.currentRanking.find((id) => !eliminated.has(id));
|
|
248
|
-
if (validChoice) {
|
|
249
|
-
const tally = tallies.get(validChoice);
|
|
250
|
-
if (tally) {
|
|
251
|
-
tally.voteCount++;
|
|
252
|
-
tally.weightedScore += vote.weight;
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
|
-
const sorted = talliesToArray(tallies, totalWeight);
|
|
257
|
-
if (sorted.length > 0 && sorted[0].percentage > 50) {
|
|
258
|
-
return {
|
|
259
|
-
tallies: sorted,
|
|
260
|
-
winnerId: sorted[0].proposalId,
|
|
261
|
-
resolved: true,
|
|
262
|
-
outcome: "winner_declared",
|
|
263
|
-
eliminated: Array.from(eliminated),
|
|
264
|
-
consensusLevel: sorted[0].percentage / 100
|
|
265
|
-
};
|
|
266
|
-
}
|
|
267
|
-
if (sorted.length > 1) {
|
|
268
|
-
const loser = sorted[sorted.length - 1];
|
|
269
|
-
eliminated.add(loser.proposalId);
|
|
270
|
-
} else if (sorted.length === 1) {
|
|
271
|
-
return {
|
|
272
|
-
tallies: sorted,
|
|
273
|
-
winnerId: sorted[0].proposalId,
|
|
274
|
-
resolved: true,
|
|
275
|
-
outcome: "winner_declared",
|
|
276
|
-
eliminated: Array.from(eliminated)
|
|
277
|
-
};
|
|
278
|
-
} else {
|
|
279
|
-
break;
|
|
280
|
-
}
|
|
281
|
-
}
|
|
282
|
-
return {
|
|
283
|
-
tallies: [],
|
|
284
|
-
resolved: false,
|
|
285
|
-
outcome: "deadlock",
|
|
286
|
-
eliminated: Array.from(eliminated)
|
|
287
|
-
};
|
|
288
|
-
},
|
|
289
|
-
validateVote(vote, proposals) {
|
|
290
|
-
if (vote.ranking.length === 0) return false;
|
|
291
|
-
const proposalIds = new Set(proposals.map((p) => p.id));
|
|
292
|
-
return vote.ranking.every((id) => proposalIds.has(id));
|
|
293
|
-
},
|
|
294
|
-
getRequiredQuorum(config) {
|
|
295
|
-
return config.quorum || 0.5;
|
|
296
|
-
}
|
|
297
|
-
};
|
|
298
|
-
var approvalHandler = {
|
|
299
|
-
count(votes, proposals, config, _round) {
|
|
300
|
-
const tallies = initializeTallies(proposals);
|
|
301
|
-
const totalVotes = votes.length;
|
|
302
|
-
for (const vote of votes) {
|
|
303
|
-
const approvals = vote.approvals || vote.ranking;
|
|
304
|
-
for (const proposalId of approvals) {
|
|
305
|
-
const tally = tallies.get(proposalId);
|
|
306
|
-
if (tally) {
|
|
307
|
-
tally.voteCount++;
|
|
308
|
-
tally.weightedScore += vote.weight;
|
|
309
|
-
tally.approvalCount = (tally.approvalCount || 0) + 1;
|
|
310
|
-
}
|
|
311
|
-
}
|
|
312
|
-
}
|
|
313
|
-
const sorted = talliesToArray(
|
|
314
|
-
tallies,
|
|
315
|
-
votes.reduce((s, v) => s + v.weight, 0)
|
|
316
|
-
);
|
|
317
|
-
const ties = findTies(sorted);
|
|
318
|
-
if (ties.length > 1) {
|
|
319
|
-
const tieBreakWinner = breakTie(ties, proposals, config);
|
|
320
|
-
if (tieBreakWinner) {
|
|
321
|
-
return {
|
|
322
|
-
tallies: sorted,
|
|
323
|
-
winnerId: tieBreakWinner,
|
|
324
|
-
resolved: true,
|
|
325
|
-
outcome: "tie_broken",
|
|
326
|
-
tie: true
|
|
327
|
-
};
|
|
328
|
-
}
|
|
329
|
-
}
|
|
330
|
-
if (sorted.length > 0) {
|
|
331
|
-
return {
|
|
332
|
-
tallies: sorted,
|
|
333
|
-
winnerId: sorted[0].proposalId,
|
|
334
|
-
resolved: true,
|
|
335
|
-
outcome: "winner_declared",
|
|
336
|
-
consensusLevel: totalVotes > 0 ? (sorted[0].approvalCount || 0) / totalVotes : 0
|
|
337
|
-
};
|
|
338
|
-
}
|
|
339
|
-
return {
|
|
340
|
-
tallies: sorted,
|
|
341
|
-
resolved: false,
|
|
342
|
-
outcome: "deadlock"
|
|
343
|
-
};
|
|
344
|
-
},
|
|
345
|
-
validateVote(vote, proposals) {
|
|
346
|
-
const approvals = vote.approvals || vote.ranking;
|
|
347
|
-
if (approvals.length === 0) return false;
|
|
348
|
-
const proposalIds = new Set(proposals.map((p) => p.id));
|
|
349
|
-
return approvals.every((id) => proposalIds.has(id));
|
|
350
|
-
},
|
|
351
|
-
getRequiredQuorum(config) {
|
|
352
|
-
return config.quorum || 0.5;
|
|
353
|
-
}
|
|
354
|
-
};
|
|
355
|
-
var bordaHandler = {
|
|
356
|
-
count(votes, proposals, config, _round) {
|
|
357
|
-
const tallies = initializeTallies(proposals);
|
|
358
|
-
const n = proposals.length;
|
|
359
|
-
for (const vote of votes) {
|
|
360
|
-
for (let i = 0; i < vote.ranking.length; i++) {
|
|
361
|
-
const proposalId = vote.ranking[i];
|
|
362
|
-
const tally = tallies.get(proposalId);
|
|
363
|
-
if (tally) {
|
|
364
|
-
const points = (n - 1 - i) * vote.weight;
|
|
365
|
-
tally.bordaPoints = (tally.bordaPoints || 0) + points;
|
|
366
|
-
tally.weightedScore += points;
|
|
367
|
-
tally.voteCount++;
|
|
368
|
-
}
|
|
369
|
-
}
|
|
370
|
-
}
|
|
371
|
-
const sorted = talliesToArray(tallies, n * votes.reduce((s, v) => s + v.weight, 0));
|
|
372
|
-
const ties = findTies(sorted);
|
|
373
|
-
if (ties.length > 1) {
|
|
374
|
-
const tieBreakWinner = breakTie(ties, proposals, config);
|
|
375
|
-
if (tieBreakWinner) {
|
|
376
|
-
return {
|
|
377
|
-
tallies: sorted,
|
|
378
|
-
winnerId: tieBreakWinner,
|
|
379
|
-
resolved: true,
|
|
380
|
-
outcome: "tie_broken",
|
|
381
|
-
tie: true
|
|
382
|
-
};
|
|
383
|
-
}
|
|
384
|
-
}
|
|
385
|
-
if (sorted.length > 0) {
|
|
386
|
-
return {
|
|
387
|
-
tallies: sorted,
|
|
388
|
-
winnerId: sorted[0].proposalId,
|
|
389
|
-
resolved: true,
|
|
390
|
-
outcome: "winner_declared"
|
|
391
|
-
};
|
|
392
|
-
}
|
|
393
|
-
return {
|
|
394
|
-
tallies: sorted,
|
|
395
|
-
resolved: false,
|
|
396
|
-
outcome: "deadlock"
|
|
397
|
-
};
|
|
398
|
-
},
|
|
399
|
-
validateVote(vote, proposals) {
|
|
400
|
-
return rankedHandler.validateVote(vote, proposals);
|
|
401
|
-
},
|
|
402
|
-
getRequiredQuorum(config) {
|
|
403
|
-
return config.quorum || 0.5;
|
|
404
|
-
}
|
|
405
|
-
};
|
|
406
|
-
function getVotingHandler(mechanism) {
|
|
407
|
-
switch (mechanism) {
|
|
408
|
-
case "majority":
|
|
409
|
-
return majorityHandler;
|
|
410
|
-
case "supermajority":
|
|
411
|
-
return supermajorityHandler;
|
|
412
|
-
case "weighted":
|
|
413
|
-
return weightedHandler;
|
|
414
|
-
case "consensus":
|
|
415
|
-
return consensusHandler;
|
|
416
|
-
case "ranked":
|
|
417
|
-
return rankedHandler;
|
|
418
|
-
case "approval":
|
|
419
|
-
return approvalHandler;
|
|
420
|
-
case "borda":
|
|
421
|
-
return bordaHandler;
|
|
422
|
-
case "custom":
|
|
423
|
-
default:
|
|
424
|
-
return majorityHandler;
|
|
425
|
-
}
|
|
426
|
-
}
|
|
427
|
-
function checkQuorum(votes, participants, config, mechanism) {
|
|
428
|
-
const handler = getVotingHandler(mechanism);
|
|
429
|
-
const requiredQuorum = handler.getRequiredQuorum(config);
|
|
430
|
-
const participation = participants > 0 ? votes.length / participants : 0;
|
|
431
|
-
return participation >= requiredQuorum;
|
|
432
|
-
}
|
|
433
|
-
function getTrustWeight(trustLevel) {
|
|
434
|
-
switch (trustLevel) {
|
|
435
|
-
case "local":
|
|
436
|
-
return 1;
|
|
437
|
-
case "verified":
|
|
438
|
-
return 0.8;
|
|
439
|
-
case "external":
|
|
440
|
-
return 0.5;
|
|
441
|
-
default:
|
|
442
|
-
return 0.5;
|
|
443
|
-
}
|
|
444
|
-
}
|
|
445
|
-
|
|
446
|
-
// src/negotiation/NegotiationProtocol.ts
|
|
447
|
-
var NegotiationProtocol = class {
|
|
448
|
-
sessions = /* @__PURE__ */ new Map();
|
|
449
|
-
auditLog = [];
|
|
450
|
-
deadlines = /* @__PURE__ */ new Map();
|
|
451
|
-
eventHandlers = /* @__PURE__ */ new Map();
|
|
452
|
-
sessionCounter = 0;
|
|
453
|
-
proposalCounter = 0;
|
|
454
|
-
voteCounter = 0;
|
|
455
|
-
// ===========================================================================
|
|
456
|
-
// PUBLIC API
|
|
457
|
-
// ===========================================================================
|
|
458
|
-
/**
|
|
459
|
-
* Initiate a new negotiation session
|
|
460
|
-
*/
|
|
461
|
-
async initiate(options) {
|
|
462
|
-
const sessionId = this.generateSessionId();
|
|
463
|
-
const timeout = options.timeout ?? 6e4;
|
|
464
|
-
const config = {
|
|
465
|
-
mechanism: options.votingMechanism || "majority",
|
|
466
|
-
votingMechanism: options.votingMechanism || "majority",
|
|
467
|
-
quorum: options.quorum ?? 0.5,
|
|
468
|
-
timeout,
|
|
469
|
-
votingDeadline: timeout,
|
|
470
|
-
proposalDeadline: timeout,
|
|
471
|
-
maxRounds: options.maxRounds ?? 3,
|
|
472
|
-
allowAbstain: options.allowAbstain ?? true,
|
|
473
|
-
requireJustification: options.requireJustification ?? false,
|
|
474
|
-
tieBreaker: options.tieBreaker ?? "random",
|
|
475
|
-
escalationPath: options.escalationPath
|
|
476
|
-
};
|
|
477
|
-
const now = Date.now();
|
|
478
|
-
const session = {
|
|
479
|
-
id: sessionId,
|
|
480
|
-
topic: options.topic,
|
|
481
|
-
description: options.description,
|
|
482
|
-
participants: [...options.participants],
|
|
483
|
-
status: "open",
|
|
484
|
-
proposals: [],
|
|
485
|
-
votes: [],
|
|
486
|
-
config,
|
|
487
|
-
round: 1,
|
|
488
|
-
currentRound: 1,
|
|
489
|
-
createdAt: now,
|
|
490
|
-
startedAt: now,
|
|
491
|
-
lastActivityAt: now,
|
|
492
|
-
deadline: now + timeout,
|
|
493
|
-
history: [],
|
|
494
|
-
metadata: options.metadata || {}
|
|
495
|
-
};
|
|
496
|
-
this.sessions.set(sessionId, session);
|
|
497
|
-
this.startDeadlineTimer(session);
|
|
498
|
-
this.audit("initiated", sessionId, void 0, {
|
|
499
|
-
topic: options.topic,
|
|
500
|
-
participants: options.participants,
|
|
501
|
-
config
|
|
502
|
-
});
|
|
503
|
-
await this.emit("sessionStarted", { session });
|
|
504
|
-
return session;
|
|
505
|
-
}
|
|
506
|
-
/**
|
|
507
|
-
* Submit a proposal to a session
|
|
508
|
-
*/
|
|
509
|
-
async propose(sessionId, input) {
|
|
510
|
-
const session = this.getSession(sessionId);
|
|
511
|
-
this.validateSessionOpen(session);
|
|
512
|
-
this.validateParticipant(session, input.proposerId);
|
|
513
|
-
const proposalId = this.generateProposalId();
|
|
514
|
-
const proposal = {
|
|
515
|
-
id: proposalId,
|
|
516
|
-
sessionId,
|
|
517
|
-
proposerId: input.proposerId,
|
|
518
|
-
agentId: input.proposerId,
|
|
519
|
-
title: input.title,
|
|
520
|
-
description: input.description,
|
|
521
|
-
content: input.content,
|
|
522
|
-
priority: input.priority ?? 0,
|
|
523
|
-
status: "submitted",
|
|
524
|
-
submittedAt: Date.now(),
|
|
525
|
-
metadata: input.metadata || {}
|
|
526
|
-
};
|
|
527
|
-
session.proposals.push(proposal);
|
|
528
|
-
session.lastActivityAt = Date.now();
|
|
529
|
-
this.audit("proposal_submitted", sessionId, input.proposerId, {
|
|
530
|
-
proposalId,
|
|
531
|
-
title: input.title
|
|
532
|
-
});
|
|
533
|
-
await this.emit("proposalSubmitted", { session, proposal });
|
|
534
|
-
return proposal;
|
|
535
|
-
}
|
|
536
|
-
/**
|
|
537
|
-
* Cast a vote in a session
|
|
538
|
-
*/
|
|
539
|
-
async vote(sessionId, input) {
|
|
540
|
-
const session = this.getSession(sessionId);
|
|
541
|
-
this.validateSessionOpen(session);
|
|
542
|
-
this.validateParticipant(session, input.agentId);
|
|
543
|
-
this.validateNotDuplicate(session, input.agentId);
|
|
544
|
-
const mechanism = session.config.mechanism || session.config.votingMechanism || "majority";
|
|
545
|
-
const handler = getVotingHandler(mechanism);
|
|
546
|
-
const vote = {
|
|
547
|
-
id: this.generateVoteId(),
|
|
548
|
-
sessionId,
|
|
549
|
-
agentId: input.agentId,
|
|
550
|
-
ranking: input.ranking || [],
|
|
551
|
-
approvals: input.approvals,
|
|
552
|
-
weight: input.weight ?? getTrustWeight("local"),
|
|
553
|
-
justification: input.justification,
|
|
554
|
-
abstain: input.abstain ?? false,
|
|
555
|
-
timestamp: Date.now()
|
|
556
|
-
};
|
|
557
|
-
if (!vote.abstain && !handler.validateVote(vote, session.proposals)) {
|
|
558
|
-
throw new Error(
|
|
559
|
-
`Invalid vote: ranking must reference valid proposal IDs for mechanism '${mechanism}'`
|
|
560
|
-
);
|
|
561
|
-
}
|
|
562
|
-
session.votes.push(vote);
|
|
563
|
-
this.audit("vote_cast", sessionId, input.agentId, {
|
|
564
|
-
voteId: vote.id,
|
|
565
|
-
abstain: vote.abstain
|
|
566
|
-
});
|
|
567
|
-
await this.emit("voteReceived", { session, vote });
|
|
568
|
-
if (this.allVotesCast(session)) {
|
|
569
|
-
await this.tryAutoResolve(session);
|
|
570
|
-
}
|
|
571
|
-
return vote;
|
|
572
|
-
}
|
|
573
|
-
/**
|
|
574
|
-
* Resolve a negotiation session
|
|
575
|
-
*/
|
|
576
|
-
async resolve(sessionId, force = false) {
|
|
577
|
-
const session = this.getSession(sessionId);
|
|
578
|
-
if (session.status !== "open" && session.status !== "voting") {
|
|
579
|
-
if (session.resolution) {
|
|
580
|
-
return session.resolution;
|
|
581
|
-
}
|
|
582
|
-
throw new Error(`Session ${sessionId} is ${session.status}, cannot resolve`);
|
|
583
|
-
}
|
|
584
|
-
const mechanism = session.config.mechanism || session.config.votingMechanism || "majority";
|
|
585
|
-
if (!force) {
|
|
586
|
-
const quorumMet = checkQuorum(
|
|
587
|
-
session.votes,
|
|
588
|
-
session.participants.length,
|
|
589
|
-
session.config,
|
|
590
|
-
mechanism
|
|
591
|
-
);
|
|
592
|
-
if (!quorumMet) {
|
|
593
|
-
return this.createFailedResolution(session, "quorum_not_met");
|
|
594
|
-
}
|
|
595
|
-
}
|
|
596
|
-
const handler = getVotingHandler(mechanism);
|
|
597
|
-
const result = handler.count(
|
|
598
|
-
session.votes.filter((v) => !v.abstain),
|
|
599
|
-
session.proposals,
|
|
600
|
-
session.config,
|
|
601
|
-
session.round || session.currentRound || 1
|
|
602
|
-
);
|
|
603
|
-
const resolution = this.buildResolution(session, result);
|
|
604
|
-
session.status = resolution.outcome === "deadlock" ? "deadlock" : "resolved";
|
|
605
|
-
session.resolution = resolution;
|
|
606
|
-
session.resolvedAt = Date.now();
|
|
607
|
-
this.clearDeadline(sessionId);
|
|
608
|
-
this.audit("resolved", sessionId, void 0, {
|
|
609
|
-
outcome: resolution.outcome,
|
|
610
|
-
winnerId: resolution.winnerId
|
|
611
|
-
});
|
|
612
|
-
await this.emit("sessionResolved", { session, resolution });
|
|
613
|
-
return resolution;
|
|
614
|
-
}
|
|
615
|
-
/**
|
|
616
|
-
* Get session by ID
|
|
617
|
-
*/
|
|
618
|
-
getSession(sessionId) {
|
|
619
|
-
const session = this.sessions.get(sessionId);
|
|
620
|
-
if (!session) {
|
|
621
|
-
throw new Error(`Negotiation session not found: ${sessionId}`);
|
|
622
|
-
}
|
|
623
|
-
return session;
|
|
624
|
-
}
|
|
625
|
-
/**
|
|
626
|
-
* Get all active sessions
|
|
627
|
-
*/
|
|
628
|
-
getActiveSessions() {
|
|
629
|
-
return Array.from(this.sessions.values()).filter(
|
|
630
|
-
(s) => s.status === "open" || s.status === "voting"
|
|
631
|
-
);
|
|
632
|
-
}
|
|
633
|
-
/**
|
|
634
|
-
* Get sessions for a specific agent
|
|
635
|
-
*/
|
|
636
|
-
getAgentSessions(agentId) {
|
|
637
|
-
return Array.from(this.sessions.values()).filter((s) => s.participants.includes(agentId));
|
|
638
|
-
}
|
|
639
|
-
/**
|
|
640
|
-
* Cancel a session
|
|
641
|
-
*/
|
|
642
|
-
async cancel(sessionId, _reason) {
|
|
643
|
-
const session = this.getSession(sessionId);
|
|
644
|
-
if (session.status === "resolved" || session.status === "cancelled") {
|
|
645
|
-
return;
|
|
646
|
-
}
|
|
647
|
-
session.status = "cancelled";
|
|
648
|
-
const mechanism = session.config.mechanism || session.config.votingMechanism || "majority";
|
|
649
|
-
session.resolution = {
|
|
650
|
-
sessionId,
|
|
651
|
-
outcome: "cancelled",
|
|
652
|
-
tallies: [],
|
|
653
|
-
finalTallies: [],
|
|
654
|
-
mechanism,
|
|
655
|
-
rounds: session.round || 1,
|
|
656
|
-
resolvedAt: Date.now(),
|
|
657
|
-
participationRate: session.votes.length / session.participants.length,
|
|
658
|
-
timestamp: Date.now()
|
|
659
|
-
};
|
|
660
|
-
this.clearDeadline(sessionId);
|
|
661
|
-
await this.emit("sessionResolved", {
|
|
662
|
-
session,
|
|
663
|
-
resolution: session.resolution
|
|
664
|
-
});
|
|
665
|
-
}
|
|
666
|
-
/**
|
|
667
|
-
* Escalate a deadlocked session
|
|
668
|
-
*/
|
|
669
|
-
async escalate(sessionId) {
|
|
670
|
-
const session = this.getSession(sessionId);
|
|
671
|
-
if (!session.config.escalationPath) {
|
|
672
|
-
throw new Error(`No escalation path configured for session ${sessionId}`);
|
|
673
|
-
}
|
|
674
|
-
session.status = "escalated";
|
|
675
|
-
this.audit("escalated", sessionId, void 0, {
|
|
676
|
-
escalationPath: session.config.escalationPath
|
|
677
|
-
});
|
|
678
|
-
const mechanism = session.config.mechanism || session.config.votingMechanism || "majority";
|
|
679
|
-
const resolution = {
|
|
680
|
-
sessionId,
|
|
681
|
-
outcome: "escalated",
|
|
682
|
-
tallies: session.resolution?.tallies || [],
|
|
683
|
-
finalTallies: session.resolution?.finalTallies || [],
|
|
684
|
-
mechanism,
|
|
685
|
-
rounds: session.round || 1,
|
|
686
|
-
resolvedAt: Date.now(),
|
|
687
|
-
participationRate: session.votes.length / session.participants.length,
|
|
688
|
-
timestamp: Date.now(),
|
|
689
|
-
escalatedTo: session.config.escalationPath
|
|
690
|
-
};
|
|
691
|
-
session.resolution = resolution;
|
|
692
|
-
await this.emit("sessionResolved", { session, resolution });
|
|
693
|
-
return resolution;
|
|
694
|
-
}
|
|
695
|
-
/**
|
|
696
|
-
* Add a participant to an open session
|
|
697
|
-
*/
|
|
698
|
-
addParticipant(sessionId, agentId) {
|
|
699
|
-
const session = this.getSession(sessionId);
|
|
700
|
-
if (session.status !== "open") {
|
|
701
|
-
throw new Error("Cannot add participant to non-open session");
|
|
702
|
-
}
|
|
703
|
-
if (!session.participants.includes(agentId)) {
|
|
704
|
-
session.participants.push(agentId);
|
|
705
|
-
}
|
|
706
|
-
}
|
|
707
|
-
/**
|
|
708
|
-
* Remove a participant from a session
|
|
709
|
-
*/
|
|
710
|
-
removeParticipant(sessionId, agentId) {
|
|
711
|
-
const session = this.getSession(sessionId);
|
|
712
|
-
if (session.status !== "open") {
|
|
713
|
-
throw new Error("Cannot remove participant from non-open session");
|
|
714
|
-
}
|
|
715
|
-
session.participants = session.participants.filter((p) => p !== agentId);
|
|
716
|
-
}
|
|
717
|
-
/**
|
|
718
|
-
* Subscribe to negotiation events
|
|
719
|
-
*/
|
|
720
|
-
on(event, handler) {
|
|
721
|
-
if (!this.eventHandlers.has(event)) {
|
|
722
|
-
this.eventHandlers.set(event, /* @__PURE__ */ new Set());
|
|
723
|
-
}
|
|
724
|
-
this.eventHandlers.get(event).add(handler);
|
|
725
|
-
return () => {
|
|
726
|
-
this.eventHandlers.get(event)?.delete(handler);
|
|
727
|
-
};
|
|
728
|
-
}
|
|
729
|
-
/**
|
|
730
|
-
* Get audit log
|
|
731
|
-
*/
|
|
732
|
-
getAuditLog(sessionId) {
|
|
733
|
-
if (sessionId) {
|
|
734
|
-
return this.auditLog.filter((e) => e.sessionId === sessionId);
|
|
735
|
-
}
|
|
736
|
-
return [...this.auditLog];
|
|
737
|
-
}
|
|
738
|
-
/**
|
|
739
|
-
* Clear completed sessions older than maxAge
|
|
740
|
-
*/
|
|
741
|
-
pruneOldSessions(maxAgeMs) {
|
|
742
|
-
const cutoff = Date.now() - maxAgeMs;
|
|
743
|
-
let pruned = 0;
|
|
744
|
-
for (const [id, session] of this.sessions) {
|
|
745
|
-
const sessionTime = session.resolvedAt || session.createdAt || session.startedAt || 0;
|
|
746
|
-
if ((session.status === "resolved" || session.status === "cancelled") && sessionTime < cutoff) {
|
|
747
|
-
this.sessions.delete(id);
|
|
748
|
-
pruned++;
|
|
749
|
-
}
|
|
750
|
-
}
|
|
751
|
-
return pruned;
|
|
752
|
-
}
|
|
753
|
-
/**
|
|
754
|
-
* Reset protocol state (for testing)
|
|
755
|
-
*/
|
|
756
|
-
reset() {
|
|
757
|
-
for (const deadline of this.deadlines.values()) {
|
|
758
|
-
clearTimeout(deadline.timer);
|
|
759
|
-
}
|
|
760
|
-
this.sessions.clear();
|
|
761
|
-
this.auditLog = [];
|
|
762
|
-
this.deadlines.clear();
|
|
763
|
-
this.eventHandlers.clear();
|
|
764
|
-
this.sessionCounter = 0;
|
|
765
|
-
this.proposalCounter = 0;
|
|
766
|
-
this.voteCounter = 0;
|
|
767
|
-
}
|
|
768
|
-
// ===========================================================================
|
|
769
|
-
// PRIVATE METHODS
|
|
770
|
-
// ===========================================================================
|
|
771
|
-
generateSessionId() {
|
|
772
|
-
return `neg-${Date.now()}-${++this.sessionCounter}`;
|
|
773
|
-
}
|
|
774
|
-
generateProposalId() {
|
|
775
|
-
return `prop-${Date.now()}-${++this.proposalCounter}`;
|
|
776
|
-
}
|
|
777
|
-
generateVoteId() {
|
|
778
|
-
return `vote-${Date.now()}-${++this.voteCounter}`;
|
|
779
|
-
}
|
|
780
|
-
validateSessionOpen(session) {
|
|
781
|
-
if (session.status !== "open" && session.status !== "voting") {
|
|
782
|
-
throw new Error(`Session ${session.id} is ${session.status}, not accepting input`);
|
|
783
|
-
}
|
|
784
|
-
}
|
|
785
|
-
validateParticipant(session, agentId) {
|
|
786
|
-
if (!session.participants.includes(agentId)) {
|
|
787
|
-
throw new Error(`Agent ${agentId} is not a participant in session ${session.id}`);
|
|
788
|
-
}
|
|
789
|
-
}
|
|
790
|
-
validateNotDuplicate(session, agentId) {
|
|
791
|
-
const roundVotes = session.votes.filter((v) => v.agentId === agentId && !v.supersededBy);
|
|
792
|
-
if (roundVotes.length > 0) {
|
|
793
|
-
throw new Error(`Agent ${agentId} has already voted in this round of session ${session.id}`);
|
|
794
|
-
}
|
|
795
|
-
}
|
|
796
|
-
allVotesCast(session) {
|
|
797
|
-
const voted = new Set(session.votes.map((v) => v.agentId));
|
|
798
|
-
return session.participants.every((p) => {
|
|
799
|
-
const participantId = typeof p === "string" ? p : p.id;
|
|
800
|
-
return voted.has(participantId);
|
|
801
|
-
});
|
|
802
|
-
}
|
|
803
|
-
async tryAutoResolve(session) {
|
|
804
|
-
if (session.status === "open" && session.proposals.length > 0) {
|
|
805
|
-
session.status = "voting";
|
|
806
|
-
}
|
|
807
|
-
if (this.allVotesCast(session)) {
|
|
808
|
-
await this.resolve(session.id);
|
|
809
|
-
}
|
|
810
|
-
}
|
|
811
|
-
buildResolution(session, result) {
|
|
812
|
-
const winningProposal = result.winnerId ? session.proposals.find((p) => p.id === result.winnerId) : void 0;
|
|
813
|
-
const mechanism = session.config.mechanism || session.config.votingMechanism || "majority";
|
|
814
|
-
const resolvedAt = Date.now();
|
|
815
|
-
return {
|
|
816
|
-
sessionId: session.id,
|
|
817
|
-
outcome: result.outcome,
|
|
818
|
-
winnerId: result.winnerId,
|
|
819
|
-
winner: winningProposal,
|
|
820
|
-
winningProposal,
|
|
821
|
-
tallies: result.tallies,
|
|
822
|
-
finalTallies: result.tallies,
|
|
823
|
-
mechanism,
|
|
824
|
-
rounds: session.round || 1,
|
|
825
|
-
round: session.round || session.currentRound,
|
|
826
|
-
resolvedAt,
|
|
827
|
-
consensusLevel: result.consensusLevel,
|
|
828
|
-
dissenters: result.dissenters,
|
|
829
|
-
participationRate: session.votes.length / session.participants.length,
|
|
830
|
-
timestamp: resolvedAt
|
|
831
|
-
};
|
|
832
|
-
}
|
|
833
|
-
createFailedResolution(session, outcome) {
|
|
834
|
-
session.status = outcome === "timeout" ? "timeout" : "deadlock";
|
|
835
|
-
const mechanism = session.config.mechanism || session.config.votingMechanism || "majority";
|
|
836
|
-
const resolvedAt = Date.now();
|
|
837
|
-
const resolution = {
|
|
838
|
-
sessionId: session.id,
|
|
839
|
-
outcome,
|
|
840
|
-
tallies: [],
|
|
841
|
-
finalTallies: [],
|
|
842
|
-
mechanism,
|
|
843
|
-
rounds: session.round || 1,
|
|
844
|
-
resolvedAt,
|
|
845
|
-
participationRate: session.votes.length / session.participants.length,
|
|
846
|
-
timestamp: resolvedAt
|
|
847
|
-
};
|
|
848
|
-
session.resolution = resolution;
|
|
849
|
-
this.clearDeadline(session.id);
|
|
850
|
-
return resolution;
|
|
851
|
-
}
|
|
852
|
-
startDeadlineTimer(session) {
|
|
853
|
-
const timeout = session.config.timeout || session.config.votingDeadline || 6e4;
|
|
854
|
-
const timer = setTimeout(async () => {
|
|
855
|
-
if (session.status === "open" || session.status === "voting") {
|
|
856
|
-
this.audit("timeout", session.id, void 0, {
|
|
857
|
-
deadline: session.deadline
|
|
858
|
-
});
|
|
859
|
-
await this.handleTimeout(session);
|
|
860
|
-
}
|
|
861
|
-
}, timeout);
|
|
862
|
-
this.deadlines.set(session.id, { sessionId: session.id, timer });
|
|
863
|
-
}
|
|
864
|
-
async handleTimeout(session) {
|
|
865
|
-
if (session.votes.length > 0) {
|
|
866
|
-
try {
|
|
867
|
-
await this.resolve(session.id, true);
|
|
868
|
-
return;
|
|
869
|
-
} catch {
|
|
870
|
-
}
|
|
871
|
-
}
|
|
872
|
-
const resolution = this.createFailedResolution(session, "timeout");
|
|
873
|
-
await this.emit("sessionResolved", { session, resolution });
|
|
874
|
-
}
|
|
875
|
-
clearDeadline(sessionId) {
|
|
876
|
-
const deadline = this.deadlines.get(sessionId);
|
|
877
|
-
if (deadline) {
|
|
878
|
-
clearTimeout(deadline.timer);
|
|
879
|
-
this.deadlines.delete(sessionId);
|
|
880
|
-
}
|
|
881
|
-
}
|
|
882
|
-
audit(action, sessionId, agentId, details) {
|
|
883
|
-
this.auditLog.push({
|
|
884
|
-
timestamp: Date.now(),
|
|
885
|
-
sessionId,
|
|
886
|
-
action,
|
|
887
|
-
agentId,
|
|
888
|
-
details
|
|
889
|
-
});
|
|
890
|
-
}
|
|
891
|
-
async emit(event, data) {
|
|
892
|
-
const handlers = this.eventHandlers.get(event);
|
|
893
|
-
if (handlers) {
|
|
894
|
-
for (const handler of handlers) {
|
|
895
|
-
try {
|
|
896
|
-
await handler(data);
|
|
897
|
-
} catch (err) {
|
|
898
|
-
console.error(`Error in negotiation event handler for ${event}:`, err);
|
|
899
|
-
}
|
|
900
|
-
}
|
|
901
|
-
}
|
|
902
|
-
}
|
|
903
|
-
};
|
|
904
|
-
var defaultProtocol = null;
|
|
905
|
-
function getNegotiationProtocol() {
|
|
906
|
-
if (!defaultProtocol) {
|
|
907
|
-
defaultProtocol = new NegotiationProtocol();
|
|
908
|
-
}
|
|
909
|
-
return defaultProtocol;
|
|
910
|
-
}
|
|
911
|
-
function resetNegotiationProtocol() {
|
|
912
|
-
if (defaultProtocol) {
|
|
913
|
-
defaultProtocol.reset();
|
|
914
|
-
defaultProtocol = null;
|
|
915
|
-
}
|
|
916
|
-
}
|
|
917
|
-
export {
|
|
918
|
-
NegotiationProtocol,
|
|
919
|
-
approvalHandler,
|
|
920
|
-
bordaHandler,
|
|
921
|
-
checkQuorum,
|
|
922
|
-
consensusHandler,
|
|
923
|
-
getNegotiationProtocol,
|
|
924
|
-
getTrustWeight,
|
|
925
|
-
getVotingHandler,
|
|
926
|
-
majorityHandler,
|
|
927
|
-
rankedHandler,
|
|
928
|
-
resetNegotiationProtocol,
|
|
929
|
-
supermajorityHandler,
|
|
930
|
-
weightedHandler
|
|
931
|
-
};
|