cns/core/
Immutable domain model. No database access, no HTTP, no external dependencies. Downstream layers (services, infrastructure) consume these types.
Files
continuum.py— Continuum aggregate root. Holds state + message cache.get_messages_for_api()handles all API formatting (timestamps, multimodal, tool calls, cache control). Messages loaded externally viaapply_cache().message.py— Frozen Message dataclass. Value object with UUID identity, UTC timestamps, role validation.to_db_tuple()for DB insertion,with_metadata()for immutable updates. ExportsMessageMetadataTypedDict (all known metadata keys,total=False),ContentBlockunion type (TextBlock | ImageBlock | DocumentBlock | ContainerUploadBlock).state.py— Minimal ContinuumState (id, user_id, metadata). ExportsContinuumStateDictTypedDict forto_dict()/from_dict()round-trips. Intentionally lightweight — real state lives in the message cache.events.py— Domain event hierarchy. Four base categories: MessageEvent, ToolEvent, WorkingMemoryEvent, ContinuumCheckpointEvent. All frozen, all have.create()classmethods.TurnCompletedEvent.continuumis typed asContinuumviaTYPE_CHECKINGguard (circular import with continuum.py).stream_events.py— Mutable dataclasses for LLM streaming: TextEvent, ThinkingEvent, ToolDetectedEvent/Executing/Completed/Error, CompleteEvent, ErrorEvent, CircuitBreakerEvent, RetryEvent, FileArtifactEvent (code execution file downloads). Type-discriminated viatypefield.CompleteEvent.responseis typed asanthropic.types.Message.segment_cache_loader.py— Reconstructs message history on cache miss. Loads collapsed summaries (complexity-scored selection), continuity messages, active segment. Usessegment_helpersfor markers.
Patterns to Follow
- New events: Subclass one of the four base categories. Add a
.create()classmethod that auto-generates event_id/occurred_at and pulls user_id from contextvar. Usefrozen=True, kw_only=True. - New stream events: Subclass
StreamEvent, set a uniquetypestring default. These are mutable (streaming perf). - Message creation: Always use
Message(content=..., role=...)— id and created_at auto-generate. Never construct raw dicts when a Message would do. - Serialization: Use
to_dict()/from_dict()round-trip methods. UUIDs become strings, datetimes become ISO format at the boundary. - Metadata keys: All known keys are documented in
MessageMetadataTypedDict inmessage.py. Common keys:is_segment_boundary,status,segment_id,system_notification,has_tool_calls,tool_calls,tool_call_id,complexity_score,embedding_value.