snapkitty
compilers
c
python
nasm
SNAPKITTYWEST's picture
push from SNAPKITTYWEST/sovereign-engine-v2
9abace2 verified
Raw History Blame Contribute Delete
13.1 kB
"""
Sovereign LLM Engine — Parallel Swarm Coordinator
Part of SOVEREIGN PYTHON LLM ENGINE
Coordinates N concurrent async agent tasks using asyncio primitives.
Supports fan_out, map_reduce, and race patterns with configurable
concurrency limits, per-task timeouts, and result aggregation.
"""
from __future__ import annotations
import asyncio
import logging
import time
from dataclasses import dataclass, field
from typing import Any, Callable, Coroutine, TypeVar
logger = logging.getLogger("sovereign.swarm")
T = TypeVar("T")
R = TypeVar("R")
# Type aliases for readability
AgentCallable = Callable[..., Coroutine[Any, Any, Any]]
Mapper = Callable[[Any], Coroutine[Any, Any, Any]]
Reducer = Callable[[list[Any]], Coroutine[Any, Any, Any]]
# ==========================================
# Result Types
# ==========================================
@dataclass
class TaskOutcome:
"""Outcome of a single task within a swarm operation."""
index: int
success: bool
value: Any = None
error: str | None = None
latency_ms: float = 0.0
@dataclass
class SwarmResult:
"""
Aggregated result from a swarm operation.
Attributes:
results: Successful results in order of completion (or index for fan_out).
failures: Failed task outcomes.
latency_ms: Wall-clock time for the entire swarm operation.
winner: For race() operations — the first successful result value.
"""
results: list[Any]
failures: list[TaskOutcome]
latency_ms: float
winner: Any | None = None
@property
def success_count(self) -> int:
return len(self.results)
@property
def failure_count(self) -> int:
return len(self.failures)
@property
def total_count(self) -> int:
return self.success_count + self.failure_count
@property
def all_succeeded(self) -> bool:
return self.failure_count == 0
def __repr__(self) -> str:
return (
f"SwarmResult(success={self.success_count}, "
f"failures={self.failure_count}, "
f"latency_ms={self.latency_ms:.1f})"
)
# ==========================================
# Internal helpers
# ==========================================
async def _run_with_timeout(
coro: Coroutine[Any, Any, T],
timeout: float | None,
index: int,
semaphore: asyncio.Semaphore,
) -> TaskOutcome:
"""
Run a coroutine under a semaphore and optional timeout.
Returns a TaskOutcome regardless of success or failure.
"""
start = time.monotonic()
async with semaphore:
try:
if timeout is not None:
value = await asyncio.wait_for(coro, timeout=timeout)
else:
value = await coro
latency = (time.monotonic() - start) * 1000.0
return TaskOutcome(index=index, success=True, value=value, latency_ms=latency)
except asyncio.TimeoutError:
latency = (time.monotonic() - start) * 1000.0
return TaskOutcome(
index=index,
success=False,
error=f"Task {index} timed out after {timeout}s",
latency_ms=latency,
)
except Exception as exc:
latency = (time.monotonic() - start) * 1000.0
return TaskOutcome(
index=index,
success=False,
error=f"{type(exc).__name__}: {exc}",
latency_ms=latency,
)
# ==========================================
# Swarm
# ==========================================
class Swarm:
"""
Parallel swarm coordinator.
All operations respect a global concurrency limit (semaphore) and an
optional per-task timeout. Tasks that exceed the timeout are recorded
as failures rather than raising exceptions.
Args:
concurrency: Maximum number of tasks running simultaneously.
task_timeout: Per-task timeout in seconds (None = unlimited).
"""
def __init__(
self,
concurrency: int = 16,
task_timeout: float | None = 60.0,
) -> None:
if concurrency < 1:
raise ValueError("concurrency must be >= 1")
self._concurrency = concurrency
self._task_timeout = task_timeout
# ------------------------------------------------------------------
# fan_out
# ------------------------------------------------------------------
async def fan_out(
self,
task: Any,
agents: list[AgentCallable],
) -> SwarmResult:
"""
Dispatch the same task to every agent concurrently.
Each agent in `agents` is called as ``agent(task)``.
Results are returned in the same order as the agent list.
Failures do not block other agents.
Returns:
SwarmResult with results indexed to match agent positions.
"""
if not agents:
return SwarmResult(results=[], failures=[], latency_ms=0.0)
semaphore = asyncio.Semaphore(self._concurrency)
wall_start = time.monotonic()
coros = [
_run_with_timeout(agent(task), self._task_timeout, idx, semaphore)
for idx, agent in enumerate(agents)
]
outcomes: list[TaskOutcome] = await asyncio.gather(*coros)
wall_ms = (time.monotonic() - wall_start) * 1000.0
# Preserve original index order for results
ordered_results: list[Any] = [None] * len(agents)
failures: list[TaskOutcome] = []
for outcome in outcomes:
if outcome.success:
ordered_results[outcome.index] = outcome.value
else:
failures.append(outcome)
logger.warning(
"fan_out agent[%d] failed: %s", outcome.index, outcome.error
)
# Remove None slots for failed agents so callers get a clean list
success_results = [
ordered_results[i]
for i in range(len(agents))
if outcomes[i].success
]
return SwarmResult(
results=success_results,
failures=failures,
latency_ms=wall_ms,
)
# ------------------------------------------------------------------
# map_reduce
# ------------------------------------------------------------------
async def map_reduce(
self,
items: list[Any],
mapper: Mapper,
reducer: Reducer,
) -> SwarmResult:
"""
Map items through an async mapper concurrently, then reduce.
Each item in `items` is passed to ``mapper(item)`` concurrently.
Successful mapped values are collected and passed to ``reducer(values)``.
The reducer result is the single entry in SwarmResult.results.
Failures in individual map tasks are recorded; the reducer only
receives successfully mapped values. If all maps fail, the reducer
is not called and SwarmResult.results is empty.
Returns:
SwarmResult where results[0] is the reducer output (if any map succeeded).
"""
if not items:
reduced = await reducer([])
return SwarmResult(results=[reduced], failures=[], latency_ms=0.0)
semaphore = asyncio.Semaphore(self._concurrency)
wall_start = time.monotonic()
map_coros = [
_run_with_timeout(mapper(item), self._task_timeout, idx, semaphore)
for idx, item in enumerate(items)
]
map_outcomes: list[TaskOutcome] = await asyncio.gather(*map_coros)
mapped_values: list[Any] = []
failures: list[TaskOutcome] = []
for outcome in map_outcomes:
if outcome.success:
mapped_values.append(outcome.value)
else:
failures.append(outcome)
logger.warning(
"map_reduce mapper[%d] failed: %s", outcome.index, outcome.error
)
results: list[Any] = []
if mapped_values:
try:
reduced_value = await reducer(mapped_values)
results = [reduced_value]
except Exception as exc:
logger.exception("map_reduce reducer failed: %s", exc)
failures.append(
TaskOutcome(
index=-1,
success=False,
error=f"Reducer {type(exc).__name__}: {exc}",
)
)
wall_ms = (time.monotonic() - wall_start) * 1000.0
return SwarmResult(results=results, failures=failures, latency_ms=wall_ms)
# ------------------------------------------------------------------
# race
# ------------------------------------------------------------------
async def race(
self,
tasks: list[Coroutine[Any, Any, Any]],
) -> SwarmResult:
"""
Run tasks concurrently and return the first successful result.
All remaining tasks are cancelled once a winner is found.
If all tasks fail, SwarmResult.winner is None and all failures
are recorded.
Returns:
SwarmResult with winner set to the first successful value.
results contains only the winning value (or empty if all failed).
"""
if not tasks:
return SwarmResult(results=[], failures=[], latency_ms=0.0, winner=None)
semaphore = asyncio.Semaphore(self._concurrency)
wall_start = time.monotonic()
# Wrap each coroutine in a task
loop = asyncio.get_running_loop()
pending: set[asyncio.Task[TaskOutcome]] = set()
for idx, coro in enumerate(tasks):
t = loop.create_task(
_run_with_timeout(coro, self._task_timeout, idx, semaphore)
)
pending.add(t)
winner: Any | None = None
winner_found = False
failures: list[TaskOutcome] = []
while pending:
done, pending = await asyncio.wait(
pending, return_when=asyncio.FIRST_COMPLETED
)
for finished in done:
outcome: TaskOutcome = finished.result()
if outcome.success and not winner_found:
winner = outcome.value
winner_found = True
logger.debug(
"race winner: task[%d] in %.1fms",
outcome.index,
outcome.latency_ms,
)
# Cancel remaining tasks
for remaining in pending:
remaining.cancel()
# Drain cancelled tasks
if pending:
await asyncio.gather(*pending, return_exceptions=True)
pending = set()
break
elif not outcome.success:
failures.append(outcome)
wall_ms = (time.monotonic() - wall_start) * 1000.0
if winner_found:
return SwarmResult(
results=[winner],
failures=failures,
latency_ms=wall_ms,
winner=winner,
)
else:
return SwarmResult(
results=[],
failures=failures,
latency_ms=wall_ms,
winner=None,
)
# ------------------------------------------------------------------
# Batch helper
# ------------------------------------------------------------------
async def batch(
self,
coros: list[Coroutine[Any, Any, Any]],
) -> SwarmResult:
"""
Run an arbitrary list of coroutines concurrently with the swarm
concurrency and timeout settings. Results are in completion order.
This is a lower-level primitive used internally; fan_out and
map_reduce are preferred for agent patterns.
"""
if not coros:
return SwarmResult(results=[], failures=[], latency_ms=0.0)
semaphore = asyncio.Semaphore(self._concurrency)
wall_start = time.monotonic()
wrapped = [
_run_with_timeout(coro, self._task_timeout, idx, semaphore)
for idx, coro in enumerate(coros)
]
outcomes: list[TaskOutcome] = await asyncio.gather(*wrapped)
results = [o.value for o in outcomes if o.success]
failures = [o for o in outcomes if not o.success]
wall_ms = (time.monotonic() - wall_start) * 1000.0
return SwarmResult(results=results, failures=failures, latency_ms=wall_ms)