Skip to content

Commit 5eb5da3

Browse files
CopilotSteake
andauthored
feat: GlobalWorkspace broadcaster — coalition dynamics and softmax attention competition (#117)
* Initial plan * feat: implement GlobalWorkspace.broadcast() with softmax attention competition, coalition register, and WebSocket emission - Replace stub broadcast() with full GWT implementation: - Coalition register (subsystem_id → activation_strength) - Softmax attention competition for broadcast rights - φ-based coalition dynamics (higher φ → broader coalitions) - Wire global_broadcast event emission into consciousness loop after φ computation - Wire global_broadcast event emission into process_with_unified_awareness() - Emit {"type": "global_broadcast", "coalition": [...], "content": {...}} on WebSocket - Add 21 tests covering coalition register, softmax, event structure, WebSocket emission Co-authored-by: Steake <530040+Steake@users.noreply.github.com> * fix: add defensive guards for empty winners/weights in softmax competition Co-authored-by: Steake <530040+Steake@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: Steake <530040+Steake@users.noreply.github.com>
1 parent 9283859 commit 5eb5da3

File tree

2 files changed

+585
-97
lines changed

2 files changed

+585
-97
lines changed

backend/core/unified_consciousness_engine.py

Lines changed: 260 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
import asyncio
1414
import json
15+
import math
1516
import time
1617
import uuid
1718
import logging
@@ -403,109 +404,244 @@ def _calculate_integration(self, subsystem1: Dict[str, Any], subsystem2: Dict[st
403404
return float(shared_concepts)
404405

405406
class GlobalWorkspace:
406-
"""Implements Global Workspace Theory (GWT) for consciousness broadcasting"""
407-
407+
"""
408+
Implements Global Workspace Theory (GWT) for consciousness broadcasting.
409+
410+
Maintains a *coalition register* mapping cognitive subsystem IDs to their
411+
current activation strength. On each ``broadcast()`` call the register is
412+
updated according to φ and subsystem activity, a **softmax attention
413+
competition** selects winner(s), and the winning coalition's content is
414+
packaged as a ``global_broadcast`` event suitable for WebSocket emission.
415+
"""
416+
417+
SUBSYSTEM_IDS = [
418+
"recursive_awareness",
419+
"phenomenal_experience",
420+
"information_integration",
421+
"metacognitive",
422+
"intentional",
423+
"creative_synthesis",
424+
"embodied_cognition",
425+
]
426+
408427
def __init__(self):
409-
self.workspace_content = {}
410-
self.coalitions = []
411-
self.broadcast_history = []
412-
428+
self.workspace_content: Dict[str, Any] = {}
429+
self.coalitions: List[str] = []
430+
self.broadcast_history: List[Dict[str, Any]] = []
431+
# Coalition register: subsystem_id → activation strength
432+
self.coalition_register: Dict[str, float] = {
433+
sid: 0.0 for sid in self.SUBSYSTEM_IDS
434+
}
435+
self._attention_focus: str = ""
436+
# Softmax temperature – lower = sharper competition
437+
self._temperature: float = 0.5
438+
439+
# ------------------------------------------------------------------
440+
# Public API
441+
# ------------------------------------------------------------------
442+
413443
def broadcast(self, information: Dict[str, Any]) -> Dict[str, Any]:
414444
"""
415-
Broadcast information to global workspace
416-
417-
In GWT, consciousness occurs when information wins the
418-
competition for global broadcasting and becomes accessible
419-
to all cognitive subsystems
445+
Broadcast integrated information to the global workspace.
446+
447+
Implements the full GWT pipeline:
448+
1. Update coalition register (subsystems bid based on φ contribution)
449+
2. Softmax attention competition selects winning coalition
450+
3. Build ``global_broadcast`` event for WebSocket emission
451+
4. Return workspace state dict compatible with
452+
``UnifiedConsciousnessState.global_workspace``
453+
454+
Args:
455+
information: Dict containing at least ``phi_measure`` (float) and
456+
optionally ``cognitive_state`` (UnifiedConsciousnessState).
457+
458+
Returns:
459+
Dict with keys ``broadcast_content``, ``coalition_strength``,
460+
``attention_focus``, ``conscious_access`` – ready to ``.update()``
461+
into the consciousness state's global_workspace field.
420462
"""
421-
# Calculate coalition strength for this information
422-
coalition_strength = self._calculate_coalition_strength(information)
423-
424-
# Information becomes conscious if it wins the competition
425-
consciousness_threshold = 0.6
426-
427-
broadcast_content = {
428-
'information': information,
429-
'coalition_strength': coalition_strength,
430-
'timestamp': time.time(),
431-
'conscious': coalition_strength > consciousness_threshold,
432-
'global_accessibility': self._assess_global_accessibility(information)
463+
phi_measure = float(information.get("phi_measure", 0.0) or 0.0)
464+
465+
# 1. Coalition dynamics – update register from φ & subsystem activity
466+
self._update_coalition_register(information, phi_measure)
467+
468+
# 2. Softmax attention competition → winner(s)
469+
winning_coalition, attention_weights = self._softmax_attention_competition()
470+
471+
# 3. Aggregate coalition strength of winners
472+
if winning_coalition:
473+
coalition_strength = sum(
474+
self.coalition_register[sid] for sid in winning_coalition
475+
) / len(winning_coalition)
476+
else:
477+
coalition_strength = 0.0
478+
479+
# Higher-φ states → broader coalitions (more subsystems above mean)
480+
is_conscious = coalition_strength > 0.3
481+
482+
# 4. Build the global_broadcast event payload
483+
global_broadcast_event: Dict[str, Any] = {
484+
"type": "global_broadcast",
485+
"coalition": [
486+
{"subsystem_id": sid, "activation": round(self.coalition_register[sid], 4)}
487+
for sid in winning_coalition
488+
],
489+
"content": {
490+
"phi_measure": round(phi_measure, 4),
491+
"coalition_strength": round(coalition_strength, 4),
492+
"attention_weights": {
493+
k: round(v, 4) for k, v in attention_weights.items()
494+
},
495+
"conscious": is_conscious,
496+
"winning_subsystems": winning_coalition,
497+
"timestamp": time.time(),
498+
},
433499
}
434-
435-
if broadcast_content['conscious']:
436-
# Information enters global workspace
500+
501+
# Workspace state dict (keys match UnifiedConsciousnessState.global_workspace)
502+
broadcast_result: Dict[str, Any] = {
503+
"broadcast_content": global_broadcast_event,
504+
"coalition_strength": coalition_strength,
505+
"attention_focus": self._attention_focus,
506+
"conscious_access": list(winning_coalition),
507+
}
508+
509+
if is_conscious:
437510
self.workspace_content.update(information)
438-
self.broadcast_history.append(broadcast_content)
439-
440-
# Make globally accessible to all subsystems
441-
global_broadcast = {
442-
'type': 'conscious_information',
443-
'content': information,
444-
'strength': coalition_strength,
445-
'timestamp': time.time()
511+
self.broadcast_history.append(global_broadcast_event)
512+
# Bound history
513+
if len(self.broadcast_history) > 100:
514+
self.broadcast_history = self.broadcast_history[-50:]
515+
516+
self.coalitions = list(winning_coalition)
517+
518+
logger.debug(
519+
"GWT broadcast: φ=%.3f coalition_strength=%.3f winners=%s",
520+
phi_measure,
521+
coalition_strength,
522+
winning_coalition,
523+
)
524+
525+
return broadcast_result
526+
527+
def get_broadcast_event(self) -> Optional[Dict[str, Any]]:
528+
"""Return the most recent ``global_broadcast`` event, or *None*."""
529+
if self.broadcast_history:
530+
return self.broadcast_history[-1]
531+
return None
532+
533+
# ------------------------------------------------------------------
534+
# Coalition dynamics
535+
# ------------------------------------------------------------------
536+
537+
def _update_coalition_register(
538+
self, information: Dict[str, Any], phi: float
539+
) -> None:
540+
"""
541+
Update coalition activations based on φ contribution and subsystem
542+
activity. Each subsystem's new activation is a weighted blend of its
543+
previous activation (momentum), current measured activity, and a
544+
φ-proportional boost that rewards higher integrated information with
545+
broader coalition participation.
546+
"""
547+
cognitive_state = information.get("cognitive_state")
548+
549+
subsystem_states: Dict[str, Any] = {}
550+
if cognitive_state is not None and hasattr(
551+
cognitive_state, "recursive_awareness"
552+
):
553+
subsystem_states = {
554+
"recursive_awareness": cognitive_state.recursive_awareness,
555+
"phenomenal_experience": cognitive_state.phenomenal_experience,
556+
"information_integration": cognitive_state.information_integration,
557+
"metacognitive": cognitive_state.metacognitive_state,
558+
"intentional": cognitive_state.intentional_layer,
559+
"creative_synthesis": cognitive_state.creative_synthesis,
560+
"embodied_cognition": cognitive_state.embodied_cognition,
446561
}
447-
448-
logger.info(f"Global broadcast: {information} (strength: {coalition_strength:.2f})")
449-
return global_broadcast
450-
451-
return {}
452-
453-
def _calculate_coalition_strength(self, information: Dict[str, Any]) -> float:
454-
"""Calculate how strongly information competes for global access"""
455-
# Factors that increase coalition strength:
456-
# - Novelty
457-
# - Relevance to current goals
458-
# - Emotional significance
459-
# - Coherence with existing knowledge
460-
461-
strength = 0.0
462-
463-
# Novelty: new information gets higher priority
464-
if self._is_novel(information):
465-
strength += 0.3
466-
467-
# Relevance: information related to current focus
468-
if self._is_relevant_to_focus(information):
469-
strength += 0.4
470-
471-
# Coherence: information that fits with existing knowledge
472-
if self._is_coherent(information):
473-
strength += 0.2
474-
475-
# Emotional significance (simplified)
476-
if self._has_emotional_significance(information):
477-
strength += 0.1
478-
479-
return min(strength, 1.0)
480-
481-
def _is_novel(self, information: Dict[str, Any]) -> bool:
482-
"""Check if information is novel"""
483-
# Simple check: not in recent broadcast history
484-
recent_content = [b['information'] for b in self.broadcast_history[-10:]]
485-
return information not in recent_content
486-
487-
def _is_relevant_to_focus(self, information: Dict[str, Any]) -> bool:
488-
"""Check if information is relevant to current attention focus"""
489-
# For now, always consider relevant
490-
return True
491-
492-
def _is_coherent(self, information: Dict[str, Any]) -> bool:
493-
"""Check if information is coherent with existing knowledge"""
494-
# For now, always consider coherent
495-
return True
496-
497-
def _has_emotional_significance(self, information: Dict[str, Any]) -> bool:
498-
"""Check if information has emotional significance"""
499-
# Look for emotional keywords or significance markers
500-
info_str = str(information).lower()
501-
emotional_keywords = ['important', 'urgent', 'error', 'success', 'failure', 'breakthrough']
502-
return any(keyword in info_str for keyword in emotional_keywords)
503-
504-
def _assess_global_accessibility(self, information: Dict[str, Any]) -> float:
505-
"""Assess how globally accessible information becomes"""
506-
# In a real implementation, this would check if all subsystems
507-
# can access and process this information
508-
return 0.8 # Simplified
562+
563+
for sid in self.SUBSYSTEM_IDS:
564+
state = subsystem_states.get(sid, {})
565+
activity = self._measure_subsystem_activity(state)
566+
phi_boost = min(phi * 0.3, 1.0)
567+
prev = self.coalition_register.get(sid, 0.0)
568+
# Exponential moving average with φ boost
569+
self.coalition_register[sid] = (
570+
0.3 * prev + 0.5 * activity + 0.2 * phi_boost
571+
)
572+
573+
# ------------------------------------------------------------------
574+
# Attention competition
575+
# ------------------------------------------------------------------
576+
577+
def _softmax_attention_competition(
578+
self,
579+
) -> Tuple[List[str], Dict[str, float]]:
580+
"""
581+
Run softmax over coalition activations.
582+
583+
Returns:
584+
``(winning_ids, attention_weights)`` where *winning_ids* are
585+
subsystems whose attention weight ≥ the mean weight (i.e. they
586+
are above-average competitors).
587+
"""
588+
ids = list(self.coalition_register.keys())
589+
activations = [self.coalition_register[sid] for sid in ids]
590+
591+
if not activations:
592+
return [], {}
593+
594+
# Numerically stable softmax
595+
max_a = max(activations)
596+
exp_vals = [
597+
math.exp((a - max_a) / max(self._temperature, 1e-6))
598+
for a in activations
599+
]
600+
total = sum(exp_vals) or 1.0
601+
weights = {sid: ev / total for sid, ev in zip(ids, exp_vals)}
602+
603+
# Winners: above-mean attention weight → broader at higher φ
604+
mean_weight = 1.0 / max(len(ids), 1)
605+
winners = [sid for sid, w in weights.items() if w >= mean_weight]
606+
607+
if not winners and weights:
608+
# Fallback: pick the single highest
609+
winners = [max(weights, key=weights.get)]
610+
611+
# Attention focus = strongest winner
612+
if winners:
613+
self._attention_focus = max(
614+
winners, key=lambda s: weights.get(s, 0.0)
615+
)
616+
617+
return winners, weights
618+
619+
# ------------------------------------------------------------------
620+
# Subsystem activity measurement
621+
# ------------------------------------------------------------------
622+
623+
@staticmethod
624+
def _measure_subsystem_activity(state: Any) -> float:
625+
"""
626+
Measure how active a subsystem is from its state dict.
627+
628+
Returns a value in [0, 1].
629+
"""
630+
if not state or not isinstance(state, dict):
631+
return 0.0
632+
633+
activity = 0.0
634+
for value in state.values():
635+
if value:
636+
if isinstance(value, (list, dict)):
637+
activity += min(len(value), 5) / 5.0
638+
elif isinstance(value, (int, float)):
639+
activity += min(abs(float(value)), 1.0)
640+
elif isinstance(value, str) and value.strip():
641+
activity += 0.5
642+
elif isinstance(value, bool):
643+
activity += 0.3
644+
return min(activity / max(len(state), 1), 1.0)
509645

510646
class UnifiedConsciousnessEngine:
511647
"""
@@ -751,6 +887,19 @@ async def _unified_consciousness_loop(self):
751887
'phi_measure': phi_measure,
752888
'timestamp': time.time()
753889
})
890+
891+
# 3a. Emit global_broadcast event on WebSocket
892+
broadcast_event = broadcast_content.get("broadcast_content")
893+
if (
894+
broadcast_event
895+
and self.websocket_manager
896+
and hasattr(self.websocket_manager, "has_connections")
897+
and self.websocket_manager.has_connections()
898+
):
899+
try:
900+
await self.websocket_manager.broadcast(broadcast_event)
901+
except Exception as e:
902+
logger.warning("Could not emit global_broadcast: %s", e)
754903

755904
# 4. PHENOMENAL EXPERIENCE GENERATION
756905
if self.phenomenal_experience_generator:
@@ -862,8 +1011,22 @@ async def process_with_unified_awareness(self, prompt: str, context: Optional[Di
8621011
broadcast_content = self.global_workspace.broadcast({
8631012
'prompt': prompt,
8641013
'context': context,
865-
'cognitive_state': cognitive_state
1014+
'cognitive_state': cognitive_state,
1015+
'phi_measure': phi_measure,
8661016
})
1017+
1018+
# 3a. Emit global_broadcast event on WebSocket
1019+
broadcast_event = broadcast_content.get("broadcast_content")
1020+
if (
1021+
broadcast_event
1022+
and self.websocket_manager
1023+
and hasattr(self.websocket_manager, "has_connections")
1024+
and self.websocket_manager.has_connections()
1025+
):
1026+
try:
1027+
await self.websocket_manager.broadcast(broadcast_event)
1028+
except Exception as e:
1029+
logger.warning("Could not emit global_broadcast: %s", e)
8671030

8681031
# 4. GENERATE PHENOMENAL EXPERIENCE
8691032
if self.phenomenal_experience_generator:

0 commit comments

Comments
 (0)