Spaces:
Runtime error
Runtime error
| """ | |
| Base event classes and idempotency key generation for CloudEvents telemetry. | |
| This module provides: | |
| - BaseEvent: Abstract base class for all Honcho telemetry events | |
| - generate_event_id(): Deterministic event ID generation for idempotency | |
| """ | |
| import base64 | |
| import hashlib | |
| from datetime import UTC, datetime | |
| from typing import ClassVar | |
| from pydantic import BaseModel, Field | |
| def generate_event_id( | |
| event_type: str, | |
| timestamp: datetime, | |
| resource_id: str, | |
| ) -> str: | |
| """Generate a deterministic event ID for idempotency. | |
| Same inputs always produce the same ID, so retries are automatically | |
| deduplicated on the receiving end. | |
| Args: | |
| event_type: The CloudEvents type (e.g., "honcho.work.representation.completed") | |
| timestamp: When the event occurred | |
| resource_id: A unique identifier for the resource (can include workspace_id if relevant) | |
| Returns: | |
| A deterministic event ID in the format "evt_{base64_hash}" | |
| """ | |
| payload = f"{event_type}:{resource_id}:{timestamp.isoformat()}" | |
| hash_bytes = hashlib.sha256(payload.encode()).digest()[:16] | |
| # Use URL-safe base64 encoding, strip padding | |
| encoded = base64.urlsafe_b64encode(hash_bytes).decode().rstrip("=") | |
| return f"evt_{encoded}" | |
| class BaseEvent(BaseModel): | |
| """Base class for all Honcho telemetry events. | |
| All events inherit from this class and define: | |
| - _event_type: The CloudEvents type string | |
| - _schema_version: Integer version for schema evolution | |
| - _category: Event category (work, activity, resource) | |
| Subclasses must implement the abstract class methods by setting class variables | |
| and providing get_resource_id(). Subclasses define their own context fields | |
| (e.g., workspace_id, workspace_name) as needed - not all events have workspace context. | |
| """ | |
| # Class variables for event metadata (set by subclasses) | |
| _event_type: ClassVar[str] | |
| _schema_version: ClassVar[int] | |
| _category: ClassVar[str] # "work", "activity", or "resource" | |
| # Common timestamp field present in all events | |
| timestamp: datetime = Field( | |
| default_factory=lambda: datetime.now(UTC), | |
| description="When the event occurred (UTC)", | |
| ) | |
| def event_type(cls) -> str: | |
| """Return the CloudEvents type string for this event.""" | |
| return cls._event_type | |
| def schema_version(cls) -> int: | |
| """Return the schema version for this event.""" | |
| return cls._schema_version | |
| def category(cls) -> str: | |
| """Return the event category (work, activity, or resource).""" | |
| return cls._category | |
| def get_resource_id(self) -> str: | |
| """Return the resource ID for idempotency key generation. | |
| This should be a unique identifier for the specific operation, | |
| such as a task_id or a hash of message IDs. | |
| Must be implemented by subclasses. | |
| """ | |
| raise NotImplementedError("Subclasses must implement get_resource_id()") | |
| def generate_id(self) -> str: | |
| """Generate a deterministic event ID for this event instance.""" | |
| return generate_event_id( | |
| event_type=self.event_type(), | |
| timestamp=self.timestamp, | |
| resource_id=self.get_resource_id(), | |
| ) | |