Cortex API (semvec.cortex)¶
Multi-agent coordination primitives. Install with pip install "semvec[cortex]".
SemvecAgentNetwork¶
Container for multiple SemvecAgent objects aggregated into one SemvecCortexObserver.
from semvec.cortex import SemvecAgentNetwork, AttentionAggregation
net = SemvecAgentNetwork(
aggregation_strategy=AttentionAggregation(),
enable_feedback=True,
feedback_strength=0.3,
max_instances=10,
)
net.add_local_instance("analyst")
net.add_local_instance("planner")
net.process_input("analyst", "quarterly revenue is up 23%")
state = net.get_network_state()
Methods¶
| Method | Purpose |
|---|---|
add_instance(id) / add_local_instance(id) |
Register a new agent. |
remove_local_instance(id) |
Unregister. |
process_input(instance_id, text) |
Drive one agent; MetaPSS updates internally per call. |
get_network_state() -> dict |
Snapshot coherence + per-agent metrics. |
Attributes¶
| Attribute | Type |
|---|---|
local_instances |
dict[str, SemvecAgent] |
meta_pss |
SemvecCortexObserver |
enable_feedback |
bool |
feedback_strength |
float |
max_instances |
int |
SemvecAgent¶
Per-agent PSS state.
from semvec.cortex import SemvecAgent
# `dimension=` propagates to the inner SemvecState. Use 768 for
# mpnet (recommended for German/multilingual), 384 for MiniLM.
# Default is 384.
inst = SemvecAgent("agent_a", embedder=my_embedder, dimension=768)
assert inst.pss_state.config.dimension == 768
result = inst.process_input("hello")
# or bypass text embedding:
result = inst.process_input_embedding(vector, "hello")
Missing embedder in process_input raises RuntimeError with guidance to either set embedder= or call process_input_embedding directly. Embedding-dimension mismatches in process_input_embedding raise ValueError (≥ 0.3.2 — pre-fix this was a Rust assertion panic that aborted the interpreter).
process_input(text, global_feedback=None) -> dict¶
| Parameter | Type | Default | Description |
|---|---|---|---|
text |
str |
— | Input text. Embedded with the agent's injected embedder. |
global_feedback |
list[float] | np.ndarray | None |
None |
Optional meta-PSS / cortex feedback vector. When supplied, the input embedding is blended via (1 − 0.1) · embedding + 0.1 · feedback before the PSS update. Use this with SemvecCortexService.get_feedback_for_agent() to align an agent with the network consensus. |
Returns the same dict as SemvecState.update() plus the per-agent keys instance_id, local_coherence, global_influence, state_vector, interaction_count.
process_input_embedding(embedding, text, global_feedback=None) -> dict¶
Same signature minus the embedder call. Use when you already have a normalised vector (e.g. batch-embedded offline).
Attributes¶
instance_id, local_coherence (read / write), interaction_count, global_influence (read / write), last_update_time, min_coherence_threshold, pss_state (read / write — used by SemvecCortexService when hydrating from a store).
SemvecCortexObserver¶
Aggregator for a collection of locals.
from semvec.cortex import SemvecCortexObserver, WeightedAverageAggregation
meta = SemvecCortexObserver(
aggregation_strategy=WeightedAverageAggregation(dimension=384),
dimension=384,
)
meta.update_global_state([local_a, local_b, local_c])
feedback = meta.get_feedback_for_instance("agent_a")
| Attribute | Type |
|---|---|
global_state |
list[float] |
global_coherence |
float |
network_resonance |
float |
beta_global |
float |
update_count |
int |
Aggregation strategies¶
WeightedAverageAggregation¶
aggregate(local_states, weights=None) — simple weighted mean with automatic None → uniform weights.
AttentionAggregation¶
Query/key/value attention with learnable projections. Constructed with AttentionAggregation(attention_dim=64, dimension=384).
Documented numeric drift
Projection matrices are seeded differently in pss (NumPy PCG64) and semvec (Rust StdRng), so byte-level aggregate outputs diverge even at the same seed. Structural invariants (shape, determinism per instance, softmax sum = 1) match exactly. See MIGRATION.md §Numerical Fidelity.
ConsensusEngine + ConsensusProposal + ConsensusLevel¶
from semvec.cortex import ConsensusEngine, ConsensusLevel
import numpy as np
engine = ConsensusEngine("me", "net_0")
for voter in ("cto", "sre", "fin_ops"):
engine.register_instance(voter, weight=1.0)
proposal = engine.create_proposal(
"state_update",
proposed_state=np.zeros(8),
rationale="move to Postgres 16",
consensus_level=ConsensusLevel.QUALIFIED_MAJORITY,
voting_timeout=300.0,
)
engine.vote_on_proposal(proposal.proposal_id, True, "cto")
engine.vote_on_proposal(proposal.proposal_id, True, "sre")
engine.vote_on_proposal(proposal.proposal_id, False, "fin_ops")
print(proposal.calculate_consensus()) # (True, 2/3)
ConsensusLevel is a string enum with members SIMPLE_MAJORITY, QUALIFIED_MAJORITY, UNANIMOUS, WEIGHTED_VOTE, ADAPTIVE_THRESHOLD. Threshold semantics match pss exactly.
Shared-state semantics¶
create_proposal returns a ConsensusProposal linked to the engine's internal storage. Voting through engine.vote_on_proposal(proposal_id, …) is reflected in the returned object. Once consensus is reached, the proposal is moved from active_proposals to proposal_history and further votes on the same ID return False.
Quorum semantics (≥ 0.3.2)¶
create_proposal snapshots the engine's known_instances voter pool at proposal-creation time. calculate_consensus then measures positive_weight / total_voter_pool_weight — not positive / votes_cast_so_far. Concretely: with 3 registered instances and SimpleMajority, the first YES gives ratio 1/3 (not reached), the second YES gives 2/3 > 0.5 (reached), and the third vote is silently rejected because the proposal was already finalised on vote #2.
Pre-0.3.2 the denominator was votes.len(), so the first local YES already produced 1/1 = 1.0 and tripped SimpleMajority before any remote instance could vote — remote votes were silently dropped. The pre-fix behaviour is still preserved when a ConsensusProposal is constructed directly without an engine (parity-test path).
StateVectorPacket + TransferType¶
Inter-agent state transfer with SHA-256/16 checksumming.
from semvec.cortex import StateVectorPacket, TransferType
import numpy as np
packet = StateVectorPacket(
packet_id="pkt_1",
source_instance="agent_a",
target_instance="agent_b",
transfer_type=TransferType.FULL_STATE,
state_vector=np.arange(16, dtype=np.float64),
)
blob = packet.serialize() # bytes (JSON)
restored = StateVectorPacket.deserialize(blob)
assert restored.verify_integrity()
TransferType members: FULL_STATE, PARTIAL_STATE, SEMANTIC_DELTA, MEMORY_FRAGMENT, COHERENCE_FIELD.
Bit-exact serialisation (≥ 0.3.2). The wire format carries a state_vector_bits: [u64, …] field with the IEEE 754 bit pattern of the state vector alongside the human-readable float array. Deserialisation prefers the bit pattern, so verify_integrity() returns True after a serialize → deserialize round-trip even on values that JSON's float encoder would otherwise round to a slightly different representation. Pre-0.3.2 the integrity check failed on freshly serialised packets because of that lossy round-trip.
SemvecCortexService¶
Cortex-as-a-service facade — a 1:1 port of pss.integrations.meta_pss_service.MetaPSSService. Coordinates multiple agents (1 per task/tenant) via attention-based or weighted-average aggregation, and exposes a global feedback vector that individual agents can mix into their updates.
from semvec.cortex import SemvecCortexService
svc = SemvecCortexService(
pss_store=None, # optional async store (see below)
aggregation="attention", # or "weighted"
dimension=384,
)
Constructor¶
| Argument | Type | Default | Description |
|---|---|---|---|
pss_store |
Protocol (async) or None |
None |
Any object exposing async list_active_states() -> Iterable[tuple[str, SemvecState]]. When None, the service runs fully in-memory and aggregates whatever was fed via register_agent() + process_input(). |
aggregation |
"attention" \| "weighted" |
"attention" |
Aggregation strategy. Any other value raises ValueError. |
dimension |
int |
384 |
Shared embedding dimension for agents and the aggregator. |
Methods¶
register_agent(agent_id) -> bool— register a new agent on the in-memory network; returnsFalseif already known.process_input(agent_id, text) -> dict— drive one turn of the named agent (in-memory path; needs an embedder).async update_global_state() -> dict— aggregate all active agents. Reads viapss_store.list_active_states()when a store is set, otherwise from the local cache populated byregister_agent. Returns a dict withglobal_state,global_coherence,network_resonance,active_instances.async get_global_context() -> str— human-readable summary for system prompts ("Global Coherence: 0.73, Network Resonance: 0.61, Active Agents: 3").get_feedback_for_agent(agent_id) -> np.ndarray— per-agent feedback vector of shape(dimension,). Agents mix this into their updates viaSemvecAgent.process_input(text, global_feedback=fb)._calculate_coherence(state) -> float/_calculate_influence(state) -> float— expose the scoring math used for weighting aggregates (pure compute on aSemvecState).