Compare commits
2 Commits
3dc06c73ef
...
a27eb44f62
| Author | SHA1 | Date | |
|---|---|---|---|
| a27eb44f62 | |||
| 66b525a24b |
@@ -75,6 +75,12 @@ Add to your opencode config:
|
||||
|
||||
Run on multiple machines to combine their power:
|
||||
|
||||
### Features
|
||||
- **Parallel Execution**: Local and peers generate simultaneously for faster consensus
|
||||
- **Streaming Support**: Federation works with streaming responses
|
||||
- **Winner Tracking**: Logs which node (local or peer) won consensus voting
|
||||
- **Token Usage**: Reports accurate token counts for federated responses
|
||||
|
||||
```bash
|
||||
# Machine 1 (Windows with RTX 4060)
|
||||
python main.py --auto --federation
|
||||
@@ -88,6 +94,29 @@ python main.py --auto --federation
|
||||
|
||||
Machines auto-discover each other and vote together on every request.
|
||||
|
||||
### Consensus with Federation
|
||||
1. Your prompt goes to all LLM instances across all machines
|
||||
2. Local swarm and all peers generate **in parallel** (2x faster)
|
||||
3. Wait for **all** nodes to complete generation
|
||||
4. Run global consensus across all responses
|
||||
5. Use federated result (highest confidence from all nodes)
|
||||
|
||||
### Token Reporting
|
||||
|
||||
Federation now provides accurate token counts:
|
||||
- **Prompt tokens**: Counted using tiktoken (cl100k_base encoding)
|
||||
- **Completion tokens**: Counted using tiktoken for federated response
|
||||
- **Total tokens**: Sum of prompt + completion tokens
|
||||
- **Included in**: Final streaming chunk and non-streaming responses
|
||||
|
||||
### Federation with Streaming
|
||||
|
||||
Federation works with streaming responses:
|
||||
- Local swarm and all peers generate in parallel
|
||||
- Stream content from local while waiting for federation
|
||||
- Switch to federated result when consensus complete
|
||||
- Full token reporting in streaming mode
|
||||
|
||||
## How Consensus Works
|
||||
|
||||
1. Your prompt goes to all LLM instances
|
||||
|
||||
+2
-2
@@ -555,8 +555,8 @@ async def chat_completions(request: ChatCompletionRequest, fastapi_request: Requ
|
||||
peers_count = len(federated_swarm.discovery.get_peers())
|
||||
use_federation = peers_count > 0
|
||||
|
||||
if use_federation and not has_tools:
|
||||
# Use federation - wait for ALL nodes to complete and use consensus result
|
||||
if use_federation:
|
||||
# Use federation for ALL requests (with or without tools)
|
||||
logger.debug(f"🌐 Using federation with {peers_count} peer(s) - waiting for consensus...")
|
||||
|
||||
# Run federation and get consensus result
|
||||
|
||||
@@ -0,0 +1,146 @@
|
||||
"""Unit tests for federation functionality."""
|
||||
|
||||
import sys
|
||||
import os
|
||||
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', 'src'))
|
||||
|
||||
from network.federation import FederationResult, PeerVote
|
||||
|
||||
|
||||
def test_federation_result_creation():
|
||||
"""Test FederationResult dataclass creation."""
|
||||
result = FederationResult(
|
||||
final_response="Test response",
|
||||
local_confidence=0.9,
|
||||
peer_votes=[
|
||||
PeerVote(
|
||||
peer_name="peer1",
|
||||
response_text="Peer response 1",
|
||||
confidence=0.85,
|
||||
latency_ms=100,
|
||||
worker_count=1
|
||||
),
|
||||
PeerVote(
|
||||
peer_name="peer2",
|
||||
response_text="Peer response 2",
|
||||
confidence=0.92,
|
||||
latency_ms=120,
|
||||
worker_count=1
|
||||
)
|
||||
],
|
||||
strategy="similarity",
|
||||
winner="peer2"
|
||||
)
|
||||
|
||||
assert result.final_response == "Test response"
|
||||
assert result.local_confidence == 0.9
|
||||
assert len(result.peer_votes) == 2
|
||||
assert result.strategy == "similarity"
|
||||
assert result.winner == "peer2"
|
||||
assert result.peer_votes[0].peer_name == "peer1"
|
||||
assert result.peer_votes[0].confidence == 0.85
|
||||
|
||||
|
||||
def test_peer_vote_creation():
|
||||
"""Test PeerVote dataclass creation."""
|
||||
vote = PeerVote(
|
||||
peer_name="test-peer",
|
||||
response_text="Test response content",
|
||||
confidence=0.95,
|
||||
latency_ms=100,
|
||||
worker_count=1
|
||||
)
|
||||
|
||||
assert vote.peer_name == "test-peer"
|
||||
assert vote.response_text == "Test response content"
|
||||
assert vote.confidence == 0.95
|
||||
|
||||
|
||||
def test_federation_result_empty_peers():
|
||||
"""Test FederationResult with no peer votes."""
|
||||
result = FederationResult(
|
||||
final_response="Local response",
|
||||
local_confidence=1.0,
|
||||
peer_votes=[],
|
||||
strategy="local_only",
|
||||
winner="local"
|
||||
)
|
||||
|
||||
assert result.final_response == "Local response"
|
||||
assert result.local_confidence == 1.0
|
||||
assert len(result.peer_votes) == 0
|
||||
assert result.strategy == "local_only"
|
||||
assert result.winner == "local"
|
||||
|
||||
|
||||
def test_federation_result_multiple_peers():
|
||||
"""Test FederationResult with multiple peer votes."""
|
||||
votes = [
|
||||
PeerVote(f"peer{i}", f"Response {i}", 0.8 + (i * 0.05), 100, 1)
|
||||
for i in range(5)
|
||||
]
|
||||
|
||||
result = FederationResult(
|
||||
final_response="Best response",
|
||||
local_confidence=0.75,
|
||||
peer_votes=votes,
|
||||
strategy="majority",
|
||||
winner="peer3"
|
||||
)
|
||||
|
||||
assert len(result.peer_votes) == 5
|
||||
assert result.peer_votes[2].peer_name == "peer2"
|
||||
assert result.peer_votes[4].confidence == 1.0
|
||||
|
||||
|
||||
def test_federation_result_winner_tracking():
|
||||
"""Test that winner is properly tracked."""
|
||||
result = FederationResult(
|
||||
final_response="Selected response",
|
||||
local_confidence=0.88,
|
||||
peer_votes=[
|
||||
PeerVote("peer1", "Response 1", 0.7, 80, 1),
|
||||
PeerVote("peer2", "Response 2", 0.92, 95, 1),
|
||||
PeerVote("peer3", "Response 3", 0.65, 110, 1)
|
||||
],
|
||||
strategy="highest_confidence",
|
||||
winner="peer2"
|
||||
)
|
||||
|
||||
# Verify winner is in peer_votes
|
||||
winner_names = [v.peer_name for v in result.peer_votes]
|
||||
assert result.winner in winner_names
|
||||
assert result.winner == "peer2"
|
||||
# Verify winner has highest confidence
|
||||
assert result.peer_votes[winner_names.index("peer2")].confidence == 0.92
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Run all tests
|
||||
test_functions = [
|
||||
test_federation_result_creation,
|
||||
test_peer_vote_creation,
|
||||
test_federation_result_empty_peers,
|
||||
test_federation_result_multiple_peers,
|
||||
test_federation_result_winner_tracking,
|
||||
]
|
||||
|
||||
passed = 0
|
||||
failed = 0
|
||||
|
||||
for test_func in test_functions:
|
||||
try:
|
||||
test_func()
|
||||
print(f"✓ {test_func.__name__}")
|
||||
passed += 1
|
||||
except AssertionError as e:
|
||||
print(f"✗ {test_func.__name__}: {e}")
|
||||
failed += 1
|
||||
except Exception as e:
|
||||
print(f"✗ {test_func.__name__}: Exception - {e}")
|
||||
failed += 1
|
||||
|
||||
print(f"\n{passed} passed, {failed} failed")
|
||||
|
||||
if failed > 0:
|
||||
sys.exit(1)
|
||||
Reference in New Issue
Block a user