| """Shared pydantic schemas for the scheduling agent. |
| |
| The model is constrained to emit an ActionPlan (see server/agent.py); these types |
| are also the contract used by the UI and the calendar outputs. |
| """ |
| from __future__ import annotations |
|
|
| from typing import Optional |
|
|
| from pydantic import BaseModel, Field |
|
|
|
|
| class Event(BaseModel): |
| title: str |
| start: str |
| end: Optional[str] = None |
| location: Optional[str] = None |
| attendees: list[str] = Field(default_factory=list) |
| reminder_minutes: Optional[int] = None |
| notes: Optional[str] = None |
|
|
|
|
| class Conflict(BaseModel): |
| event_index: int = Field(description="index into ActionPlan.events") |
| clashes_with: str = Field(description="summary of the existing event it clashes with") |
| severity: str = Field(description='one of: "overlap", "adjacent", "tight"') |
|
|
|
|
| class ActionPlan(BaseModel): |
| """Everything the agent decides for one thread, in one constrained object.""" |
|
|
| reasoning: Optional[str] = Field( |
| default=None, description="brief chain of thought shown to the user" |
| ) |
| events: list[Event] = Field(default_factory=list) |
| conflicts: list[Conflict] = Field(default_factory=list) |
| proposed_times: list[str] = Field( |
| default_factory=list, description="ISO 8601 alternatives when there is a conflict" |
| ) |
| reply_draft: str = Field(default="", description="suggested reply to send back") |
| needs_clarification: Optional[str] = Field( |
| default=None, description="a question to ask if the plan is ambiguous" |
| ) |
|
|