mirror of
https://github.com/himanshudongre/smriti.git
synced 2026-10-09 03:17:59 +00:00
Tasks in checkpoints evolve from flat strings to objects with optional intent_hint (implement/review/investigate/docs/test), blocked_by (dependency label), and status (open/done). Agents reading the state brief can now self-select complementary work by matching task intents against active claim intent_types — no founder routing needed. Backward-compatible: old string tasks normalize at render time. No schema migration. JSONB handles both shapes. Skill pack v1.7 teaches the autonomous selection reflex.
160 lines
5 KiB
Python
160 lines
5 KiB
Python
"""API request and response schemas using Pydantic."""
|
|
|
|
import uuid
|
|
from datetime import datetime
|
|
from typing import Any, Optional, Union
|
|
|
|
from pydantic import BaseModel, Field, field_validator
|
|
|
|
from app.domain.enums import SessionStatus, TargetTool
|
|
|
|
|
|
# ── Request Schemas ──────────────────────────────────────────────────────────
|
|
|
|
|
|
class SessionCreateRequest(BaseModel):
|
|
"""Request body for creating a new session."""
|
|
raw_transcript: str = Field(..., min_length=1, description="The raw transcript text")
|
|
title: str | None = Field(None, max_length=255, description="Optional session title")
|
|
source_tool: str | None = Field(None, description="Source AI tool")
|
|
|
|
|
|
class ContextPackCreateRequest(BaseModel):
|
|
"""Request body for generating a context pack."""
|
|
target_tool: TargetTool = Field(..., description="Target tool for continuation pack")
|
|
|
|
|
|
# ── Response Schemas ─────────────────────────────────────────────────────────
|
|
|
|
|
|
class SessionResponse(BaseModel):
|
|
"""Response for a session."""
|
|
id: uuid.UUID
|
|
title: str | None
|
|
source_tool: str | None
|
|
status: SessionStatus
|
|
raw_transcript: str
|
|
created_at: datetime
|
|
|
|
model_config = {"from_attributes": True}
|
|
|
|
|
|
class DecisionResponse(BaseModel):
|
|
description: str
|
|
context: str = ""
|
|
|
|
|
|
class TaskResponse(BaseModel):
|
|
description: str
|
|
status: str = "pending"
|
|
|
|
|
|
class OpenQuestionResponse(BaseModel):
|
|
question: str
|
|
context: str = ""
|
|
|
|
|
|
class EntityResponse(BaseModel):
|
|
name: str
|
|
type: str
|
|
context: str = ""
|
|
|
|
|
|
class CodeSnippetResponse(BaseModel):
|
|
language: str
|
|
code: str
|
|
description: str = ""
|
|
|
|
|
|
class ArtifactsResponse(BaseModel):
|
|
"""Response for extracted artifacts."""
|
|
summary: str
|
|
decisions: list[DecisionResponse]
|
|
tasks: list[TaskResponse]
|
|
open_questions: list[OpenQuestionResponse]
|
|
entities: list[EntityResponse]
|
|
code_snippets: list[CodeSnippetResponse]
|
|
|
|
|
|
class ContextPackResponse(BaseModel):
|
|
"""Response for a generated context pack."""
|
|
id: uuid.UUID
|
|
session_id: uuid.UUID
|
|
target_tool: str
|
|
content: str
|
|
format: str
|
|
created_at: datetime
|
|
|
|
model_config = {"from_attributes": True}
|
|
|
|
|
|
class ErrorResponse(BaseModel):
|
|
"""Standard error response."""
|
|
error: str
|
|
detail: str | None = None
|
|
|
|
class CheckpointDraftRequest(BaseModel):
|
|
session_id: uuid.UUID
|
|
num_turns: int = Field(15, ge=1, le=100)
|
|
mounted_checkpoint_id: Optional[str] = Field(
|
|
None,
|
|
description="If set, draft only uses turns after history_base_seq (mirrors send_message isolation)."
|
|
)
|
|
history_base_seq: Optional[int] = Field(
|
|
None,
|
|
description="Sequence boundary from mount event. Only turns with sequence_number > this value are included."
|
|
)
|
|
|
|
class CheckpointDraftResponse(BaseModel):
|
|
title: str = ""
|
|
objective: str = ""
|
|
summary: str = ""
|
|
decisions: list[str] = Field(default_factory=list)
|
|
assumptions: list[str] = Field(default_factory=list)
|
|
tasks: list[Union[str, dict[str, Any]]] = Field(default_factory=list)
|
|
open_questions: list[str] = Field(default_factory=list)
|
|
entities: list[str] = Field(default_factory=list)
|
|
|
|
|
|
class ReviewIssue(BaseModel):
|
|
type: str # contradiction, hidden_assumption, resolved_question, unused_entity
|
|
description: str
|
|
|
|
|
|
class CheckpointReviewResponse(BaseModel):
|
|
checkpoint_id: uuid.UUID
|
|
issues: list[ReviewIssue] = Field(default_factory=list)
|
|
suggestions: list[str] = Field(default_factory=list)
|
|
|
|
|
|
class CheckpointExtractRequest(BaseModel):
|
|
"""Request body for the freeform-markdown checkpoint extractor.
|
|
|
|
Takes a freeform markdown document and asks the background LLM to
|
|
extract Smriti checkpoint schema fields from it. Stateless — no
|
|
session or checkpoint ID required.
|
|
"""
|
|
content: str = Field(..., description="Freeform markdown document to extract checkpoint fields from")
|
|
use_mock: bool = Field(False, description="Force MockAdapter even when a real provider is configured (for tests and dry-run flows)")
|
|
|
|
@field_validator("content")
|
|
@classmethod
|
|
def validate_content(cls, v: str) -> str:
|
|
stripped = v.strip()
|
|
if not stripped:
|
|
raise ValueError("content must not be empty")
|
|
if len(stripped) > 200_000:
|
|
raise ValueError("content exceeds 200000 character limit")
|
|
return v
|
|
|
|
|
|
class CheckpointExtractResponse(BaseModel):
|
|
title: str = ""
|
|
objective: str = ""
|
|
summary: str = ""
|
|
decisions: list[str] = Field(default_factory=list)
|
|
assumptions: list[str] = Field(default_factory=list)
|
|
tasks: list[Union[str, dict[str, Any]]] = Field(default_factory=list)
|
|
open_questions: list[str] = Field(default_factory=list)
|
|
entities: list[str] = Field(default_factory=list)
|
|
artifacts: list[dict] = Field(default_factory=list)
|