ducklm/app/core/contracts.py

149 lines
3.8 KiB
Python

from __future__ import annotations
from datetime import datetime, timezone
from typing import Any, Literal
from uuid import uuid4
from pydantic import BaseModel, Field
def utc_now() -> datetime:
return datetime.now(timezone.utc)
class UserTask(BaseModel):
task_id: str = Field(default_factory=lambda: str(uuid4()))
session_id: str = Field(default_factory=lambda: str(uuid4()))
input: str
context: dict[str, Any] = Field(default_factory=dict)
created_at: datetime = Field(default_factory=utc_now)
class PlanStep(BaseModel):
id: str
kind: Literal["tool", "coder", "memory", "respond"]
tool: str | None = None
args: dict[str, Any] = Field(default_factory=dict)
description: str
requires_confirmation: bool = False
depends_on: list[str] = Field(default_factory=list)
class ToolCall(BaseModel):
tool: str
args: dict[str, Any] = Field(default_factory=dict)
task_id: str
step_id: str
class ToolResult(BaseModel):
tool: str
ok: bool
output: Any = None
error: str | None = None
metadata: dict[str, Any] = Field(default_factory=dict)
class CoderRequest(BaseModel):
mode: Literal["generate", "fix", "refactor"]
instruction: str
context: dict[str, Any] = Field(default_factory=dict)
task_id: str
class CriticScore(BaseModel):
correctness: float = Field(ge=0.0, le=1.0)
usefulness: float = Field(ge=0.0, le=1.0)
safety: float = Field(ge=0.0, le=1.0)
memory_store: bool
weight: float = Field(ge=0.0, le=1.0)
explanation: str
class MemoryEntry(BaseModel):
id: str = Field(default_factory=lambda: str(uuid4()))
text: str
kind: Literal["tool_result", "plan", "critique", "fact", "summary", "user_preference"]
source: Literal["tool", "critic", "user", "system"]
weight: float = Field(ge=0.0, le=1.0)
task_id: str | None = None
session_id: str | None = None
metadata: dict[str, Any] = Field(default_factory=dict)
created_at: datetime = Field(default_factory=utc_now)
embedding_model: str
embedding_dim: int
class PermissionDecision(BaseModel):
action_type: str
pattern: str
decision: Literal["allow_once", "allow_always", "deny", "ask_always"]
created_at: datetime = Field(default_factory=utc_now)
class RuntimeEvent(BaseModel):
event_id: str = Field(default_factory=lambda: str(uuid4()))
task_id: str
session_id: str
sequence: int
type: str
timestamp: datetime = Field(default_factory=utc_now)
payload: dict[str, Any] = Field(default_factory=dict)
causation_id: str | None = None
correlation_id: str = Field(default_factory=lambda: str(uuid4()))
class TaskCheckpoint(BaseModel):
task_id: str
status: str
active_step_id: str | None = None
plan_snapshot: dict[str, Any] = Field(default_factory=dict)
context_snapshot: dict[str, Any] = Field(default_factory=dict)
updated_at: datetime = Field(default_factory=utc_now)
class PermissionRequest(BaseModel):
task_id: str
session_id: str
action_type: str
pattern: str
command: str | None = None
path: str | None = None
requires_password: bool = False
class SecretRequest(BaseModel):
task_id: str
session_id: str
kind: str
prompt: str
command: str | None = None
class PasswordRequest(BaseModel):
task_id: str
session_id: str
command: str
reason: str
attempts: int = 0
max_attempts: int = 3
class ExecutionDirective(BaseModel):
type: Literal[
"plan",
"tool",
"coder",
"respond",
"replan",
"store_memory",
"request_permission",
"complete",
"fail",
"noop",
]
payload: dict[str, Any] = Field(default_factory=dict)
requires_permission: bool = False
confidence: float = Field(ge=0.0, le=1.0, default=0.0)
reason: str = ""