69 lines
2.7 KiB
Python
69 lines
2.7 KiB
Python
"""Declarative workspace contributions; no plugin JavaScript or model execution."""
|
|
|
|
from typing import Literal
|
|
|
|
from pydantic import BaseModel, ConfigDict, Field, model_validator
|
|
|
|
|
|
class WorkspaceModel(BaseModel):
|
|
model_config = ConfigDict(extra="forbid")
|
|
|
|
|
|
class PanelWidth(WorkspaceModel):
|
|
preferred: int = Field(default=340, ge=200, le=1000)
|
|
minimum: int = Field(default=240, ge=160, le=800)
|
|
maximum: int = Field(default=480, ge=200, le=1200)
|
|
|
|
@model_validator(mode="after")
|
|
def ordered(self):
|
|
if not self.minimum <= self.preferred <= self.maximum:
|
|
raise ValueError("面板宽度必须满足 minimum ≤ preferred ≤ maximum")
|
|
return self
|
|
|
|
|
|
class WorkspaceField(WorkspaceModel):
|
|
id: str = Field(pattern=r"^[a-z][a-z0-9_]{0,47}$")
|
|
label: str = Field(min_length=1, max_length=100)
|
|
description: str = Field(default="", max_length=1000)
|
|
kind: Literal["choice", "text"]
|
|
options: list[str] = Field(default_factory=list, max_length=12)
|
|
max_length: int = Field(default=2000, ge=1, le=10000)
|
|
report: bool = True
|
|
|
|
@model_validator(mode="after")
|
|
def valid_options(self):
|
|
if self.kind == "choice" and not self.options:
|
|
raise ValueError("选择字段必须声明 options")
|
|
if self.kind == "text" and self.options:
|
|
raise ValueError("文本字段不接受 options")
|
|
if len(set(self.options)) != len(self.options) or any(
|
|
not option.strip() or len(option) > min(100, self.max_length) for option in self.options
|
|
):
|
|
raise ValueError("选项必须非空、唯一且不超过长度限制")
|
|
return self
|
|
|
|
|
|
class WorkspacePanel(WorkspaceModel):
|
|
id: str = Field(pattern=r"^[a-z][a-z0-9_]{0,47}$")
|
|
title: str = Field(min_length=1, max_length=100)
|
|
side: Literal["left", "right"]
|
|
kind: Literal["initial_prompt", "form"]
|
|
width: PanelWidth = Field(default_factory=PanelWidth)
|
|
|
|
|
|
class WorkspaceContribution(WorkspaceModel):
|
|
panels: list[WorkspacePanel] = Field(min_length=1, max_length=2)
|
|
fields: list[WorkspaceField] = Field(default_factory=list, max_length=20)
|
|
|
|
@model_validator(mode="after")
|
|
def unique_contributions(self):
|
|
if len({panel.id for panel in self.panels}) != len(self.panels) or len(
|
|
{panel.kind for panel in self.panels}
|
|
) != len(self.panels):
|
|
raise ValueError("面板 id 和 kind 不得重复")
|
|
if len({field.id for field in self.fields}) != len(self.fields):
|
|
raise ValueError("工作区字段 id 不得重复")
|
|
if bool(self.fields) != any(panel.kind == "form" for panel in self.panels):
|
|
raise ValueError("表单面板与 fields 必须同时声明")
|
|
return self
|