This commit is contained in:
2026-03-17 18:32:44 +03:00
commit efcd4a8dfd
209 changed files with 33355 additions and 0 deletions
+69
View File
@@ -0,0 +1,69 @@
from __future__ import annotations
from datetime import datetime
from typing import Any
from uuid import UUID
from pydantic import BaseModel, ConfigDict, computed_field
from app.models import ActionIngestStatus, HttpMethod
class ActionListItemResponse(BaseModel):
id: UUID
user_id: UUID | None = None
operation_id: str | None = None
method: HttpMethod
path: str
base_url: str | None = None
summary: str | None = None
description: str | None = None
tags: list[str] | None = None
source_filename: str | None = None
ingest_status: ActionIngestStatus
ingest_error: str | None = None
created_at: datetime
updated_at: datetime
model_config = ConfigDict(from_attributes=True)
class ActionIngestItemResponse(BaseModel):
id: UUID
user_id: UUID | None = None
operation_id: str | None = None
method: HttpMethod
path: str
summary: str | None = None
source_filename: str | None = None
ingest_status: ActionIngestStatus
ingest_error: str | None = None
model_config = ConfigDict(from_attributes=True)
class ActionDetailResponse(ActionListItemResponse):
parameters_schema: dict[str, Any] | None = None
request_body_schema: dict[str, Any] | None = None
response_schema: dict[str, Any] | None = None
raw_spec: dict[str, Any] | None = None
@computed_field(return_type=dict[str, Any] | None)
@property
def json_schema(self) -> dict[str, Any] | None:
if not any((self.parameters_schema, self.request_body_schema, self.response_schema, self.raw_spec)):
return None
return {
"parameters": self.parameters_schema,
"request_body": self.request_body_schema,
"response": self.response_schema,
"raw_spec": self.raw_spec,
}
class ActionIngestResponse(BaseModel):
succeeded_count: int
failed_count: int
succeeded_actions: list[ActionDetailResponse]
failed_actions: list[ActionDetailResponse]
+19
View File
@@ -0,0 +1,19 @@
from pydantic import AliasChoices, BaseModel, ConfigDict, EmailStr, Field
class RegisterIn(BaseModel):
email: EmailStr = Field(max_length=254)
password: str = Field(min_length=1, max_length=72)
full_name: str = Field(
min_length=2,
max_length=200,
validation_alias=AliasChoices("full_name", "fullName"),
serialization_alias="fullName",
)
model_config = ConfigDict(populate_by_name=True)
class LoginIn(BaseModel):
email: EmailStr = Field(max_length=254)
password: str = Field(min_length=1, max_length=72)
+73
View File
@@ -0,0 +1,73 @@
from __future__ import annotations
from datetime import datetime
from typing import Any
from uuid import UUID
from pydantic import BaseModel, ConfigDict, Field
from app.schemas.action_sch import ActionIngestItemResponse
class CapabilityDataFormat(BaseModel):
parameter_locations: list[str] = []
request_content_types: list[str] = []
request_schema_type: str | None = None
response_content_types: list[str] = []
response_schema_types: list[str] = []
class CapabilityResponse(BaseModel):
id: UUID
user_id: UUID | None = None
action_id: UUID | None = None
type: str = "ATOMIC"
name: str
description: str | None = None
input_schema: dict[str, Any] | None = None
output_schema: dict[str, Any] | None = None
recipe: dict[str, Any] | None = None
data_format: CapabilityDataFormat | None = None
created_at: datetime
updated_at: datetime
model_config = ConfigDict(from_attributes=True)
class CapabilityIngestItemResponse(BaseModel):
id: UUID
user_id: UUID | None = None
action_id: UUID | None = None
type: str = "ATOMIC"
name: str
description: str | None = None
model_config = ConfigDict(from_attributes=True)
class ActionIngestWithCapabilitiesResponse(BaseModel):
succeeded_count: int
failed_count: int
created_capabilities_count: int
succeeded_actions: list[ActionIngestItemResponse]
failed_actions: list[ActionIngestItemResponse]
capabilities: list[CapabilityIngestItemResponse]
class CompositeCapabilityRecipeStepCreate(BaseModel):
step: int = Field(ge=1)
capability_id: UUID
inputs: dict[str, str] = Field(default_factory=dict)
class CompositeCapabilityRecipeCreate(BaseModel):
version: int = 1
steps: list[CompositeCapabilityRecipeStepCreate] = Field(default_factory=list)
class CreateCompositeCapabilityRequest(BaseModel):
name: str = Field(min_length=1, max_length=255)
description: str | None = None
input_schema: dict[str, Any] | None = None
output_schema: dict[str, Any] | None = None
recipe: CompositeCapabilityRecipeCreate
+67
View File
@@ -0,0 +1,67 @@
from __future__ import annotations
from datetime import datetime
from typing import Any, Literal
from uuid import UUID
from pydantic import BaseModel, ConfigDict, Field
class RunPipelineRequest(BaseModel):
inputs: dict[str, Any] = Field(default_factory=dict)
class RunPipelineResponse(BaseModel):
run_id: UUID
pipeline_id: UUID
status: Literal["QUEUED", "RUNNING"]
class ExecutionRunListItemResponse(BaseModel):
id: UUID
pipeline_id: UUID
status: Literal["QUEUED", "RUNNING", "SUCCEEDED", "FAILED", "PARTIAL_FAILED"]
error: str | None = None
started_at: datetime | None = None
finished_at: datetime | None = None
created_at: datetime
updated_at: datetime
model_config = ConfigDict(from_attributes=True)
class ExecutionStepRunResponse(BaseModel):
step: int
name: str | None = None
capability_id: UUID | None = None
action_id: UUID | None = None
method: Literal["GET", "POST", "PUT", "PATCH", "DELETE", "HEAD", "OPTIONS"] | None = None
status_code: int | None = None
status: Literal["PENDING", "RUNNING", "SUCCEEDED", "FAILED", "SKIPPED"]
resolved_inputs: dict[str, Any] | None = None
accepted_payload: Any = None
output_payload: Any = None
request_snapshot: dict[str, Any] | None = None
response_snapshot: dict[str, Any] | None = None
error: str | None = None
started_at: datetime | None = None
finished_at: datetime | None = None
duration_ms: int | None = None
created_at: datetime
updated_at: datetime
model_config = ConfigDict(from_attributes=True)
class ExecutionRunDetailResponse(BaseModel):
id: UUID
pipeline_id: UUID
status: Literal["QUEUED", "RUNNING", "SUCCEEDED", "FAILED", "PARTIAL_FAILED"]
inputs: dict[str, Any] = Field(default_factory=dict)
summary: dict[str, Any] | None = None
error: str | None = None
started_at: datetime | None = None
finished_at: datetime | None = None
created_at: datetime
updated_at: datetime
steps: list[ExecutionStepRunResponse] = Field(default_factory=list)
+104
View File
@@ -0,0 +1,104 @@
from __future__ import annotations
from datetime import datetime
from typing import Any, Literal
from uuid import UUID
from pydantic import BaseModel, ConfigDict, Field
class PipelineInputTypeFromPrevious(BaseModel):
from_step: int
type: str
class PipelineStepEndpoint(BaseModel):
name: str
capability_id: UUID
action_id: UUID | None = None
type: str | None = None
input_type: str | dict[str, Any] | None = None
output_type: str | dict[str, Any] | None = None
class PipelineGraphNode(BaseModel):
step: int
name: str
description: str | None = None
input_connected_from: list[int] = Field(default_factory=list)
output_connected_to: list[int] = Field(default_factory=list)
input_data_type_from_previous: list[PipelineInputTypeFromPrevious] = Field(default_factory=list)
external_inputs: list[str] = Field(default_factory=list)
endpoints: list[PipelineStepEndpoint] = Field(default_factory=list)
class PipelineGraphEdge(BaseModel):
from_step: int
to_step: int
type: str
class PipelineGenerateRequest(BaseModel):
dialog_id: UUID
message: str = Field(min_length=1)
capability_ids: list[UUID] | None = None
class PipelineGenerateResponse(BaseModel):
status: Literal["ready", "needs_input", "cannot_build"]
message_ru: str
chat_reply_ru: str
pipeline_id: UUID | None = None
nodes: list[PipelineGraphNode] = Field(default_factory=list)
edges: list[PipelineGraphEdge] = Field(default_factory=list)
missing_requirements: list[str] = Field(default_factory=list)
context_summary: str | None = None
class PipelineGraphUpdateRequest(BaseModel):
nodes: list[PipelineGraphNode] = Field(default_factory=list)
edges: list[PipelineGraphEdge] = Field(default_factory=list)
class PipelineGraphUpdateResponse(BaseModel):
pipeline_id: UUID
nodes: list[PipelineGraphNode] = Field(default_factory=list)
edges: list[PipelineGraphEdge] = Field(default_factory=list)
updated_at: datetime
class DialogResetRequest(BaseModel):
dialog_id: UUID
class DialogResetResponse(BaseModel):
status: Literal["ok"]
message_ru: str
class PipelineDialogListItemResponse(BaseModel):
dialog_id: UUID
title: str | None = None
last_status: str | None = None
last_pipeline_id: UUID | None = None
last_message_preview: str | None = None
created_at: datetime
updated_at: datetime
model_config = ConfigDict(from_attributes=True)
class PipelineDialogMessageResponse(BaseModel):
id: UUID
role: Literal["user", "assistant"]
content: str
assistant_payload: dict[str, Any] | None = None
created_at: datetime
model_config = ConfigDict(from_attributes=True)
class PipelineDialogHistoryResponse(BaseModel):
dialog_id: UUID
title: str | None = None
messages: list[PipelineDialogMessageResponse] = Field(default_factory=list)
+33
View File
@@ -0,0 +1,33 @@
from pydantic import BaseModel, EmailStr, ConfigDict
from uuid import UUID
from datetime import datetime
from app.models import UserRole
from typing import Optional
class UserBase(BaseModel):
email: EmailStr
full_name: str
class UserUpdate(BaseModel):
email: Optional[EmailStr] = None
full_name: Optional[str] = None
role: Optional[UserRole] = None
is_active: Optional[bool] = None
min_approvals_required: Optional[int] = None
class UserResponse(UserBase):
id: UUID
role: UserRole
is_active: bool
min_approvals_required: int
created_at: datetime
model_config = ConfigDict(from_attributes=True)
class UserUpdateMe(BaseModel):
email: Optional[EmailStr] = None
full_name: Optional[str] = None
class PasswordUpdate(BaseModel):
old_password: str
new_password: str
+45
View File
@@ -0,0 +1,45 @@
from typing import Annotated, Optional
import uuid
from datetime import datetime
from pydantic import BaseModel, EmailStr, Field, ConfigDict, field_validator
from app.models import UserRole
class UserBase(BaseModel):
email: EmailStr
full_name: Annotated[str | None, Field(max_length=255)] = None
class UserResponse(UserBase):
id: uuid.UUID
role: UserRole
is_active: bool
created_at: datetime
updated_at: datetime | None = None
model_config = ConfigDict(from_attributes=True)
class UserUpdate(BaseModel):
email: Optional[EmailStr] = None
full_name: Optional[str] = Field(None, min_length=2, max_length=255)
role: Optional[UserRole] = None
is_active: Optional[bool] = None
class UserUpdateMe(BaseModel):
email: Optional[EmailStr] = None
full_name: Optional[str] = Field(None, min_length=2, max_length=255)
class PasswordUpdate(BaseModel):
old_password: str = Field(min_length=8)
new_password: str = Field(min_length=8)
@field_validator("new_password")
@classmethod
def validate_password_complexity(cls, v: str) -> str:
if not any(c.isalpha() for c in v) or not any(c.isdigit() for c in v):
raise ValueError("must contain at least one letter and one digit")
return v