Files
xAdmin 41e08611c9 Implement optional single-image intake, Signal ingestion, and multimodal vision analysis
- Add image intake service with format validation (JPEG, PNG, WebP) and EXIF/GPS stripping
- Enforce strict single-image rule across Web and Signal attachment channels
- Implement token-optimized vision downscaling and JPEG compression
- Add IMAGE_CONTEXT pipeline stage with OmniRoute vision routing and resilient failover
- Seed and manage versioned idea-image-interpreter prompt in catalog
- Update Web UI with responsive image picker, preview chip, and Visual Context tab
- Add comprehensive automated test suite in test_image_intake.py
- Update README and Labyricorn devlog
2026-08-23 01:40:22 -07:00

248 lines
6.6 KiB
Python

"""
ThinkStorm Data Models & Enums
Defines lifecycle states, operational entities, and schema types.
"""
from enum import Enum
from dataclasses import dataclass, field
from typing import Optional, List, Dict, Any
from datetime import datetime
class LifecycleState(str, Enum):
SUBMITTED = "SUBMITTED"
AVAILABLE = "AVAILABLE"
CLAIMED = "CLAIMED"
ACTIVE = "ACTIVE"
COMPLETED = "COMPLETED"
ABANDONED = "ABANDONED"
RETIRED = "RETIRED"
QUARANTINED = "QUARANTINED"
REJECTED = "REJECTED"
DUPLICATE = "DUPLICATE"
TRASHED = "TRASHED"
class ProcessingState(str, Enum):
IDLE = "IDLE"
QUEUED = "QUEUED"
PROCESSING = "PROCESSING"
PARTIAL = "PARTIAL"
ERROR = "ERROR"
class URLSafetyState(str, Enum):
PENDING = "PENDING"
CHECKING = "CHECKING"
SAFE = "SAFE"
SUSPICIOUS = "SUSPICIOUS"
MALICIOUS = "MALICIOUS"
UNKNOWN = "UNKNOWN"
ERROR = "ERROR"
class AutomationPolicy(str, Enum):
APPROVED = "APPROVED"
BLOCKED = "BLOCKED"
REQUIRES_REVIEW = "REQUIRES_REVIEW"
class WorkTrackState(str, Enum):
PLANNED = "PLANNED"
ACTIVE = "ACTIVE"
PAUSED = "PAUSED"
COMPLETED = "COMPLETED"
ABANDONED = "ABANDONED"
RETIRED = "RETIRED"
class UserRole(str, Enum):
ANONYMOUS = "ANONYMOUS"
USER = "USER"
ADMIN = "ADMIN"
class ProcessorStatus(str, Enum):
PENDING = "PENDING"
RUNNING = "RUNNING"
COMPLETED = "COMPLETED"
FAILED = "FAILED"
CANCELLED = "CANCELLED"
@dataclass
class User:
id: int
username: str
password_hash: str
role: UserRole = UserRole.USER
created_at: str = ""
@dataclass
class IdeaURL:
id: Optional[int]
idea_id: str
url: str
safety_state: URLSafetyState = URLSafetyState.PENDING
automation_policy: AutomationPolicy = AutomationPolicy.REQUIRES_REVIEW
virustotal_data: Dict[str, Any] = field(default_factory=dict)
admin_review_required: bool = False
reviewed_by: Optional[str] = None
reviewed_at: Optional[str] = None
decision: Optional[str] = None
@dataclass
class Idea:
id: str # e.g. TS-0001
original_text: str
submitted_at: str
title: str = ""
summary: str = ""
categories: List[str] = field(default_factory=list)
tags: List[str] = field(default_factory=list)
lifecycle_state: LifecycleState = LifecycleState.SUBMITTED
processing_state: ProcessingState = ProcessingState.IDLE
enrichment_level: int = 0
claimed_by: Optional[str] = None
claimed_at: Optional[str] = None
released_at: Optional[str] = None
previous_lifecycle_state: Optional[str] = None
trashed_at: Optional[str] = None
profile_id: Optional[str] = None
profile_version: int = 1
opengist_id: Optional[str] = None
opengist_url: Optional[str] = None
gitea_repo_name: Optional[str] = None
gitea_repo_url: Optional[str] = None
created_at: str = ""
updated_at: str = ""
urls: List[IdeaURL] = field(default_factory=list)
relationships: List[Dict[str, Any]] = field(default_factory=list)
submission_image: Optional[Dict[str, Any]] = None
source_channel: str = "web"
source_sender_uuid: Optional[str] = None
source_group_id: Optional[str] = None
source_event_id: Optional[str] = None
@dataclass
class SubmittedImage:
raw_bytes: bytes
filename: str
content_type: str
source: str = "web" # "web" | "signal"
@dataclass
class IdeaSubmission:
text: str
source: str = "web" # "web" | "signal"
image: Optional[SubmittedImage] = None
sender_uuid: Optional[str] = None
sender_number: Optional[str] = None
sender_name: Optional[str] = None
group_id: Optional[str] = None
message_id: Optional[str] = None
event_id: Optional[str] = None
reply_to: Optional[str] = None
received_at: Optional[str] = None
@dataclass
class WorkTrackOutput:
id: Optional[int]
work_track_id: str
name: str
artifact_path: str
content: str
version: int = 1
is_current: bool = True
model_used: Optional[str] = None
opengist_file: Optional[str] = None
created_at: str = ""
updated_at: str = ""
@dataclass
class WorkTrack:
id: str # e.g. WT-0001
idea_id: str
work_type_id: str # ARTICLE, BLOG_ENTRY, CODING_PROJECT, YOUTUBE_VIDEO
name: str
state: WorkTrackState = WorkTrackState.PLANNED
workflow_id: str = ""
model_override: Optional[str] = None
created_at: str = ""
started_at: Optional[str] = None
completed_at: Optional[str] = None
outputs: List[WorkTrackOutput] = field(default_factory=list)
external_resources: List[Dict[str, Any]] = field(default_factory=list)
@dataclass
class PromptVersion:
id: Optional[int]
prompt_definition_id: str
version: int
system_prompt: str
user_prompt_template: str
applies_to: Dict[str, Any] = field(default_factory=dict)
model_policy: str = "reasoning"
expected_outputs: List[str] = field(default_factory=list)
prompt_hash: str = ""
created_by: str = "system"
created_at: str = ""
@dataclass
class PromptDefinition:
id: str # e.g. prior-art-software
name: str
stage: str
description: str
current_version: int = 1
enabled: bool = True
created_at: str = ""
versions: List[PromptVersion] = field(default_factory=list)
@dataclass
class PromptProfile:
id: str # e.g. software-idea-v1
name: str
description: str
prompt_assignments: Dict[str, str] = field(default_factory=dict) # stage -> prompt_id@version
is_default: bool = False
created_at: str = ""
@dataclass
class ProcessorRun:
id: str # e.g. RUN-0001
idea_id: str
work_track_id: Optional[str]
processor_name: str
stage: str
prompt_id: Optional[str]
prompt_version: Optional[int]
prompt_hash: Optional[str]
model_policy: str
resolved_provider: str
resolved_model: str
input_tokens: int = 0
output_tokens: int = 0
total_tokens: int = 0
started_at: str = ""
completed_at: Optional[str] = None
duration_ms: int = 0
output_artifact: Optional[str] = None
output_data: Dict[str, Any] = field(default_factory=dict)
error_message: Optional[str] = None
status: ProcessorStatus = ProcessorStatus.PENDING
@dataclass
class ServiceConfig:
id: str
name: str
endpoint: str
api_key_masked: str
enabled: bool
config_json: Dict[str, Any] = field(default_factory=dict)
last_tested_at: Optional[str] = None
health_status: str = "UNKNOWN"
last_error: Optional[str] = None
@dataclass
class AuditEvent:
id: Optional[int]
user_id: str
action: str
entity_type: str
entity_id: str
details: Dict[str, Any]
created_at: str = ""