57 lines
1.8 KiB
Python
57 lines
1.8 KiB
Python
"""Source connector Protocol and shared item types.
|
|
|
|
A SourceConnector adapts a third-party data source (Gmail, Slack, ...) to the
|
|
shared ScoutEngine interface. Each connector owns:
|
|
|
|
* how to enumerate new items since the last poll (``list_new``)
|
|
* how to fetch a single item's metadata cheaply (``fetch_metadata``)
|
|
* how to fetch a single item's full content for in-memory triage
|
|
(``fetch_content``) — this content MUST NOT be persisted by the engine
|
|
* how to archive/trash an item (``archive``) for spam handling
|
|
* optional push-notification setup (``setup_watch`` / ``renew_watch``)
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from datetime import datetime
|
|
from typing import Literal, Protocol
|
|
|
|
from pydantic import BaseModel, Field
|
|
|
|
|
|
class ItemRef(BaseModel):
|
|
source_msg_ref: str
|
|
received_at: datetime | None = None
|
|
|
|
|
|
class ItemMetadata(BaseModel):
|
|
subject: str | None = None
|
|
sender: str | None = None
|
|
snippet: str | None = None
|
|
received_at: datetime | None = None
|
|
|
|
|
|
class ItemContent(BaseModel):
|
|
metadata: ItemMetadata
|
|
body_text: str
|
|
raw_headers: dict[str, str] = Field(default_factory=dict)
|
|
|
|
|
|
class TriageVerdict(BaseModel):
|
|
verdict: Literal["relevant", "spam"]
|
|
reason: str
|
|
confidence: float = Field(ge=0.0, le=1.0)
|
|
|
|
|
|
class SourceConnector(Protocol):
|
|
"""Adapter for a third-party data source (Gmail, Slack, ...)."""
|
|
|
|
source_type: str # e.g. "gmail"
|
|
|
|
async def list_new(self, scout) -> list[ItemRef]: ...
|
|
async def fetch_metadata(self, scout, ref: ItemRef) -> ItemMetadata: ...
|
|
async def fetch_content(self, scout, ref: ItemRef) -> ItemContent: ...
|
|
async def archive(self, scout, ref: ItemRef) -> None: ...
|
|
async def setup_watch(self, scout) -> None: ...
|
|
async def renew_watch(self, scout) -> None: ...
|