agentic-qe 2.7.4 → 2.8.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/CHANGELOG.md +104 -0
- package/README.md +67 -2
- package/dist/cli/commands/agent/spawn.d.ts +12 -1
- package/dist/cli/commands/agent/spawn.d.ts.map +1 -1
- package/dist/cli/commands/agent/spawn.js +95 -8
- package/dist/cli/commands/agent/spawn.js.map +1 -1
- package/dist/cli/index.js +91 -0
- package/dist/cli/index.js.map +1 -1
- package/dist/core/memory/HNSWVectorMemory.js +1 -1
- package/dist/edge/adapters/BrowserHNSWAdapter.d.ts +134 -0
- package/dist/edge/adapters/BrowserHNSWAdapter.d.ts.map +1 -0
- package/dist/edge/adapters/BrowserHNSWAdapter.js +484 -0
- package/dist/edge/adapters/BrowserHNSWAdapter.js.map +1 -0
- package/dist/edge/adapters/IndexedDBStorage.d.ts +114 -0
- package/dist/edge/adapters/IndexedDBStorage.d.ts.map +1 -0
- package/dist/edge/adapters/IndexedDBStorage.js +478 -0
- package/dist/edge/adapters/IndexedDBStorage.js.map +1 -0
- package/dist/edge/adapters/index.d.ts +12 -0
- package/dist/edge/adapters/index.d.ts.map +1 -0
- package/dist/edge/adapters/index.js +22 -0
- package/dist/edge/adapters/index.js.map +1 -0
- package/dist/edge/browser/BrowserAgent.d.ts +241 -0
- package/dist/edge/browser/BrowserAgent.d.ts.map +1 -0
- package/dist/edge/browser/BrowserAgent.js +743 -0
- package/dist/edge/browser/BrowserAgent.js.map +1 -0
- package/dist/edge/index.d.ts +34 -0
- package/dist/edge/index.d.ts.map +1 -0
- package/dist/edge/index.js +114 -0
- package/dist/edge/index.js.map +1 -0
- package/dist/edge/p2p/coordination/CoordinationManager.d.ts +181 -0
- package/dist/edge/p2p/coordination/CoordinationManager.d.ts.map +1 -0
- package/dist/edge/p2p/coordination/CoordinationManager.js +851 -0
- package/dist/edge/p2p/coordination/CoordinationManager.js.map +1 -0
- package/dist/edge/p2p/coordination/HealthMonitor.d.ts +143 -0
- package/dist/edge/p2p/coordination/HealthMonitor.d.ts.map +1 -0
- package/dist/edge/p2p/coordination/HealthMonitor.js +432 -0
- package/dist/edge/p2p/coordination/HealthMonitor.js.map +1 -0
- package/dist/edge/p2p/coordination/SyncOrchestrator.d.ts +146 -0
- package/dist/edge/p2p/coordination/SyncOrchestrator.d.ts.map +1 -0
- package/dist/edge/p2p/coordination/SyncOrchestrator.js +783 -0
- package/dist/edge/p2p/coordination/SyncOrchestrator.js.map +1 -0
- package/dist/edge/p2p/coordination/index.d.ts +70 -0
- package/dist/edge/p2p/coordination/index.d.ts.map +1 -0
- package/dist/edge/p2p/coordination/index.js +107 -0
- package/dist/edge/p2p/coordination/index.js.map +1 -0
- package/dist/edge/p2p/coordination/types.d.ts +572 -0
- package/dist/edge/p2p/coordination/types.d.ts.map +1 -0
- package/dist/edge/p2p/coordination/types.js +366 -0
- package/dist/edge/p2p/coordination/types.js.map +1 -0
- package/dist/edge/p2p/crdt/CRDTStore.d.ts +324 -0
- package/dist/edge/p2p/crdt/CRDTStore.d.ts.map +1 -0
- package/dist/edge/p2p/crdt/CRDTStore.js +839 -0
- package/dist/edge/p2p/crdt/CRDTStore.js.map +1 -0
- package/dist/edge/p2p/crdt/GCounter.d.ts +173 -0
- package/dist/edge/p2p/crdt/GCounter.d.ts.map +1 -0
- package/dist/edge/p2p/crdt/GCounter.js +394 -0
- package/dist/edge/p2p/crdt/GCounter.js.map +1 -0
- package/dist/edge/p2p/crdt/LWWRegister.d.ts +200 -0
- package/dist/edge/p2p/crdt/LWWRegister.d.ts.map +1 -0
- package/dist/edge/p2p/crdt/LWWRegister.js +456 -0
- package/dist/edge/p2p/crdt/LWWRegister.js.map +1 -0
- package/dist/edge/p2p/crdt/ORSet.d.ts +232 -0
- package/dist/edge/p2p/crdt/ORSet.d.ts.map +1 -0
- package/dist/edge/p2p/crdt/ORSet.js +723 -0
- package/dist/edge/p2p/crdt/ORSet.js.map +1 -0
- package/dist/edge/p2p/crdt/PatternCRDT.d.ts +366 -0
- package/dist/edge/p2p/crdt/PatternCRDT.d.ts.map +1 -0
- package/dist/edge/p2p/crdt/PatternCRDT.js +838 -0
- package/dist/edge/p2p/crdt/PatternCRDT.js.map +1 -0
- package/dist/edge/p2p/crdt/VectorClock.d.ts +274 -0
- package/dist/edge/p2p/crdt/VectorClock.d.ts.map +1 -0
- package/dist/edge/p2p/crdt/VectorClock.js +499 -0
- package/dist/edge/p2p/crdt/VectorClock.js.map +1 -0
- package/dist/edge/p2p/crdt/index.d.ts +87 -0
- package/dist/edge/p2p/crdt/index.d.ts.map +1 -0
- package/dist/edge/p2p/crdt/index.js +120 -0
- package/dist/edge/p2p/crdt/index.js.map +1 -0
- package/dist/edge/p2p/crdt/types.d.ts +667 -0
- package/dist/edge/p2p/crdt/types.d.ts.map +1 -0
- package/dist/edge/p2p/crdt/types.js +208 -0
- package/dist/edge/p2p/crdt/types.js.map +1 -0
- package/dist/edge/p2p/crypto/Identity.d.ts +139 -0
- package/dist/edge/p2p/crypto/Identity.d.ts.map +1 -0
- package/dist/edge/p2p/crypto/Identity.js +449 -0
- package/dist/edge/p2p/crypto/Identity.js.map +1 -0
- package/dist/edge/p2p/crypto/KeyManager.d.ts +196 -0
- package/dist/edge/p2p/crypto/KeyManager.d.ts.map +1 -0
- package/dist/edge/p2p/crypto/KeyManager.js +576 -0
- package/dist/edge/p2p/crypto/KeyManager.js.map +1 -0
- package/dist/edge/p2p/crypto/Signer.d.ts +164 -0
- package/dist/edge/p2p/crypto/Signer.d.ts.map +1 -0
- package/dist/edge/p2p/crypto/Signer.js +357 -0
- package/dist/edge/p2p/crypto/Signer.js.map +1 -0
- package/dist/edge/p2p/crypto/index.d.ts +90 -0
- package/dist/edge/p2p/crypto/index.d.ts.map +1 -0
- package/dist/edge/p2p/crypto/index.js +158 -0
- package/dist/edge/p2p/crypto/index.js.map +1 -0
- package/dist/edge/p2p/crypto/types.d.ts +217 -0
- package/dist/edge/p2p/crypto/types.d.ts.map +1 -0
- package/dist/edge/p2p/crypto/types.js +42 -0
- package/dist/edge/p2p/crypto/types.js.map +1 -0
- package/dist/edge/p2p/federated/FederatedCoordinator.d.ts +270 -0
- package/dist/edge/p2p/federated/FederatedCoordinator.d.ts.map +1 -0
- package/dist/edge/p2p/federated/FederatedCoordinator.js +824 -0
- package/dist/edge/p2p/federated/FederatedCoordinator.js.map +1 -0
- package/dist/edge/p2p/federated/FederatedRound.d.ts +295 -0
- package/dist/edge/p2p/federated/FederatedRound.d.ts.map +1 -0
- package/dist/edge/p2p/federated/FederatedRound.js +819 -0
- package/dist/edge/p2p/federated/FederatedRound.js.map +1 -0
- package/dist/edge/p2p/federated/GradientAggregator.d.ts +226 -0
- package/dist/edge/p2p/federated/GradientAggregator.d.ts.map +1 -0
- package/dist/edge/p2p/federated/GradientAggregator.js +826 -0
- package/dist/edge/p2p/federated/GradientAggregator.js.map +1 -0
- package/dist/edge/p2p/federated/ModelManager.d.ts +248 -0
- package/dist/edge/p2p/federated/ModelManager.d.ts.map +1 -0
- package/dist/edge/p2p/federated/ModelManager.js +724 -0
- package/dist/edge/p2p/federated/ModelManager.js.map +1 -0
- package/dist/edge/p2p/federated/index.d.ts +65 -0
- package/dist/edge/p2p/federated/index.d.ts.map +1 -0
- package/dist/edge/p2p/federated/index.js +110 -0
- package/dist/edge/p2p/federated/index.js.map +1 -0
- package/dist/edge/p2p/federated/types.d.ts +905 -0
- package/dist/edge/p2p/federated/types.d.ts.map +1 -0
- package/dist/edge/p2p/federated/types.js +339 -0
- package/dist/edge/p2p/federated/types.js.map +1 -0
- package/dist/edge/p2p/index.d.ts +156 -0
- package/dist/edge/p2p/index.d.ts.map +1 -0
- package/dist/edge/p2p/index.js +242 -0
- package/dist/edge/p2p/index.js.map +1 -0
- package/dist/edge/p2p/nat/ConnectivityTester.d.ts +128 -0
- package/dist/edge/p2p/nat/ConnectivityTester.d.ts.map +1 -0
- package/dist/edge/p2p/nat/ConnectivityTester.js +560 -0
- package/dist/edge/p2p/nat/ConnectivityTester.js.map +1 -0
- package/dist/edge/p2p/nat/HolePuncher.d.ts +159 -0
- package/dist/edge/p2p/nat/HolePuncher.d.ts.map +1 -0
- package/dist/edge/p2p/nat/HolePuncher.js +569 -0
- package/dist/edge/p2p/nat/HolePuncher.js.map +1 -0
- package/dist/edge/p2p/nat/NATDetector.d.ts +109 -0
- package/dist/edge/p2p/nat/NATDetector.d.ts.map +1 -0
- package/dist/edge/p2p/nat/NATDetector.js +472 -0
- package/dist/edge/p2p/nat/NATDetector.js.map +1 -0
- package/dist/edge/p2p/nat/TURNManager.d.ts +158 -0
- package/dist/edge/p2p/nat/TURNManager.d.ts.map +1 -0
- package/dist/edge/p2p/nat/TURNManager.js +547 -0
- package/dist/edge/p2p/nat/TURNManager.js.map +1 -0
- package/dist/edge/p2p/nat/index.d.ts +74 -0
- package/dist/edge/p2p/nat/index.d.ts.map +1 -0
- package/dist/edge/p2p/nat/index.js +104 -0
- package/dist/edge/p2p/nat/index.js.map +1 -0
- package/dist/edge/p2p/nat/types.d.ts +583 -0
- package/dist/edge/p2p/nat/types.d.ts.map +1 -0
- package/dist/edge/p2p/nat/types.js +267 -0
- package/dist/edge/p2p/nat/types.js.map +1 -0
- package/dist/edge/p2p/protocol/AgentChannel.d.ts +333 -0
- package/dist/edge/p2p/protocol/AgentChannel.d.ts.map +1 -0
- package/dist/edge/p2p/protocol/AgentChannel.js +914 -0
- package/dist/edge/p2p/protocol/AgentChannel.js.map +1 -0
- package/dist/edge/p2p/protocol/MessageEncoder.d.ts +147 -0
- package/dist/edge/p2p/protocol/MessageEncoder.d.ts.map +1 -0
- package/dist/edge/p2p/protocol/MessageEncoder.js +738 -0
- package/dist/edge/p2p/protocol/MessageEncoder.js.map +1 -0
- package/dist/edge/p2p/protocol/MessageRouter.d.ts +266 -0
- package/dist/edge/p2p/protocol/MessageRouter.d.ts.map +1 -0
- package/dist/edge/p2p/protocol/MessageRouter.js +808 -0
- package/dist/edge/p2p/protocol/MessageRouter.js.map +1 -0
- package/dist/edge/p2p/protocol/ProtocolHandler.d.ts +309 -0
- package/dist/edge/p2p/protocol/ProtocolHandler.d.ts.map +1 -0
- package/dist/edge/p2p/protocol/ProtocolHandler.js +930 -0
- package/dist/edge/p2p/protocol/ProtocolHandler.js.map +1 -0
- package/dist/edge/p2p/protocol/index.d.ts +114 -0
- package/dist/edge/p2p/protocol/index.d.ts.map +1 -0
- package/dist/edge/p2p/protocol/index.js +206 -0
- package/dist/edge/p2p/protocol/index.js.map +1 -0
- package/dist/edge/p2p/protocol/types.d.ts +737 -0
- package/dist/edge/p2p/protocol/types.d.ts.map +1 -0
- package/dist/edge/p2p/protocol/types.js +490 -0
- package/dist/edge/p2p/protocol/types.js.map +1 -0
- package/dist/edge/p2p/sharing/PatternBroadcaster.d.ts +284 -0
- package/dist/edge/p2p/sharing/PatternBroadcaster.d.ts.map +1 -0
- package/dist/edge/p2p/sharing/PatternBroadcaster.js +644 -0
- package/dist/edge/p2p/sharing/PatternBroadcaster.js.map +1 -0
- package/dist/edge/p2p/sharing/PatternIndex.d.ts +168 -0
- package/dist/edge/p2p/sharing/PatternIndex.d.ts.map +1 -0
- package/dist/edge/p2p/sharing/PatternIndex.js +781 -0
- package/dist/edge/p2p/sharing/PatternIndex.js.map +1 -0
- package/dist/edge/p2p/sharing/PatternSerializer.d.ts +163 -0
- package/dist/edge/p2p/sharing/PatternSerializer.d.ts.map +1 -0
- package/dist/edge/p2p/sharing/PatternSerializer.js +696 -0
- package/dist/edge/p2p/sharing/PatternSerializer.js.map +1 -0
- package/dist/edge/p2p/sharing/PatternSyncManager.d.ts +242 -0
- package/dist/edge/p2p/sharing/PatternSyncManager.d.ts.map +1 -0
- package/dist/edge/p2p/sharing/PatternSyncManager.js +859 -0
- package/dist/edge/p2p/sharing/PatternSyncManager.js.map +1 -0
- package/dist/edge/p2p/sharing/index.d.ts +90 -0
- package/dist/edge/p2p/sharing/index.d.ts.map +1 -0
- package/dist/edge/p2p/sharing/index.js +152 -0
- package/dist/edge/p2p/sharing/index.js.map +1 -0
- package/dist/edge/p2p/sharing/types.d.ts +796 -0
- package/dist/edge/p2p/sharing/types.d.ts.map +1 -0
- package/dist/edge/p2p/sharing/types.js +264 -0
- package/dist/edge/p2p/sharing/types.js.map +1 -0
- package/dist/edge/p2p/webrtc/ConnectionPool.d.ts +218 -0
- package/dist/edge/p2p/webrtc/ConnectionPool.d.ts.map +1 -0
- package/dist/edge/p2p/webrtc/ConnectionPool.js +562 -0
- package/dist/edge/p2p/webrtc/ConnectionPool.js.map +1 -0
- package/dist/edge/p2p/webrtc/ICEManager.d.ts +171 -0
- package/dist/edge/p2p/webrtc/ICEManager.d.ts.map +1 -0
- package/dist/edge/p2p/webrtc/ICEManager.js +490 -0
- package/dist/edge/p2p/webrtc/ICEManager.js.map +1 -0
- package/dist/edge/p2p/webrtc/PeerConnectionManager.d.ts +159 -0
- package/dist/edge/p2p/webrtc/PeerConnectionManager.d.ts.map +1 -0
- package/dist/edge/p2p/webrtc/PeerConnectionManager.js +735 -0
- package/dist/edge/p2p/webrtc/PeerConnectionManager.js.map +1 -0
- package/dist/edge/p2p/webrtc/SignalingClient.d.ts +191 -0
- package/dist/edge/p2p/webrtc/SignalingClient.d.ts.map +1 -0
- package/dist/edge/p2p/webrtc/SignalingClient.js +608 -0
- package/dist/edge/p2p/webrtc/SignalingClient.js.map +1 -0
- package/dist/edge/p2p/webrtc/index.d.ts +158 -0
- package/dist/edge/p2p/webrtc/index.d.ts.map +1 -0
- package/dist/edge/p2p/webrtc/index.js +164 -0
- package/dist/edge/p2p/webrtc/index.js.map +1 -0
- package/dist/edge/p2p/webrtc/types.d.ts +665 -0
- package/dist/edge/p2p/webrtc/types.d.ts.map +1 -0
- package/dist/edge/p2p/webrtc/types.js +245 -0
- package/dist/edge/p2p/webrtc/types.js.map +1 -0
- package/dist/edge/server/AgentSpawnAPI.d.ts +98 -0
- package/dist/edge/server/AgentSpawnAPI.d.ts.map +1 -0
- package/dist/edge/server/AgentSpawnAPI.js +264 -0
- package/dist/edge/server/AgentSpawnAPI.js.map +1 -0
- package/dist/edge/server/SignalingServer.d.ts +71 -0
- package/dist/edge/server/SignalingServer.d.ts.map +1 -0
- package/dist/edge/server/SignalingServer.js +429 -0
- package/dist/edge/server/SignalingServer.js.map +1 -0
- package/dist/edge/server/index.d.ts +64 -0
- package/dist/edge/server/index.d.ts.map +1 -0
- package/dist/edge/server/index.js +318 -0
- package/dist/edge/server/index.js.map +1 -0
- package/dist/edge/types/browser-agent.types.d.ts +455 -0
- package/dist/edge/types/browser-agent.types.d.ts.map +1 -0
- package/dist/edge/types/browser-agent.types.js +116 -0
- package/dist/edge/types/browser-agent.types.js.map +1 -0
- package/dist/edge/types/index.d.ts +11 -0
- package/dist/edge/types/index.d.ts.map +1 -0
- package/dist/edge/types/index.js +17 -0
- package/dist/edge/types/index.js.map +1 -0
- package/dist/edge/types/storage.types.d.ts +207 -0
- package/dist/edge/types/storage.types.d.ts.map +1 -0
- package/dist/edge/types/storage.types.js +47 -0
- package/dist/edge/types/storage.types.js.map +1 -0
- package/dist/edge/wasm/shims.d.ts +224 -0
- package/dist/edge/wasm/shims.d.ts.map +1 -0
- package/dist/edge/wasm/shims.js +667 -0
- package/dist/edge/wasm/shims.js.map +1 -0
- package/dist/mcp/handlers/NewDomainToolsHandler.d.ts +33 -0
- package/dist/mcp/handlers/NewDomainToolsHandler.d.ts.map +1 -0
- package/dist/mcp/handlers/NewDomainToolsHandler.js +305 -0
- package/dist/mcp/handlers/NewDomainToolsHandler.js.map +1 -0
- package/dist/mcp/handlers/filtered/index.d.ts +15 -19
- package/dist/mcp/handlers/filtered/index.d.ts.map +1 -1
- package/dist/mcp/handlers/filtered/index.js +16 -27
- package/dist/mcp/handlers/filtered/index.js.map +1 -1
- package/dist/mcp/handlers/integration/index.d.ts +5 -4
- package/dist/mcp/handlers/integration/index.d.ts.map +1 -1
- package/dist/mcp/handlers/integration/index.js +7 -7
- package/dist/mcp/handlers/integration/index.js.map +1 -1
- package/dist/mcp/server-instructions.d.ts +1 -1
- package/dist/mcp/server-instructions.js +1 -1
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/mcp/server.js +14 -0
- package/dist/mcp/server.js.map +1 -1
- package/dist/mcp/tools.d.ts +8 -0
- package/dist/mcp/tools.d.ts.map +1 -1
- package/dist/mcp/tools.js +412 -1
- package/dist/mcp/tools.js.map +1 -1
- package/dist/planning/GOAPPlanner.d.ts +1 -0
- package/dist/planning/GOAPPlanner.d.ts.map +1 -1
- package/dist/planning/GOAPPlanner.js +12 -0
- package/dist/planning/GOAPPlanner.js.map +1 -1
- package/package.json +29 -8
- package/dist/alerting/AlertManager.d.ts +0 -120
- package/dist/alerting/AlertManager.d.ts.map +0 -1
- package/dist/alerting/AlertManager.js +0 -345
- package/dist/alerting/AlertManager.js.map +0 -1
- package/dist/alerting/FeedbackRouter.d.ts +0 -98
- package/dist/alerting/FeedbackRouter.d.ts.map +0 -1
- package/dist/alerting/FeedbackRouter.js +0 -331
- package/dist/alerting/FeedbackRouter.js.map +0 -1
- package/dist/alerting/StrategyApplicator.d.ts +0 -120
- package/dist/alerting/StrategyApplicator.d.ts.map +0 -1
- package/dist/alerting/StrategyApplicator.js +0 -299
- package/dist/alerting/StrategyApplicator.js.map +0 -1
- package/dist/alerting/index.d.ts +0 -68
- package/dist/alerting/index.d.ts.map +0 -1
- package/dist/alerting/index.js +0 -112
- package/dist/alerting/index.js.map +0 -1
- package/dist/alerting/types.d.ts +0 -118
- package/dist/alerting/types.d.ts.map +0 -1
- package/dist/alerting/types.js +0 -11
- package/dist/alerting/types.js.map +0 -1
- package/dist/cli/commands/fleet/backup.d.ts +0 -49
- package/dist/cli/commands/fleet/backup.d.ts.map +0 -1
- package/dist/cli/commands/fleet/backup.js +0 -88
- package/dist/cli/commands/fleet/backup.js.map +0 -1
- package/dist/cli/commands/fleet/health.d.ts +0 -154
- package/dist/cli/commands/fleet/health.d.ts.map +0 -1
- package/dist/cli/commands/fleet/health.js +0 -483
- package/dist/cli/commands/fleet/health.js.map +0 -1
- package/dist/cli/commands/fleet/init.d.ts +0 -11
- package/dist/cli/commands/fleet/init.d.ts.map +0 -1
- package/dist/cli/commands/fleet/init.js +0 -91
- package/dist/cli/commands/fleet/init.js.map +0 -1
- package/dist/cli/commands/fleet/logs.d.ts +0 -21
- package/dist/cli/commands/fleet/logs.d.ts.map +0 -1
- package/dist/cli/commands/fleet/logs.js +0 -267
- package/dist/cli/commands/fleet/logs.js.map +0 -1
- package/dist/cli/commands/fleet/metrics.d.ts +0 -27
- package/dist/cli/commands/fleet/metrics.d.ts.map +0 -1
- package/dist/cli/commands/fleet/metrics.js +0 -369
- package/dist/cli/commands/fleet/metrics.js.map +0 -1
- package/dist/cli/commands/fleet/monitor.d.ts +0 -18
- package/dist/cli/commands/fleet/monitor.d.ts.map +0 -1
- package/dist/cli/commands/fleet/monitor.js +0 -237
- package/dist/cli/commands/fleet/monitor.js.map +0 -1
- package/dist/cli/commands/fleet/optimize.d.ts +0 -42
- package/dist/cli/commands/fleet/optimize.d.ts.map +0 -1
- package/dist/cli/commands/fleet/optimize.js +0 -135
- package/dist/cli/commands/fleet/optimize.js.map +0 -1
- package/dist/cli/commands/fleet/recover.d.ts +0 -22
- package/dist/cli/commands/fleet/recover.d.ts.map +0 -1
- package/dist/cli/commands/fleet/recover.js +0 -99
- package/dist/cli/commands/fleet/recover.js.map +0 -1
- package/dist/cli/commands/fleet/restart.d.ts +0 -18
- package/dist/cli/commands/fleet/restart.d.ts.map +0 -1
- package/dist/cli/commands/fleet/restart.js +0 -290
- package/dist/cli/commands/fleet/restart.js.map +0 -1
- package/dist/cli/commands/fleet/scale.d.ts +0 -9
- package/dist/cli/commands/fleet/scale.d.ts.map +0 -1
- package/dist/cli/commands/fleet/scale.js +0 -77
- package/dist/cli/commands/fleet/scale.js.map +0 -1
- package/dist/cli/commands/fleet/shutdown.d.ts +0 -19
- package/dist/cli/commands/fleet/shutdown.d.ts.map +0 -1
- package/dist/cli/commands/fleet/shutdown.js +0 -307
- package/dist/cli/commands/fleet/shutdown.js.map +0 -1
- package/dist/cli/commands/fleet/status.d.ts +0 -10
- package/dist/cli/commands/fleet/status.d.ts.map +0 -1
- package/dist/cli/commands/fleet/status.js +0 -97
- package/dist/cli/commands/fleet/status.js.map +0 -1
- package/dist/cli/commands/fleet/topology.d.ts +0 -23
- package/dist/cli/commands/fleet/topology.d.ts.map +0 -1
- package/dist/cli/commands/fleet/topology.js +0 -376
- package/dist/cli/commands/fleet/topology.js.map +0 -1
- package/dist/cli/commands/monitor/alerts.d.ts +0 -45
- package/dist/cli/commands/monitor/alerts.d.ts.map +0 -1
- package/dist/cli/commands/monitor/alerts.js +0 -168
- package/dist/cli/commands/monitor/alerts.js.map +0 -1
- package/dist/cli/commands/monitor/analyze.d.ts +0 -49
- package/dist/cli/commands/monitor/analyze.d.ts.map +0 -1
- package/dist/cli/commands/monitor/analyze.js +0 -209
- package/dist/cli/commands/monitor/analyze.js.map +0 -1
- package/dist/cli/commands/monitor/compare.d.ts +0 -38
- package/dist/cli/commands/monitor/compare.d.ts.map +0 -1
- package/dist/cli/commands/monitor/compare.js +0 -177
- package/dist/cli/commands/monitor/compare.js.map +0 -1
- package/dist/cli/commands/monitor/dashboard.d.ts +0 -34
- package/dist/cli/commands/monitor/dashboard.d.ts.map +0 -1
- package/dist/cli/commands/monitor/dashboard.js +0 -157
- package/dist/cli/commands/monitor/dashboard.js.map +0 -1
- package/dist/cli/commands/monitor/export.d.ts +0 -36
- package/dist/cli/commands/monitor/export.d.ts.map +0 -1
- package/dist/cli/commands/monitor/export.js +0 -157
- package/dist/cli/commands/monitor/export.js.map +0 -1
- package/dist/cli/commands/monitor/index.d.ts +0 -11
- package/dist/cli/commands/monitor/index.d.ts.map +0 -1
- package/dist/cli/commands/monitor/index.js +0 -14
- package/dist/cli/commands/monitor/index.js.map +0 -1
- package/dist/cli/commands/quality/baseline.d.ts +0 -27
- package/dist/cli/commands/quality/baseline.d.ts.map +0 -1
- package/dist/cli/commands/quality/baseline.js +0 -124
- package/dist/cli/commands/quality/baseline.js.map +0 -1
- package/dist/cli/commands/quality/compare.d.ts +0 -36
- package/dist/cli/commands/quality/compare.d.ts.map +0 -1
- package/dist/cli/commands/quality/compare.js +0 -136
- package/dist/cli/commands/quality/compare.js.map +0 -1
- package/dist/cli/commands/quality/decision.d.ts +0 -81
- package/dist/cli/commands/quality/decision.d.ts.map +0 -1
- package/dist/cli/commands/quality/decision.js +0 -319
- package/dist/cli/commands/quality/decision.js.map +0 -1
- package/dist/cli/commands/quality/gate.d.ts +0 -47
- package/dist/cli/commands/quality/gate.d.ts.map +0 -1
- package/dist/cli/commands/quality/gate.js +0 -205
- package/dist/cli/commands/quality/gate.js.map +0 -1
- package/dist/cli/commands/quality/index.d.ts +0 -17
- package/dist/cli/commands/quality/index.d.ts.map +0 -1
- package/dist/cli/commands/quality/index.js +0 -41
- package/dist/cli/commands/quality/index.js.map +0 -1
- package/dist/cli/commands/quality/policy.d.ts +0 -57
- package/dist/cli/commands/quality/policy.d.ts.map +0 -1
- package/dist/cli/commands/quality/policy.js +0 -359
- package/dist/cli/commands/quality/policy.js.map +0 -1
- package/dist/cli/commands/quality/risk.d.ts +0 -41
- package/dist/cli/commands/quality/risk.d.ts.map +0 -1
- package/dist/cli/commands/quality/risk.js +0 -255
- package/dist/cli/commands/quality/risk.js.map +0 -1
- package/dist/cli/commands/quality/trends.d.ts +0 -40
- package/dist/cli/commands/quality/trends.d.ts.map +0 -1
- package/dist/cli/commands/quality/trends.js +0 -122
- package/dist/cli/commands/quality/trends.js.map +0 -1
- package/dist/cli/commands/quality/validate.d.ts +0 -44
- package/dist/cli/commands/quality/validate.d.ts.map +0 -1
- package/dist/cli/commands/quality/validate.js +0 -234
- package/dist/cli/commands/quality/validate.js.map +0 -1
- package/dist/cli/commands/test/analyze-failures.d.ts +0 -39
- package/dist/cli/commands/test/analyze-failures.d.ts.map +0 -1
- package/dist/cli/commands/test/analyze-failures.js +0 -113
- package/dist/cli/commands/test/analyze-failures.js.map +0 -1
- package/dist/cli/commands/test/clean.d.ts +0 -3
- package/dist/cli/commands/test/clean.d.ts.map +0 -1
- package/dist/cli/commands/test/clean.js +0 -148
- package/dist/cli/commands/test/clean.js.map +0 -1
- package/dist/cli/commands/test/debug.d.ts +0 -3
- package/dist/cli/commands/test/debug.d.ts.map +0 -1
- package/dist/cli/commands/test/debug.js +0 -167
- package/dist/cli/commands/test/debug.js.map +0 -1
- package/dist/cli/commands/test/diff.d.ts +0 -3
- package/dist/cli/commands/test/diff.d.ts.map +0 -1
- package/dist/cli/commands/test/diff.js +0 -195
- package/dist/cli/commands/test/diff.js.map +0 -1
- package/dist/cli/commands/test/flakiness.d.ts +0 -32
- package/dist/cli/commands/test/flakiness.d.ts.map +0 -1
- package/dist/cli/commands/test/flakiness.js +0 -121
- package/dist/cli/commands/test/flakiness.js.map +0 -1
- package/dist/cli/commands/test/index.d.ts +0 -17
- package/dist/cli/commands/test/index.d.ts.map +0 -1
- package/dist/cli/commands/test/index.js +0 -45
- package/dist/cli/commands/test/index.js.map +0 -1
- package/dist/cli/commands/test/mutate.d.ts +0 -29
- package/dist/cli/commands/test/mutate.d.ts.map +0 -1
- package/dist/cli/commands/test/mutate.js +0 -163
- package/dist/cli/commands/test/mutate.js.map +0 -1
- package/dist/cli/commands/test/parallel.d.ts +0 -3
- package/dist/cli/commands/test/parallel.d.ts.map +0 -1
- package/dist/cli/commands/test/parallel.js +0 -117
- package/dist/cli/commands/test/parallel.js.map +0 -1
- package/dist/cli/commands/test/profile.d.ts +0 -3
- package/dist/cli/commands/test/profile.d.ts.map +0 -1
- package/dist/cli/commands/test/profile.js +0 -156
- package/dist/cli/commands/test/profile.js.map +0 -1
- package/dist/cli/commands/test/queue.d.ts +0 -3
- package/dist/cli/commands/test/queue.d.ts.map +0 -1
- package/dist/cli/commands/test/queue.js +0 -140
- package/dist/cli/commands/test/queue.js.map +0 -1
- package/dist/cli/commands/test/retry.d.ts +0 -3
- package/dist/cli/commands/test/retry.d.ts.map +0 -1
- package/dist/cli/commands/test/retry.js +0 -105
- package/dist/cli/commands/test/retry.js.map +0 -1
- package/dist/cli/commands/test/snapshot.d.ts +0 -3
- package/dist/cli/commands/test/snapshot.d.ts.map +0 -1
- package/dist/cli/commands/test/snapshot.js +0 -176
- package/dist/cli/commands/test/snapshot.js.map +0 -1
- package/dist/cli/commands/test/trace.d.ts +0 -3
- package/dist/cli/commands/test/trace.d.ts.map +0 -1
- package/dist/cli/commands/test/trace.js +0 -137
- package/dist/cli/commands/test/trace.js.map +0 -1
- package/dist/cli/commands/test/watch.d.ts +0 -3
- package/dist/cli/commands/test/watch.d.ts.map +0 -1
- package/dist/cli/commands/test/watch.js +0 -130
- package/dist/cli/commands/test/watch.js.map +0 -1
- package/dist/cli/index-spec.d.ts +0 -3
- package/dist/cli/index-spec.d.ts.map +0 -1
- package/dist/cli/index-spec.js +0 -154
- package/dist/cli/index-spec.js.map +0 -1
- package/dist/cli/index-working.d.ts +0 -7
- package/dist/cli/index-working.d.ts.map +0 -1
- package/dist/cli/index-working.js +0 -617
- package/dist/cli/index-working.js.map +0 -1
- package/dist/mcp/handlers/filtered/coverage-analyzer-filtered.d.ts +0 -83
- package/dist/mcp/handlers/filtered/coverage-analyzer-filtered.d.ts.map +0 -1
- package/dist/mcp/handlers/filtered/coverage-analyzer-filtered.js +0 -130
- package/dist/mcp/handlers/filtered/coverage-analyzer-filtered.js.map +0 -1
- package/dist/mcp/handlers/filtered/flaky-detector-filtered.d.ts +0 -58
- package/dist/mcp/handlers/filtered/flaky-detector-filtered.d.ts.map +0 -1
- package/dist/mcp/handlers/filtered/flaky-detector-filtered.js +0 -84
- package/dist/mcp/handlers/filtered/flaky-detector-filtered.js.map +0 -1
- package/dist/mcp/handlers/filtered/security-scanner-filtered.d.ts +0 -54
- package/dist/mcp/handlers/filtered/security-scanner-filtered.d.ts.map +0 -1
- package/dist/mcp/handlers/filtered/security-scanner-filtered.js +0 -73
- package/dist/mcp/handlers/filtered/security-scanner-filtered.js.map +0 -1
- package/dist/mcp/handlers/integration/contract-validate.d.ts +0 -10
- package/dist/mcp/handlers/integration/contract-validate.d.ts.map +0 -1
- package/dist/mcp/handlers/integration/contract-validate.js +0 -348
- package/dist/mcp/handlers/integration/contract-validate.js.map +0 -1
- package/dist/reporting/ResultAggregator.d.ts +0 -107
- package/dist/reporting/ResultAggregator.d.ts.map +0 -1
- package/dist/reporting/ResultAggregator.js +0 -435
- package/dist/reporting/ResultAggregator.js.map +0 -1
- package/dist/reporting/index.d.ts +0 -48
- package/dist/reporting/index.d.ts.map +0 -1
- package/dist/reporting/index.js +0 -154
- package/dist/reporting/index.js.map +0 -1
- package/dist/reporting/reporters/ControlLoopReporter.d.ts +0 -128
- package/dist/reporting/reporters/ControlLoopReporter.d.ts.map +0 -1
- package/dist/reporting/reporters/ControlLoopReporter.js +0 -417
- package/dist/reporting/reporters/ControlLoopReporter.js.map +0 -1
- package/dist/reporting/reporters/HumanReadableReporter.d.ts +0 -140
- package/dist/reporting/reporters/HumanReadableReporter.d.ts.map +0 -1
- package/dist/reporting/reporters/HumanReadableReporter.js +0 -524
- package/dist/reporting/reporters/HumanReadableReporter.js.map +0 -1
- package/dist/reporting/reporters/JSONReporter.d.ts +0 -251
- package/dist/reporting/reporters/JSONReporter.d.ts.map +0 -1
- package/dist/reporting/reporters/JSONReporter.js +0 -325
- package/dist/reporting/reporters/JSONReporter.js.map +0 -1
- package/dist/reporting/reporters/index.d.ts +0 -14
- package/dist/reporting/reporters/index.d.ts.map +0 -1
- package/dist/reporting/reporters/index.js +0 -19
- package/dist/reporting/reporters/index.js.map +0 -1
- package/dist/reporting/types.d.ts +0 -427
- package/dist/reporting/types.d.ts.map +0 -1
- package/dist/reporting/types.js +0 -12
- package/dist/reporting/types.js.map +0 -1
|
@@ -0,0 +1,826 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Gradient Aggregator for Federated Learning
|
|
4
|
+
*
|
|
5
|
+
* Implements multiple aggregation strategies for combining model updates
|
|
6
|
+
* from distributed participants. Includes support for:
|
|
7
|
+
* - FedAvg: Weighted averaging based on sample counts
|
|
8
|
+
* - FedProx: Proximal term for heterogeneous data
|
|
9
|
+
* - Secure aggregation using additive secret sharing
|
|
10
|
+
* - Gradient clipping for privacy
|
|
11
|
+
* - Differential privacy noise injection
|
|
12
|
+
*
|
|
13
|
+
* @module edge/p2p/federated/GradientAggregator
|
|
14
|
+
* @version 1.0.0
|
|
15
|
+
*/
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
exports.GradientAggregator = void 0;
|
|
18
|
+
exports.createGradientAggregator = createGradientAggregator;
|
|
19
|
+
const types_1 = require("./types");
|
|
20
|
+
// ============================================
|
|
21
|
+
// GradientAggregator Class
|
|
22
|
+
// ============================================
|
|
23
|
+
/**
|
|
24
|
+
* Gradient aggregator for federated learning
|
|
25
|
+
*
|
|
26
|
+
* @example
|
|
27
|
+
* ```typescript
|
|
28
|
+
* const aggregator = new GradientAggregator({
|
|
29
|
+
* strategy: AggregationStrategy.FED_AVG,
|
|
30
|
+
* enableClipping: true,
|
|
31
|
+
* clipNorm: 1.0,
|
|
32
|
+
* differentialPrivacy: {
|
|
33
|
+
* enabled: true,
|
|
34
|
+
* epsilon: 1.0,
|
|
35
|
+
* delta: 1e-5,
|
|
36
|
+
* mechanism: 'gaussian',
|
|
37
|
+
* sensitivity: 1.0,
|
|
38
|
+
* clipNorm: 1.0,
|
|
39
|
+
* trackBudget: true,
|
|
40
|
+
* },
|
|
41
|
+
* });
|
|
42
|
+
*
|
|
43
|
+
* const result = await aggregator.aggregate(updates, globalModel);
|
|
44
|
+
* ```
|
|
45
|
+
*/
|
|
46
|
+
class GradientAggregator {
|
|
47
|
+
constructor(config = {}) {
|
|
48
|
+
this.secretShares = new Map();
|
|
49
|
+
this.pairwiseMasks = new Map();
|
|
50
|
+
this.config = {
|
|
51
|
+
strategy: config.strategy ?? types_1.AggregationStrategy.FED_AVG,
|
|
52
|
+
enableClipping: config.enableClipping ?? true,
|
|
53
|
+
clipNorm: config.clipNorm ?? types_1.DEFAULT_GRADIENT_CLIP_NORM,
|
|
54
|
+
differentialPrivacy: config.differentialPrivacy,
|
|
55
|
+
secureAggregation: config.secureAggregation,
|
|
56
|
+
proximalMu: config.proximalMu ?? 0.01,
|
|
57
|
+
trimRatio: config.trimRatio ?? 0.1,
|
|
58
|
+
byzantineTolerance: config.byzantineTolerance ?? 1,
|
|
59
|
+
};
|
|
60
|
+
// Initialize privacy budget tracking
|
|
61
|
+
const dpConfig = this.config.differentialPrivacy ?? types_1.FL_DEFAULT_DP_CONFIG;
|
|
62
|
+
this.privacyBudget = {
|
|
63
|
+
totalEpsilon: dpConfig.totalBudget ?? dpConfig.epsilon * 100,
|
|
64
|
+
totalDelta: dpConfig.delta * 100,
|
|
65
|
+
consumedEpsilon: 0,
|
|
66
|
+
consumedDelta: 0,
|
|
67
|
+
remainingEpsilon: dpConfig.totalBudget ?? dpConfig.epsilon * 100,
|
|
68
|
+
remainingDelta: dpConfig.delta * 100,
|
|
69
|
+
epsilonHistory: [],
|
|
70
|
+
exhausted: false,
|
|
71
|
+
estimatedRoundsRemaining: 100,
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
// ============================================
|
|
75
|
+
// Main Aggregation Methods
|
|
76
|
+
// ============================================
|
|
77
|
+
/**
|
|
78
|
+
* Aggregate model updates using configured strategy
|
|
79
|
+
*
|
|
80
|
+
* @param updates - Model updates from participants
|
|
81
|
+
* @param globalModel - Current global model weights
|
|
82
|
+
* @returns Aggregation result
|
|
83
|
+
*/
|
|
84
|
+
async aggregate(updates, globalModel) {
|
|
85
|
+
if (updates.length === 0) {
|
|
86
|
+
throw new types_1.FederatedError('No updates to aggregate', types_1.FederatedErrorCode.AGGREGATION_FAILED);
|
|
87
|
+
}
|
|
88
|
+
const startTime = Date.now();
|
|
89
|
+
// Apply gradient clipping if enabled
|
|
90
|
+
const clippedUpdates = this.config.enableClipping
|
|
91
|
+
? updates.map((u) => this.clipGradients(u))
|
|
92
|
+
: updates;
|
|
93
|
+
// Select aggregation strategy
|
|
94
|
+
let aggregatedWeights;
|
|
95
|
+
let excludedUpdates = [];
|
|
96
|
+
switch (this.config.strategy) {
|
|
97
|
+
case types_1.AggregationStrategy.FED_AVG:
|
|
98
|
+
aggregatedWeights = this.fedAvg(clippedUpdates, globalModel);
|
|
99
|
+
break;
|
|
100
|
+
case types_1.AggregationStrategy.FED_PROX:
|
|
101
|
+
aggregatedWeights = this.fedProx(clippedUpdates, globalModel);
|
|
102
|
+
break;
|
|
103
|
+
case types_1.AggregationStrategy.FED_MA:
|
|
104
|
+
aggregatedWeights = this.fedMA(clippedUpdates, globalModel);
|
|
105
|
+
break;
|
|
106
|
+
case types_1.AggregationStrategy.WEIGHTED_MEDIAN:
|
|
107
|
+
aggregatedWeights = this.weightedMedian(clippedUpdates, globalModel);
|
|
108
|
+
break;
|
|
109
|
+
case types_1.AggregationStrategy.TRIMMED_MEAN:
|
|
110
|
+
const trimResult = this.trimmedMean(clippedUpdates, globalModel);
|
|
111
|
+
aggregatedWeights = trimResult.weights;
|
|
112
|
+
excludedUpdates = trimResult.excluded;
|
|
113
|
+
break;
|
|
114
|
+
case types_1.AggregationStrategy.KRUM:
|
|
115
|
+
const krumResult = this.krum(clippedUpdates, globalModel);
|
|
116
|
+
aggregatedWeights = krumResult.weights;
|
|
117
|
+
excludedUpdates = krumResult.excluded;
|
|
118
|
+
break;
|
|
119
|
+
case types_1.AggregationStrategy.COORDINATE_MEDIAN:
|
|
120
|
+
aggregatedWeights = this.coordinateMedian(clippedUpdates, globalModel);
|
|
121
|
+
break;
|
|
122
|
+
default:
|
|
123
|
+
aggregatedWeights = this.fedAvg(clippedUpdates, globalModel);
|
|
124
|
+
}
|
|
125
|
+
// Apply differential privacy noise if enabled
|
|
126
|
+
if (this.config.differentialPrivacy?.enabled) {
|
|
127
|
+
aggregatedWeights = this.applyDifferentialPrivacy(aggregatedWeights);
|
|
128
|
+
}
|
|
129
|
+
// Compute checksum
|
|
130
|
+
const checksum = this.computeChecksum(aggregatedWeights);
|
|
131
|
+
// Calculate total bytes
|
|
132
|
+
let totalBytes = 0;
|
|
133
|
+
for (const weights of aggregatedWeights.values()) {
|
|
134
|
+
totalBytes += weights.byteLength;
|
|
135
|
+
}
|
|
136
|
+
// Build result
|
|
137
|
+
const aggregatedModel = {
|
|
138
|
+
modelId: globalModel.modelId,
|
|
139
|
+
version: this.incrementVersion(globalModel.version),
|
|
140
|
+
weights: aggregatedWeights,
|
|
141
|
+
shapes: globalModel.shapes,
|
|
142
|
+
totalBytes,
|
|
143
|
+
checksum,
|
|
144
|
+
timestamp: Date.now(),
|
|
145
|
+
};
|
|
146
|
+
const totalSamples = updates.reduce((sum, u) => sum + u.sampleCount, 0);
|
|
147
|
+
const aggregationTime = Date.now() - startTime;
|
|
148
|
+
const metrics = {
|
|
149
|
+
aggregationTime,
|
|
150
|
+
weightNorm: this.computeWeightNorm(aggregatedWeights),
|
|
151
|
+
updateVariance: this.computeUpdateVariance(clippedUpdates),
|
|
152
|
+
outlierScore: excludedUpdates.length > 0
|
|
153
|
+
? excludedUpdates.length / updates.length
|
|
154
|
+
: 0,
|
|
155
|
+
};
|
|
156
|
+
return {
|
|
157
|
+
aggregatedWeights: aggregatedModel,
|
|
158
|
+
updateCount: updates.length - excludedUpdates.length,
|
|
159
|
+
totalSamples,
|
|
160
|
+
metrics,
|
|
161
|
+
excludedUpdates,
|
|
162
|
+
timestamp: Date.now(),
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
// ============================================
|
|
166
|
+
// Aggregation Strategies
|
|
167
|
+
// ============================================
|
|
168
|
+
/**
|
|
169
|
+
* FedAvg: Federated Averaging
|
|
170
|
+
*
|
|
171
|
+
* Weighted average of updates based on sample counts.
|
|
172
|
+
* McMahan et al., "Communication-Efficient Learning of Deep Networks from Decentralized Data"
|
|
173
|
+
*/
|
|
174
|
+
fedAvg(updates, globalModel) {
|
|
175
|
+
const totalSamples = updates.reduce((sum, u) => sum + u.sampleCount, 0);
|
|
176
|
+
const result = new Map();
|
|
177
|
+
// Get layer names from first update
|
|
178
|
+
const layerNames = Array.from(updates[0].deltas.keys());
|
|
179
|
+
for (const layerName of layerNames) {
|
|
180
|
+
const globalWeights = globalModel.weights.get(layerName);
|
|
181
|
+
if (!globalWeights)
|
|
182
|
+
continue;
|
|
183
|
+
const aggregated = new Float32Array(globalWeights.length);
|
|
184
|
+
// Start with global model
|
|
185
|
+
for (let i = 0; i < globalWeights.length; i++) {
|
|
186
|
+
aggregated[i] = globalWeights[i];
|
|
187
|
+
}
|
|
188
|
+
// Add weighted deltas
|
|
189
|
+
for (const update of updates) {
|
|
190
|
+
const delta = update.deltas.get(layerName);
|
|
191
|
+
if (!delta)
|
|
192
|
+
continue;
|
|
193
|
+
const weight = update.sampleCount / totalSamples;
|
|
194
|
+
for (let i = 0; i < aggregated.length; i++) {
|
|
195
|
+
aggregated[i] += weight * delta[i];
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
result.set(layerName, aggregated);
|
|
199
|
+
}
|
|
200
|
+
return result;
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* FedProx: Federated Proximal
|
|
204
|
+
*
|
|
205
|
+
* Adds proximal term to handle heterogeneous data.
|
|
206
|
+
* Li et al., "Federated Optimization in Heterogeneous Networks"
|
|
207
|
+
*/
|
|
208
|
+
fedProx(updates, globalModel) {
|
|
209
|
+
const totalSamples = updates.reduce((sum, u) => sum + u.sampleCount, 0);
|
|
210
|
+
const mu = this.config.proximalMu ?? 0.01;
|
|
211
|
+
const result = new Map();
|
|
212
|
+
const layerNames = Array.from(updates[0].deltas.keys());
|
|
213
|
+
for (const layerName of layerNames) {
|
|
214
|
+
const globalWeights = globalModel.weights.get(layerName);
|
|
215
|
+
if (!globalWeights)
|
|
216
|
+
continue;
|
|
217
|
+
const aggregated = new Float32Array(globalWeights.length);
|
|
218
|
+
// Start with global model
|
|
219
|
+
for (let i = 0; i < globalWeights.length; i++) {
|
|
220
|
+
aggregated[i] = globalWeights[i];
|
|
221
|
+
}
|
|
222
|
+
// Add weighted deltas with proximal regularization
|
|
223
|
+
for (const update of updates) {
|
|
224
|
+
const delta = update.deltas.get(layerName);
|
|
225
|
+
if (!delta)
|
|
226
|
+
continue;
|
|
227
|
+
const weight = update.sampleCount / totalSamples;
|
|
228
|
+
for (let i = 0; i < aggregated.length; i++) {
|
|
229
|
+
// Proximal term pulls toward global model
|
|
230
|
+
const proximalTerm = mu * (globalWeights[i] - (globalWeights[i] + delta[i]));
|
|
231
|
+
aggregated[i] += weight * (delta[i] - proximalTerm);
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
result.set(layerName, aggregated);
|
|
235
|
+
}
|
|
236
|
+
return result;
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* FedMA: Federated Matched Averaging
|
|
240
|
+
*
|
|
241
|
+
* Layer-wise matching before averaging.
|
|
242
|
+
* Wang et al., "Federated Learning with Matched Averaging"
|
|
243
|
+
*/
|
|
244
|
+
fedMA(updates, globalModel) {
|
|
245
|
+
// Simplified FedMA: permutation matching based on weight similarities
|
|
246
|
+
// Full implementation would require neuron matching algorithm
|
|
247
|
+
const totalSamples = updates.reduce((sum, u) => sum + u.sampleCount, 0);
|
|
248
|
+
const result = new Map();
|
|
249
|
+
const layerNames = Array.from(updates[0].deltas.keys());
|
|
250
|
+
for (const layerName of layerNames) {
|
|
251
|
+
const globalWeights = globalModel.weights.get(layerName);
|
|
252
|
+
if (!globalWeights)
|
|
253
|
+
continue;
|
|
254
|
+
const aggregated = new Float32Array(globalWeights.length);
|
|
255
|
+
// Start with global model
|
|
256
|
+
for (let i = 0; i < globalWeights.length; i++) {
|
|
257
|
+
aggregated[i] = globalWeights[i];
|
|
258
|
+
}
|
|
259
|
+
// Compute matching and weighted average
|
|
260
|
+
for (const update of updates) {
|
|
261
|
+
const delta = update.deltas.get(layerName);
|
|
262
|
+
if (!delta)
|
|
263
|
+
continue;
|
|
264
|
+
// Simple weight-based matching (full FedMA would use Hungarian algorithm)
|
|
265
|
+
const matchedDelta = this.matchWeights(delta, globalWeights);
|
|
266
|
+
const weight = update.sampleCount / totalSamples;
|
|
267
|
+
for (let i = 0; i < aggregated.length; i++) {
|
|
268
|
+
aggregated[i] += weight * matchedDelta[i];
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
result.set(layerName, aggregated);
|
|
272
|
+
}
|
|
273
|
+
return result;
|
|
274
|
+
}
|
|
275
|
+
/**
|
|
276
|
+
* Weighted Median Aggregation
|
|
277
|
+
*
|
|
278
|
+
* Byzantine-resilient aggregation using weighted median.
|
|
279
|
+
*/
|
|
280
|
+
weightedMedian(updates, globalModel) {
|
|
281
|
+
const result = new Map();
|
|
282
|
+
const layerNames = Array.from(updates[0].deltas.keys());
|
|
283
|
+
for (const layerName of layerNames) {
|
|
284
|
+
const globalWeights = globalModel.weights.get(layerName);
|
|
285
|
+
if (!globalWeights)
|
|
286
|
+
continue;
|
|
287
|
+
const aggregated = new Float32Array(globalWeights.length);
|
|
288
|
+
// For each weight, compute weighted median
|
|
289
|
+
for (let i = 0; i < globalWeights.length; i++) {
|
|
290
|
+
const values = [];
|
|
291
|
+
for (const update of updates) {
|
|
292
|
+
const delta = update.deltas.get(layerName);
|
|
293
|
+
if (!delta)
|
|
294
|
+
continue;
|
|
295
|
+
values.push({
|
|
296
|
+
value: globalWeights[i] + delta[i],
|
|
297
|
+
weight: update.sampleCount,
|
|
298
|
+
});
|
|
299
|
+
}
|
|
300
|
+
aggregated[i] = this.computeWeightedMedian(values);
|
|
301
|
+
}
|
|
302
|
+
result.set(layerName, aggregated);
|
|
303
|
+
}
|
|
304
|
+
return result;
|
|
305
|
+
}
|
|
306
|
+
/**
|
|
307
|
+
* Trimmed Mean Aggregation
|
|
308
|
+
*
|
|
309
|
+
* Outlier-resistant aggregation by trimming extreme values.
|
|
310
|
+
*/
|
|
311
|
+
trimmedMean(updates, globalModel) {
|
|
312
|
+
const trimRatio = this.config.trimRatio ?? 0.1;
|
|
313
|
+
const result = new Map();
|
|
314
|
+
const excluded = [];
|
|
315
|
+
// Compute distances from mean for each update
|
|
316
|
+
const distances = updates.map((update) => ({
|
|
317
|
+
updateId: update.updateId,
|
|
318
|
+
distance: this.computeUpdateDistance(update, updates),
|
|
319
|
+
}));
|
|
320
|
+
// Sort by distance and trim
|
|
321
|
+
distances.sort((a, b) => b.distance - a.distance);
|
|
322
|
+
const trimCount = Math.floor(updates.length * trimRatio);
|
|
323
|
+
const trimmedIds = new Set(distances.slice(0, trimCount).map((d) => d.updateId));
|
|
324
|
+
for (const d of distances.slice(0, trimCount)) {
|
|
325
|
+
excluded.push(d.updateId);
|
|
326
|
+
}
|
|
327
|
+
// Filter updates
|
|
328
|
+
const filteredUpdates = updates.filter((u) => !trimmedIds.has(u.updateId));
|
|
329
|
+
// Apply FedAvg on filtered updates
|
|
330
|
+
const weights = this.fedAvg(filteredUpdates, globalModel);
|
|
331
|
+
return { weights, excluded };
|
|
332
|
+
}
|
|
333
|
+
/**
|
|
334
|
+
* Krum Aggregation
|
|
335
|
+
*
|
|
336
|
+
* Byzantine-resilient aggregation by selecting updates closest to others.
|
|
337
|
+
* Blanchard et al., "Machine Learning with Adversaries: Byzantine Tolerant Gradient Descent"
|
|
338
|
+
*/
|
|
339
|
+
krum(updates, globalModel) {
|
|
340
|
+
const f = this.config.byzantineTolerance ?? 1;
|
|
341
|
+
const n = updates.length;
|
|
342
|
+
const m = n - f - 2;
|
|
343
|
+
if (m < 1) {
|
|
344
|
+
// Fall back to FedAvg if not enough participants
|
|
345
|
+
return { weights: this.fedAvg(updates, globalModel), excluded: [] };
|
|
346
|
+
}
|
|
347
|
+
// Compute pairwise distances
|
|
348
|
+
const distances = [];
|
|
349
|
+
for (let i = 0; i < n; i++) {
|
|
350
|
+
distances[i] = [];
|
|
351
|
+
for (let j = 0; j < n; j++) {
|
|
352
|
+
if (i === j) {
|
|
353
|
+
distances[i][j] = 0;
|
|
354
|
+
}
|
|
355
|
+
else {
|
|
356
|
+
distances[i][j] = this.computePairwiseDistance(updates[i], updates[j]);
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
// For each update, compute sum of m closest distances
|
|
361
|
+
const scores = [];
|
|
362
|
+
for (let i = 0; i < n; i++) {
|
|
363
|
+
const sortedDistances = [...distances[i]].sort((a, b) => a - b);
|
|
364
|
+
const score = sortedDistances.slice(1, m + 1).reduce((a, b) => a + b, 0);
|
|
365
|
+
scores.push({ index: i, score });
|
|
366
|
+
}
|
|
367
|
+
// Select update with minimum score
|
|
368
|
+
scores.sort((a, b) => a.score - b.score);
|
|
369
|
+
const selectedIndex = scores[0].index;
|
|
370
|
+
const excluded = scores.slice(1).map((s) => updates[s.index].updateId);
|
|
371
|
+
// Return the selected update applied to global model
|
|
372
|
+
const result = new Map();
|
|
373
|
+
const selectedUpdate = updates[selectedIndex];
|
|
374
|
+
for (const [layerName, delta] of selectedUpdate.deltas) {
|
|
375
|
+
const globalWeights = globalModel.weights.get(layerName);
|
|
376
|
+
if (!globalWeights)
|
|
377
|
+
continue;
|
|
378
|
+
const updated = new Float32Array(globalWeights.length);
|
|
379
|
+
for (let i = 0; i < globalWeights.length; i++) {
|
|
380
|
+
updated[i] = globalWeights[i] + delta[i];
|
|
381
|
+
}
|
|
382
|
+
result.set(layerName, updated);
|
|
383
|
+
}
|
|
384
|
+
return { weights: result, excluded };
|
|
385
|
+
}
|
|
386
|
+
/**
|
|
387
|
+
* Coordinate-wise Median Aggregation
|
|
388
|
+
*
|
|
389
|
+
* Simple Byzantine-resilient aggregation using element-wise median.
|
|
390
|
+
*/
|
|
391
|
+
coordinateMedian(updates, globalModel) {
|
|
392
|
+
const result = new Map();
|
|
393
|
+
const layerNames = Array.from(updates[0].deltas.keys());
|
|
394
|
+
for (const layerName of layerNames) {
|
|
395
|
+
const globalWeights = globalModel.weights.get(layerName);
|
|
396
|
+
if (!globalWeights)
|
|
397
|
+
continue;
|
|
398
|
+
const aggregated = new Float32Array(globalWeights.length);
|
|
399
|
+
// For each weight, compute median of all deltas
|
|
400
|
+
for (let i = 0; i < globalWeights.length; i++) {
|
|
401
|
+
const values = [];
|
|
402
|
+
for (const update of updates) {
|
|
403
|
+
const delta = update.deltas.get(layerName);
|
|
404
|
+
if (!delta)
|
|
405
|
+
continue;
|
|
406
|
+
values.push(globalWeights[i] + delta[i]);
|
|
407
|
+
}
|
|
408
|
+
values.sort((a, b) => a - b);
|
|
409
|
+
const mid = Math.floor(values.length / 2);
|
|
410
|
+
aggregated[i] = values.length % 2 === 0
|
|
411
|
+
? (values[mid - 1] + values[mid]) / 2
|
|
412
|
+
: values[mid];
|
|
413
|
+
}
|
|
414
|
+
result.set(layerName, aggregated);
|
|
415
|
+
}
|
|
416
|
+
return result;
|
|
417
|
+
}
|
|
418
|
+
// ============================================
|
|
419
|
+
// Gradient Clipping
|
|
420
|
+
// ============================================
|
|
421
|
+
/**
|
|
422
|
+
* Clip gradients to specified norm
|
|
423
|
+
*/
|
|
424
|
+
clipGradients(update) {
|
|
425
|
+
const clipNorm = this.config.clipNorm;
|
|
426
|
+
let totalNorm = 0;
|
|
427
|
+
// Compute total L2 norm
|
|
428
|
+
for (const delta of update.deltas.values()) {
|
|
429
|
+
for (let i = 0; i < delta.length; i++) {
|
|
430
|
+
totalNorm += delta[i] * delta[i];
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
totalNorm = Math.sqrt(totalNorm);
|
|
434
|
+
// If norm exceeds clip value, scale down
|
|
435
|
+
if (totalNorm > clipNorm) {
|
|
436
|
+
const scale = clipNorm / totalNorm;
|
|
437
|
+
const clippedDeltas = new Map();
|
|
438
|
+
for (const [layerName, delta] of update.deltas) {
|
|
439
|
+
const clipped = new Float32Array(delta.length);
|
|
440
|
+
for (let i = 0; i < delta.length; i++) {
|
|
441
|
+
clipped[i] = delta[i] * scale;
|
|
442
|
+
}
|
|
443
|
+
clippedDeltas.set(layerName, clipped);
|
|
444
|
+
}
|
|
445
|
+
return {
|
|
446
|
+
...update,
|
|
447
|
+
deltas: clippedDeltas,
|
|
448
|
+
};
|
|
449
|
+
}
|
|
450
|
+
return update;
|
|
451
|
+
}
|
|
452
|
+
/**
|
|
453
|
+
* Compute gradient norm for an update
|
|
454
|
+
*/
|
|
455
|
+
computeGradientNorm(update) {
|
|
456
|
+
let norm = 0;
|
|
457
|
+
for (const delta of update.deltas.values()) {
|
|
458
|
+
for (let i = 0; i < delta.length; i++) {
|
|
459
|
+
norm += delta[i] * delta[i];
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
return Math.sqrt(norm);
|
|
463
|
+
}
|
|
464
|
+
// ============================================
|
|
465
|
+
// Differential Privacy
|
|
466
|
+
// ============================================
|
|
467
|
+
/**
|
|
468
|
+
* Apply differential privacy noise to aggregated weights
|
|
469
|
+
*/
|
|
470
|
+
applyDifferentialPrivacy(weights) {
|
|
471
|
+
const dpConfig = this.config.differentialPrivacy;
|
|
472
|
+
const result = new Map();
|
|
473
|
+
// Calculate noise scale based on mechanism
|
|
474
|
+
const noiseScale = this.computeNoiseScale(dpConfig);
|
|
475
|
+
for (const [layerName, layerWeights] of weights) {
|
|
476
|
+
const noisedWeights = new Float32Array(layerWeights.length);
|
|
477
|
+
for (let i = 0; i < layerWeights.length; i++) {
|
|
478
|
+
const noise = dpConfig.mechanism === 'laplace'
|
|
479
|
+
? this.sampleLaplace(noiseScale)
|
|
480
|
+
: this.sampleGaussian(noiseScale);
|
|
481
|
+
noisedWeights[i] = layerWeights[i] + noise;
|
|
482
|
+
}
|
|
483
|
+
result.set(layerName, noisedWeights);
|
|
484
|
+
}
|
|
485
|
+
// Update privacy budget
|
|
486
|
+
this.updatePrivacyBudget(dpConfig);
|
|
487
|
+
return result;
|
|
488
|
+
}
|
|
489
|
+
/**
|
|
490
|
+
* Compute noise scale for differential privacy
|
|
491
|
+
*/
|
|
492
|
+
computeNoiseScale(dpConfig) {
|
|
493
|
+
const sensitivity = dpConfig.sensitivity;
|
|
494
|
+
const epsilon = dpConfig.perRoundBudget ?? dpConfig.epsilon;
|
|
495
|
+
if (dpConfig.mechanism === 'laplace') {
|
|
496
|
+
// Laplace mechanism: scale = sensitivity / epsilon
|
|
497
|
+
return sensitivity / epsilon;
|
|
498
|
+
}
|
|
499
|
+
else {
|
|
500
|
+
// Gaussian mechanism: scale = sensitivity * sqrt(2 * ln(1.25/delta)) / epsilon
|
|
501
|
+
const delta = dpConfig.delta;
|
|
502
|
+
return sensitivity * Math.sqrt(2 * Math.log(1.25 / delta)) / epsilon;
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
/**
|
|
506
|
+
* Sample from Laplace distribution
|
|
507
|
+
*/
|
|
508
|
+
sampleLaplace(scale) {
|
|
509
|
+
const u = Math.random() - 0.5;
|
|
510
|
+
return -scale * Math.sign(u) * Math.log(1 - 2 * Math.abs(u));
|
|
511
|
+
}
|
|
512
|
+
/**
|
|
513
|
+
* Sample from Gaussian distribution (Box-Muller transform)
|
|
514
|
+
*/
|
|
515
|
+
sampleGaussian(stddev) {
|
|
516
|
+
const u1 = Math.random();
|
|
517
|
+
const u2 = Math.random();
|
|
518
|
+
const z = Math.sqrt(-2 * Math.log(u1)) * Math.cos(2 * Math.PI * u2);
|
|
519
|
+
return z * stddev;
|
|
520
|
+
}
|
|
521
|
+
/**
|
|
522
|
+
* Update privacy budget tracking
|
|
523
|
+
*/
|
|
524
|
+
updatePrivacyBudget(dpConfig) {
|
|
525
|
+
const epsilonConsumed = dpConfig.perRoundBudget ?? dpConfig.epsilon;
|
|
526
|
+
const deltaConsumed = dpConfig.delta;
|
|
527
|
+
this.privacyBudget.consumedEpsilon += epsilonConsumed;
|
|
528
|
+
this.privacyBudget.consumedDelta += deltaConsumed;
|
|
529
|
+
this.privacyBudget.remainingEpsilon =
|
|
530
|
+
this.privacyBudget.totalEpsilon - this.privacyBudget.consumedEpsilon;
|
|
531
|
+
this.privacyBudget.remainingDelta =
|
|
532
|
+
this.privacyBudget.totalDelta - this.privacyBudget.consumedDelta;
|
|
533
|
+
this.privacyBudget.epsilonHistory.push(epsilonConsumed);
|
|
534
|
+
this.privacyBudget.exhausted = this.privacyBudget.remainingEpsilon <= 0;
|
|
535
|
+
this.privacyBudget.estimatedRoundsRemaining = Math.floor(this.privacyBudget.remainingEpsilon / epsilonConsumed);
|
|
536
|
+
}
|
|
537
|
+
/**
|
|
538
|
+
* Get current privacy budget status
|
|
539
|
+
*/
|
|
540
|
+
getPrivacyBudget() {
|
|
541
|
+
return { ...this.privacyBudget };
|
|
542
|
+
}
|
|
543
|
+
/**
|
|
544
|
+
* Check if privacy budget is exhausted
|
|
545
|
+
*/
|
|
546
|
+
isPrivacyBudgetExhausted() {
|
|
547
|
+
return this.privacyBudget.exhausted;
|
|
548
|
+
}
|
|
549
|
+
// ============================================
|
|
550
|
+
// Secure Aggregation
|
|
551
|
+
// ============================================
|
|
552
|
+
/**
|
|
553
|
+
* Initialize secure aggregation for a set of participants
|
|
554
|
+
*/
|
|
555
|
+
async initSecureAggregation(participantIds) {
|
|
556
|
+
const saConfig = this.config.secureAggregation;
|
|
557
|
+
if (!saConfig?.enabled) {
|
|
558
|
+
throw new types_1.FederatedError('Secure aggregation not enabled', types_1.FederatedErrorCode.SECURE_AGGREGATION_ERROR);
|
|
559
|
+
}
|
|
560
|
+
// Generate secret shares for each participant
|
|
561
|
+
const shares = new Map();
|
|
562
|
+
for (const participantId of participantIds) {
|
|
563
|
+
const share = this.generateSecretShare(participantId, saConfig.totalShares);
|
|
564
|
+
shares.set(participantId, share);
|
|
565
|
+
this.secretShares.set(participantId, [{
|
|
566
|
+
participantId,
|
|
567
|
+
index: 0,
|
|
568
|
+
value: share,
|
|
569
|
+
}]);
|
|
570
|
+
}
|
|
571
|
+
// Generate pairwise masks if enabled
|
|
572
|
+
if (saConfig.pairwiseMasking) {
|
|
573
|
+
await this.generatePairwiseMasks(participantIds);
|
|
574
|
+
}
|
|
575
|
+
return shares;
|
|
576
|
+
}
|
|
577
|
+
/**
|
|
578
|
+
* Generate secret share for a participant
|
|
579
|
+
*/
|
|
580
|
+
generateSecretShare(participantId, totalShares) {
|
|
581
|
+
// Simplified secret sharing - real implementation would use Shamir's
|
|
582
|
+
const share = new Uint8Array(32);
|
|
583
|
+
crypto.getRandomValues(share);
|
|
584
|
+
return share;
|
|
585
|
+
}
|
|
586
|
+
/**
|
|
587
|
+
* Generate pairwise masks for secure aggregation
|
|
588
|
+
*/
|
|
589
|
+
async generatePairwiseMasks(participantIds) {
|
|
590
|
+
for (let i = 0; i < participantIds.length; i++) {
|
|
591
|
+
const masks = [];
|
|
592
|
+
for (let j = i + 1; j < participantIds.length; j++) {
|
|
593
|
+
// Generate random mask (simplified - real implementation would use DH key exchange)
|
|
594
|
+
const mask = {
|
|
595
|
+
source: participantIds[i],
|
|
596
|
+
target: participantIds[j],
|
|
597
|
+
masks: new Map(),
|
|
598
|
+
};
|
|
599
|
+
masks.push(mask);
|
|
600
|
+
}
|
|
601
|
+
this.pairwiseMasks.set(participantIds[i], masks);
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
/**
|
|
605
|
+
* Apply secure aggregation masks to an update
|
|
606
|
+
*/
|
|
607
|
+
applySecureMasks(update, participantMasks) {
|
|
608
|
+
const maskedDeltas = new Map();
|
|
609
|
+
for (const [layerName, delta] of update.deltas) {
|
|
610
|
+
const mask = participantMasks.get(layerName);
|
|
611
|
+
const masked = new Float32Array(delta.length);
|
|
612
|
+
for (let i = 0; i < delta.length; i++) {
|
|
613
|
+
masked[i] = delta[i] + (mask ? mask[i] : 0);
|
|
614
|
+
}
|
|
615
|
+
maskedDeltas.set(layerName, masked);
|
|
616
|
+
}
|
|
617
|
+
return {
|
|
618
|
+
...update,
|
|
619
|
+
deltas: maskedDeltas,
|
|
620
|
+
};
|
|
621
|
+
}
|
|
622
|
+
/**
|
|
623
|
+
* Remove secure aggregation masks after aggregation
|
|
624
|
+
*/
|
|
625
|
+
removeSecureMasks(aggregatedWeights, allMasks) {
|
|
626
|
+
const result = new Map();
|
|
627
|
+
for (const [layerName, weights] of aggregatedWeights) {
|
|
628
|
+
const unmasked = new Float32Array(weights.length);
|
|
629
|
+
// Sum of all masks should cancel out
|
|
630
|
+
for (let i = 0; i < weights.length; i++) {
|
|
631
|
+
let maskSum = 0;
|
|
632
|
+
for (const masks of allMasks) {
|
|
633
|
+
const mask = masks.get(layerName);
|
|
634
|
+
if (mask) {
|
|
635
|
+
maskSum += mask[i];
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
unmasked[i] = weights[i] - maskSum;
|
|
639
|
+
}
|
|
640
|
+
result.set(layerName, unmasked);
|
|
641
|
+
}
|
|
642
|
+
return result;
|
|
643
|
+
}
|
|
644
|
+
// ============================================
|
|
645
|
+
// Helper Methods
|
|
646
|
+
// ============================================
|
|
647
|
+
/**
|
|
648
|
+
* Match weights for FedMA (simplified version)
|
|
649
|
+
*/
|
|
650
|
+
matchWeights(delta, global) {
|
|
651
|
+
// Simplified matching - just return delta as-is
|
|
652
|
+
// Full implementation would use Hungarian algorithm for neuron matching
|
|
653
|
+
return delta;
|
|
654
|
+
}
|
|
655
|
+
/**
|
|
656
|
+
* Compute weighted median
|
|
657
|
+
*/
|
|
658
|
+
computeWeightedMedian(values) {
|
|
659
|
+
if (values.length === 0)
|
|
660
|
+
return 0;
|
|
661
|
+
if (values.length === 1)
|
|
662
|
+
return values[0].value;
|
|
663
|
+
// Sort by value
|
|
664
|
+
values.sort((a, b) => a.value - b.value);
|
|
665
|
+
// Compute total weight
|
|
666
|
+
const totalWeight = values.reduce((sum, v) => sum + v.weight, 0);
|
|
667
|
+
const halfWeight = totalWeight / 2;
|
|
668
|
+
// Find weighted median
|
|
669
|
+
let cumWeight = 0;
|
|
670
|
+
for (let i = 0; i < values.length; i++) {
|
|
671
|
+
cumWeight += values[i].weight;
|
|
672
|
+
if (cumWeight >= halfWeight) {
|
|
673
|
+
return values[i].value;
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
return values[values.length - 1].value;
|
|
677
|
+
}
|
|
678
|
+
/**
|
|
679
|
+
* Compute distance of an update from mean of all updates
|
|
680
|
+
*/
|
|
681
|
+
computeUpdateDistance(update, allUpdates) {
|
|
682
|
+
// Compute mean delta
|
|
683
|
+
const meanDeltas = new Map();
|
|
684
|
+
for (const layerName of update.deltas.keys()) {
|
|
685
|
+
const deltas = [];
|
|
686
|
+
for (const u of allUpdates) {
|
|
687
|
+
const d = u.deltas.get(layerName);
|
|
688
|
+
if (d)
|
|
689
|
+
deltas.push(d);
|
|
690
|
+
}
|
|
691
|
+
if (deltas.length > 0) {
|
|
692
|
+
const mean = new Float32Array(deltas[0].length);
|
|
693
|
+
for (const d of deltas) {
|
|
694
|
+
for (let i = 0; i < d.length; i++) {
|
|
695
|
+
mean[i] += d[i] / deltas.length;
|
|
696
|
+
}
|
|
697
|
+
}
|
|
698
|
+
meanDeltas.set(layerName, mean);
|
|
699
|
+
}
|
|
700
|
+
}
|
|
701
|
+
// Compute L2 distance from mean
|
|
702
|
+
let distance = 0;
|
|
703
|
+
for (const [layerName, delta] of update.deltas) {
|
|
704
|
+
const mean = meanDeltas.get(layerName);
|
|
705
|
+
if (!mean)
|
|
706
|
+
continue;
|
|
707
|
+
for (let i = 0; i < delta.length; i++) {
|
|
708
|
+
const diff = delta[i] - mean[i];
|
|
709
|
+
distance += diff * diff;
|
|
710
|
+
}
|
|
711
|
+
}
|
|
712
|
+
return Math.sqrt(distance);
|
|
713
|
+
}
|
|
714
|
+
/**
|
|
715
|
+
* Compute pairwise distance between two updates
|
|
716
|
+
*/
|
|
717
|
+
computePairwiseDistance(u1, u2) {
|
|
718
|
+
let distance = 0;
|
|
719
|
+
for (const [layerName, delta1] of u1.deltas) {
|
|
720
|
+
const delta2 = u2.deltas.get(layerName);
|
|
721
|
+
if (!delta2)
|
|
722
|
+
continue;
|
|
723
|
+
for (let i = 0; i < delta1.length; i++) {
|
|
724
|
+
const diff = delta1[i] - delta2[i];
|
|
725
|
+
distance += diff * diff;
|
|
726
|
+
}
|
|
727
|
+
}
|
|
728
|
+
return Math.sqrt(distance);
|
|
729
|
+
}
|
|
730
|
+
/**
|
|
731
|
+
* Compute weight norm for aggregated model
|
|
732
|
+
*/
|
|
733
|
+
computeWeightNorm(weights) {
|
|
734
|
+
let norm = 0;
|
|
735
|
+
for (const layerWeights of weights.values()) {
|
|
736
|
+
for (let i = 0; i < layerWeights.length; i++) {
|
|
737
|
+
norm += layerWeights[i] * layerWeights[i];
|
|
738
|
+
}
|
|
739
|
+
}
|
|
740
|
+
return Math.sqrt(norm);
|
|
741
|
+
}
|
|
742
|
+
/**
|
|
743
|
+
* Compute variance of updates
|
|
744
|
+
*/
|
|
745
|
+
computeUpdateVariance(updates) {
|
|
746
|
+
if (updates.length < 2)
|
|
747
|
+
return 0;
|
|
748
|
+
// Compute mean gradient norm
|
|
749
|
+
const norms = updates.map((u) => this.computeGradientNorm(u));
|
|
750
|
+
const meanNorm = norms.reduce((a, b) => a + b, 0) / norms.length;
|
|
751
|
+
// Compute variance
|
|
752
|
+
const variance = norms.reduce((sum, n) => sum + (n - meanNorm) ** 2, 0) / norms.length;
|
|
753
|
+
return variance;
|
|
754
|
+
}
|
|
755
|
+
/**
|
|
756
|
+
* Compute checksum for weights
|
|
757
|
+
*/
|
|
758
|
+
computeChecksum(weights) {
|
|
759
|
+
// Simple checksum based on sum and count
|
|
760
|
+
let sum = 0;
|
|
761
|
+
let count = 0;
|
|
762
|
+
for (const layerWeights of weights.values()) {
|
|
763
|
+
for (let i = 0; i < layerWeights.length; i++) {
|
|
764
|
+
sum += layerWeights[i];
|
|
765
|
+
count++;
|
|
766
|
+
}
|
|
767
|
+
}
|
|
768
|
+
return `${count}:${sum.toFixed(6)}`;
|
|
769
|
+
}
|
|
770
|
+
/**
|
|
771
|
+
* Increment model version string
|
|
772
|
+
*/
|
|
773
|
+
incrementVersion(version) {
|
|
774
|
+
const parts = version.split('.');
|
|
775
|
+
if (parts.length >= 3) {
|
|
776
|
+
parts[2] = String(parseInt(parts[2]) + 1);
|
|
777
|
+
return parts.join('.');
|
|
778
|
+
}
|
|
779
|
+
return `${version}.1`;
|
|
780
|
+
}
|
|
781
|
+
// ============================================
|
|
782
|
+
// Configuration
|
|
783
|
+
// ============================================
|
|
784
|
+
/**
|
|
785
|
+
* Update aggregator configuration
|
|
786
|
+
*/
|
|
787
|
+
updateConfig(config) {
|
|
788
|
+
this.config = { ...this.config, ...config };
|
|
789
|
+
}
|
|
790
|
+
/**
|
|
791
|
+
* Get current configuration
|
|
792
|
+
*/
|
|
793
|
+
getConfig() {
|
|
794
|
+
return { ...this.config };
|
|
795
|
+
}
|
|
796
|
+
/**
|
|
797
|
+
* Reset aggregator state
|
|
798
|
+
*/
|
|
799
|
+
reset() {
|
|
800
|
+
this.secretShares.clear();
|
|
801
|
+
this.pairwiseMasks.clear();
|
|
802
|
+
const dpConfig = this.config.differentialPrivacy ?? types_1.FL_DEFAULT_DP_CONFIG;
|
|
803
|
+
this.privacyBudget = {
|
|
804
|
+
totalEpsilon: dpConfig.totalBudget ?? dpConfig.epsilon * 100,
|
|
805
|
+
totalDelta: dpConfig.delta * 100,
|
|
806
|
+
consumedEpsilon: 0,
|
|
807
|
+
consumedDelta: 0,
|
|
808
|
+
remainingEpsilon: dpConfig.totalBudget ?? dpConfig.epsilon * 100,
|
|
809
|
+
remainingDelta: dpConfig.delta * 100,
|
|
810
|
+
epsilonHistory: [],
|
|
811
|
+
exhausted: false,
|
|
812
|
+
estimatedRoundsRemaining: 100,
|
|
813
|
+
};
|
|
814
|
+
}
|
|
815
|
+
}
|
|
816
|
+
exports.GradientAggregator = GradientAggregator;
|
|
817
|
+
// ============================================
|
|
818
|
+
// Factory Function
|
|
819
|
+
// ============================================
|
|
820
|
+
/**
|
|
821
|
+
* Create a new gradient aggregator
|
|
822
|
+
*/
|
|
823
|
+
function createGradientAggregator(config) {
|
|
824
|
+
return new GradientAggregator(config);
|
|
825
|
+
}
|
|
826
|
+
//# sourceMappingURL=GradientAggregator.js.map
|