78 lines
2.6 KiB
Python
78 lines
2.6 KiB
Python
"""Internal domain models for the knowledge module.
|
|
|
|
These are plain dataclasses passed between the extractor, the vault writer and
|
|
the repository. The Gateway router defines its own Pydantic request/response
|
|
models on top of the dicts the service returns.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from dataclasses import dataclass, field
|
|
|
|
# Allowed note source types (see product-knowledge-base-dev.md §7.1).
|
|
SOURCE_TYPES = ("thread", "search", "tool", "file", "manual", "report")
|
|
# Allowed lifecycle states.
|
|
STATUSES = ("draft", "approved", "archived")
|
|
# obsidian-wiki wiki-capture categories.
|
|
CATEGORIES = ("synthesis", "concepts", "references", "decision", "journal")
|
|
|
|
|
|
@dataclass
|
|
class SourceDraft:
|
|
"""A normalized knowledge source (search result, tool call, thread, …)."""
|
|
|
|
source_type: str
|
|
thread_id: str | None = None
|
|
message_id: str | None = None
|
|
tool_name: str | None = None
|
|
title: str | None = None
|
|
url: str | None = None
|
|
snippet: str | None = None
|
|
raw: dict | None = None
|
|
|
|
|
|
@dataclass
|
|
class NoteDraft:
|
|
"""A knowledge note ready to be persisted + written to the vault.
|
|
|
|
Produced by the extractor (from a thread / search / tool result) or built
|
|
directly for a manual note. ``content_md`` here is the *body* — the vault
|
|
writer prepends obsidian-wiki frontmatter.
|
|
"""
|
|
|
|
title: str
|
|
summary: str
|
|
content_md: str
|
|
category: str = "synthesis"
|
|
source_type: str = "manual"
|
|
source_id: str | None = None
|
|
status: str = "approved"
|
|
confidence: float = 0.0
|
|
# User-assigned directory (slash-joined path); None = unfiled.
|
|
folder: str | None = None
|
|
tags: list[str] = field(default_factory=list)
|
|
key_points: list[str] = field(default_factory=list)
|
|
actions: list[str] = field(default_factory=list)
|
|
related: list[str] = field(default_factory=list)
|
|
sources: list[SourceDraft] = field(default_factory=list)
|
|
# Phase 4: extracted graph signal. entities=[{name,type}],
|
|
# relations=[{from,to,type}] (names refer to entities or this note's title).
|
|
entities: list[dict] = field(default_factory=list)
|
|
relations: list[dict] = field(default_factory=list)
|
|
# Stable identity hint used for manifest dedup (e.g. ``thread:thread_id``).
|
|
source_key: str | None = None
|
|
|
|
|
|
def normalize_status(status: str | None) -> str:
|
|
"""Coerce an arbitrary status string to a valid lifecycle state."""
|
|
if status in STATUSES:
|
|
return status
|
|
return "approved"
|
|
|
|
|
|
def normalize_source_type(source_type: str | None) -> str:
|
|
"""Coerce an arbitrary source-type string to a valid value."""
|
|
if source_type in SOURCE_TYPES:
|
|
return source_type
|
|
return "manual"
|