912 lines
23 KiB
Python
912 lines
23 KiB
Python
from datetime import datetime
|
|
from enum import Enum
|
|
from typing import Annotated, Any, Literal
|
|
|
|
from pydantic import BaseModel, ConfigDict, Field, SecretStr
|
|
|
|
|
|
class Contract(BaseModel):
|
|
model_config = ConfigDict(extra="forbid")
|
|
|
|
|
|
class PageMeta(Contract):
|
|
total: int = 0
|
|
limit: int = 50
|
|
offset: int = 0
|
|
|
|
|
|
class ErrorDetail(Contract):
|
|
code: str
|
|
message: str
|
|
details: dict[str, Any] = Field(default_factory=dict)
|
|
|
|
|
|
class ErrorResponse(Contract):
|
|
error: ErrorDetail
|
|
|
|
|
|
class OperationResponse(Contract):
|
|
status: Literal["accepted", "completed"]
|
|
resource_id: str | None = None
|
|
message: str | None = None
|
|
|
|
|
|
# Workspace boundary (single configured Vault in Web development mode)
|
|
class WorkspaceInfo(Contract):
|
|
vault_id: str = "default"
|
|
name: str
|
|
path: str
|
|
file_count: int = 0
|
|
indexed_note_count: int = 0
|
|
requires_refresh: bool = False
|
|
|
|
|
|
class WorkspaceEntry(Contract):
|
|
entry_id: str
|
|
name: str
|
|
path: str
|
|
type: Literal["file", "folder"]
|
|
note_id: str | None = None
|
|
children: list["WorkspaceEntry"] = Field(default_factory=list)
|
|
|
|
|
|
class WorkspaceSnapshot(Contract):
|
|
workspace: WorkspaceInfo
|
|
items: list[WorkspaceEntry] = Field(default_factory=list)
|
|
|
|
|
|
class WorkspaceOpenRequest(Contract):
|
|
path: str | None = None
|
|
|
|
|
|
class FolderCreateRequest(Contract):
|
|
parent: str = ""
|
|
name: str = Field(min_length=1)
|
|
|
|
|
|
class FolderRenameRequest(Contract):
|
|
path: str
|
|
new_name: str = Field(min_length=1)
|
|
|
|
|
|
class FolderDeleteRequest(Contract):
|
|
path: str
|
|
|
|
|
|
# Notes and retrieval
|
|
class NoteBlock(Contract):
|
|
block_id: str
|
|
note_id: str
|
|
heading_path: list[str] = Field(default_factory=list)
|
|
start_offset: int
|
|
end_offset: int
|
|
content: str
|
|
content_hash: str
|
|
token_count: int
|
|
|
|
|
|
class NoteSummary(Contract):
|
|
note_id: str
|
|
title: str
|
|
file_path: str
|
|
tags: list[str] = Field(default_factory=list)
|
|
created_at: datetime
|
|
updated_at: datetime
|
|
|
|
|
|
class Note(NoteSummary):
|
|
markdown: str
|
|
blocks: list[NoteBlock] = Field(default_factory=list)
|
|
|
|
|
|
class NoteListResponse(Contract):
|
|
items: list[NoteSummary] = Field(default_factory=list)
|
|
page: PageMeta = Field(default_factory=PageMeta)
|
|
|
|
|
|
class NoteCreateRequest(Contract):
|
|
title: str = Field(min_length=1)
|
|
markdown: str = ""
|
|
folder: str | None = None
|
|
tags: list[str] = Field(default_factory=list)
|
|
|
|
|
|
class NoteUpdateRequest(Contract):
|
|
title: str | None = None
|
|
markdown: str | None = None
|
|
tags: list[str] | None = None
|
|
|
|
|
|
class NoteMoveRequest(Contract):
|
|
folder: str
|
|
|
|
|
|
class NoteRenameRequest(Contract):
|
|
file_name: str = Field(min_length=1)
|
|
|
|
|
|
class SearchMode(str, Enum):
|
|
fts = "fts"
|
|
vector = "vector"
|
|
hybrid = "hybrid"
|
|
|
|
|
|
class SearchRequest(Contract):
|
|
query: str = Field(min_length=1)
|
|
mode: SearchMode = SearchMode.hybrid
|
|
folders: list[str] = Field(default_factory=list)
|
|
note_ids: list[str] = Field(default_factory=list)
|
|
tags: list[str] = Field(default_factory=list)
|
|
created_from: datetime | None = None
|
|
created_to: datetime | None = None
|
|
updated_from: datetime | None = None
|
|
updated_to: datetime | None = None
|
|
limit: int = Field(default=20, ge=1, le=100)
|
|
offset: int = Field(default=0, ge=0)
|
|
include_snippet: bool = True
|
|
|
|
|
|
class Citation(Contract):
|
|
citation_id: str
|
|
note_id: str
|
|
block_id: str
|
|
file_path: str
|
|
heading_path: list[str] = Field(default_factory=list)
|
|
start_offset: int | None = None
|
|
end_offset: int | None = None
|
|
source_audio: str | None = None
|
|
start_time: float | None = None
|
|
end_time: float | None = None
|
|
speaker: str | None = None
|
|
|
|
|
|
class SearchResult(Contract):
|
|
note_id: str
|
|
block_id: str
|
|
title: str
|
|
file_path: str
|
|
heading_path: list[str] = Field(default_factory=list)
|
|
snippet: str | None = None
|
|
score: float
|
|
citation: Citation
|
|
|
|
|
|
class SearchResponse(Contract):
|
|
query: str
|
|
mode: SearchMode
|
|
items: list[SearchResult] = Field(default_factory=list)
|
|
page: PageMeta = Field(default_factory=PageMeta)
|
|
|
|
|
|
# Model, chat and tools
|
|
class MessageRole(str, Enum):
|
|
system = "system"
|
|
user = "user"
|
|
assistant = "assistant"
|
|
tool = "tool"
|
|
|
|
|
|
class Message(Contract):
|
|
role: MessageRole
|
|
content: str
|
|
name: str | None = None
|
|
tool_call_id: str | None = None
|
|
tool_calls: list["ToolCall"] = Field(default_factory=list)
|
|
|
|
|
|
class ToolDefinition(Contract):
|
|
name: str
|
|
description: str
|
|
parameters: dict[str, Any] = Field(default_factory=dict)
|
|
permission: str | None = None
|
|
source: Literal["builtin", "plugin", "mcp_server"] = "builtin"
|
|
|
|
|
|
class ToolCall(Contract):
|
|
tool_call_id: str
|
|
name: str
|
|
arguments: dict[str, Any] = Field(default_factory=dict)
|
|
|
|
|
|
class ToolResult(Contract):
|
|
tool_call_id: str
|
|
name: str
|
|
success: bool
|
|
output: Any | None = None
|
|
error_code: str | None = None
|
|
error_message: str | None = None
|
|
duration_ms: int | None = None
|
|
|
|
|
|
class ToolListResponse(Contract):
|
|
items: list[ToolDefinition] = Field(default_factory=list)
|
|
|
|
|
|
class ModelCapability(str, Enum):
|
|
chat = "chat"
|
|
vision = "vision"
|
|
tool_calling = "tool_calling"
|
|
reasoning = "reasoning"
|
|
streaming = "streaming"
|
|
structured_output = "structured_output"
|
|
embedding = "embedding"
|
|
|
|
|
|
class ModelRequest(Contract):
|
|
provider_id: str
|
|
model: str
|
|
system: str | None = None
|
|
messages: list[Message]
|
|
tools: list[ToolDefinition] = Field(default_factory=list)
|
|
temperature: float | None = Field(default=None, ge=0, le=2)
|
|
max_tokens: int | None = Field(default=None, ge=1)
|
|
response_format: dict[str, Any] | None = None
|
|
attachments: list[str] = Field(default_factory=list)
|
|
metadata: dict[str, Any] = Field(default_factory=dict)
|
|
|
|
|
|
class ChatRequest(ModelRequest):
|
|
conversation_id: str | None = None
|
|
use_rag: bool = True
|
|
retrieval: SearchRequest | None = None
|
|
|
|
|
|
class ModelEventType(str, Enum):
|
|
text_delta = "TextDelta"
|
|
thinking_delta = "ThinkingDelta"
|
|
tool_call_start = "ToolCallStart"
|
|
tool_call_delta = "ToolCallDelta"
|
|
tool_call_end = "ToolCallEnd"
|
|
usage = "Usage"
|
|
error = "Error"
|
|
done = "Done"
|
|
|
|
|
|
class ModelEvent(Contract):
|
|
event: ModelEventType
|
|
sequence: int = 0
|
|
data: dict[str, Any] = Field(default_factory=dict)
|
|
timestamp: datetime
|
|
|
|
|
|
# Agent
|
|
class AgentRunStatus(str, Enum):
|
|
queued = "queued"
|
|
running = "running"
|
|
waiting_permission = "waiting_permission"
|
|
completed = "completed"
|
|
failed = "failed"
|
|
cancelled = "cancelled"
|
|
|
|
|
|
class AgentRunCreateRequest(Contract):
|
|
input: str = Field(min_length=1)
|
|
provider_id: str
|
|
model: str
|
|
skill_id: str | None = None
|
|
allowed_tools: list[str] = Field(default_factory=list)
|
|
max_steps: int = Field(default=10, ge=1, le=100)
|
|
tool_timeout_seconds: int = Field(default=30, ge=1)
|
|
run_timeout_seconds: int = Field(default=300, ge=1)
|
|
token_budget: int | None = Field(default=None, ge=1)
|
|
max_concurrent_tools: int = Field(default=1, ge=1)
|
|
allow_network: bool = False
|
|
metadata: dict[str, Any] = Field(default_factory=dict)
|
|
|
|
|
|
class AgentRun(Contract):
|
|
run_id: str
|
|
status: AgentRunStatus
|
|
input: str
|
|
provider_id: str
|
|
model: str
|
|
skill_id: str | None = None
|
|
current_step: int = 0
|
|
max_steps: int
|
|
token_budget: int | None = None
|
|
cancelled: bool = False
|
|
output: str | None = None
|
|
error_code: str | None = None
|
|
error_message: str | None = None
|
|
token_usage: int = 0
|
|
tool_results: list[ToolResult] = Field(default_factory=list)
|
|
citations: list[Citation] = Field(default_factory=list)
|
|
created_at: datetime
|
|
updated_at: datetime
|
|
|
|
|
|
class AgentRunListResponse(Contract):
|
|
items: list[AgentRun] = Field(default_factory=list)
|
|
page: PageMeta = Field(default_factory=PageMeta)
|
|
|
|
|
|
class AgentEventType(str, Enum):
|
|
run_started = "RunStarted"
|
|
text_delta = "TextDelta"
|
|
thinking_delta = "ThinkingDelta"
|
|
tool_call = "ToolCall"
|
|
tool_result = "ToolResult"
|
|
permission_required = "PermissionRequired"
|
|
usage = "Usage"
|
|
citation = "Citation"
|
|
model_call_started = "ModelCallStarted"
|
|
model_call_completed = "ModelCallCompleted"
|
|
model_call_failed = "ModelCallFailed"
|
|
permission_resolved = "PermissionResolved"
|
|
run_completed = "RunCompleted"
|
|
run_failed = "RunFailed"
|
|
run_cancelled = "RunCancelled"
|
|
|
|
|
|
class AgentEvent(Contract):
|
|
event: AgentEventType
|
|
run_id: str
|
|
sequence: int
|
|
data: dict[str, Any] = Field(default_factory=dict)
|
|
timestamp: datetime
|
|
|
|
|
|
class AgentTraceSummary(Contract):
|
|
model_calls: int = 0
|
|
tool_calls: int = 0
|
|
duration_ms: int = 0
|
|
token_usage: int = 0
|
|
errors: int = 0
|
|
|
|
|
|
class AgentTraceResponse(Contract):
|
|
run_id: str
|
|
status: AgentRunStatus
|
|
items: list[AgentEvent] = Field(default_factory=list)
|
|
next_sequence: int
|
|
has_more: bool = False
|
|
summary: AgentTraceSummary = Field(default_factory=AgentTraceSummary)
|
|
config_snapshot: dict[str, Any] = Field(default_factory=dict)
|
|
|
|
|
|
class PermissionDecisionRequest(Contract):
|
|
decision: Literal["allow_once", "allow_session", "deny"]
|
|
|
|
|
|
# Skills and plugins
|
|
class RetrievalConfig(Contract):
|
|
top_k: int = Field(default=10, ge=1, le=100)
|
|
rerank: bool = True
|
|
citation: bool = True
|
|
|
|
|
|
class SkillModelConfig(Contract):
|
|
required_capabilities: list[ModelCapability] = Field(default_factory=list)
|
|
|
|
|
|
class SkillManifest(Contract):
|
|
skill_id: str
|
|
name: str
|
|
version: str
|
|
description: str = ""
|
|
permissions: list[str] = Field(default_factory=list)
|
|
tools: list[str] = Field(default_factory=list)
|
|
retrieval: RetrievalConfig = Field(default_factory=RetrievalConfig)
|
|
model: SkillModelConfig = Field(default_factory=SkillModelConfig)
|
|
|
|
|
|
class SkillStatus(str, Enum):
|
|
installed = "installed"
|
|
disabled = "disabled"
|
|
ready = "ready"
|
|
dependency_missing = "dependency_missing"
|
|
permission_required = "permission_required"
|
|
error = "error"
|
|
|
|
|
|
class Skill(Contract):
|
|
manifest: SkillManifest
|
|
status: SkillStatus
|
|
enabled: bool = False
|
|
missing_dependencies: list[str] = Field(default_factory=list)
|
|
|
|
|
|
class SkillListResponse(Contract):
|
|
items: list[Skill] = Field(default_factory=list)
|
|
|
|
|
|
class ExtensionInstallRequest(Contract):
|
|
package_path: str
|
|
|
|
|
|
class PluginBackend(Contract):
|
|
type: Literal["mcp", "internal_rpc", "none"] = "none"
|
|
transport: Literal["stdio", "http", "none"] = "none"
|
|
command: str | None = None
|
|
args: list[str] = Field(default_factory=list)
|
|
startup_timeout_seconds: int = Field(default=10, ge=1, le=60)
|
|
tool_timeout_seconds: int = Field(default=30, ge=1, le=600)
|
|
|
|
|
|
class PluginContribution(Contract):
|
|
tools: list[str] = Field(default_factory=list)
|
|
commands: list[str] = Field(default_factory=list)
|
|
importers: list[str] = Field(default_factory=list)
|
|
exporters: list[str] = Field(default_factory=list)
|
|
panels: list[str] = Field(default_factory=list)
|
|
settings_sections: list[str] = Field(default_factory=list)
|
|
|
|
|
|
class PluginManifest(Contract):
|
|
plugin_id: str
|
|
name: str
|
|
version: str
|
|
description: str = ""
|
|
permissions: list[str] = Field(default_factory=list)
|
|
contributes: PluginContribution = Field(default_factory=PluginContribution)
|
|
backend: PluginBackend = Field(default_factory=PluginBackend)
|
|
|
|
|
|
class PluginStatus(str, Enum):
|
|
installed = "installed"
|
|
disabled = "disabled"
|
|
starting = "starting"
|
|
ready = "ready"
|
|
error = "error"
|
|
dependency_missing = "dependency_missing"
|
|
permission_required = "permission_required"
|
|
|
|
|
|
class Plugin(Contract):
|
|
manifest: PluginManifest
|
|
status: PluginStatus
|
|
enabled: bool = False
|
|
granted_permissions: list[str] = Field(default_factory=list)
|
|
error_message: str | None = None
|
|
|
|
|
|
class PluginListResponse(Contract):
|
|
items: list[Plugin] = Field(default_factory=list)
|
|
|
|
|
|
class PluginHostState(str, Enum):
|
|
stopped = "stopped"
|
|
starting = "starting"
|
|
ready = "ready"
|
|
unhealthy = "unhealthy"
|
|
error = "error"
|
|
|
|
|
|
class PluginHostStatus(Contract):
|
|
plugin_id: str
|
|
backend_type: Literal["mcp", "internal_rpc", "none"]
|
|
transport: Literal["stdio", "http", "none"]
|
|
status: PluginHostState
|
|
tools_count: int = 0
|
|
started_at: datetime | None = None
|
|
last_seen_at: datetime | None = None
|
|
protocol_version: str | None = None
|
|
server_name: str | None = None
|
|
server_version: str | None = None
|
|
error: str | None = None
|
|
|
|
|
|
# Independent user-managed MCP Server Registry. This is deliberately separate
|
|
# from Plugin manifests: a server can contribute tools without being a Plugin.
|
|
class McpServerTransport(str, Enum):
|
|
stdio = "stdio"
|
|
streamable_http = "streamable_http"
|
|
sse = "sse"
|
|
|
|
|
|
class McpServerConfig(Contract):
|
|
name: str = Field(min_length=1, max_length=80)
|
|
transport: McpServerTransport = McpServerTransport.stdio
|
|
command: str | None = Field(default=None, max_length=1024)
|
|
args: list[str] = Field(default_factory=list, max_length=64)
|
|
url: str | None = Field(default=None, max_length=4096)
|
|
headers: dict[str, str] = Field(default_factory=dict)
|
|
environment: dict[str, str] = Field(default_factory=dict)
|
|
secret_environment_keys: list[str] = Field(default_factory=list)
|
|
secret_header_keys: list[str] = Field(default_factory=list)
|
|
permissions: list[str] = Field(default_factory=list)
|
|
startup_timeout_seconds: float = Field(default=15, ge=1, le=120)
|
|
tool_timeout_seconds: float = Field(default=30, ge=1, le=300)
|
|
|
|
|
|
class McpServerCreateRequest(McpServerConfig):
|
|
pass
|
|
|
|
|
|
class McpServerUpdateRequest(McpServerConfig):
|
|
version: int = Field(ge=1)
|
|
|
|
|
|
class McpServerSecretWriteRequest(Contract):
|
|
secret: SecretStr = Field(min_length=1, max_length=32768)
|
|
|
|
|
|
class McpServerSecretStatus(Contract):
|
|
key: str
|
|
configured: bool
|
|
|
|
|
|
class McpServerTrustRequest(Contract):
|
|
command_digest: str = Field(min_length=64, max_length=64)
|
|
|
|
|
|
class McpServerStatus(Contract):
|
|
enabled: bool = False
|
|
status: PluginHostState = PluginHostState.stopped
|
|
tools_count: int = 0
|
|
protocol_version: str | None = None
|
|
remote_server_name: str | None = None
|
|
remote_server_version: str | None = None
|
|
error: str | None = None
|
|
last_tested_at: datetime | None = None
|
|
last_test_succeeded: bool | None = None
|
|
|
|
|
|
class McpServer(McpServerStatus):
|
|
server_id: str
|
|
version: int
|
|
name: str
|
|
transport: McpServerTransport
|
|
command: str | None = None
|
|
args: list[str] = Field(default_factory=list)
|
|
url: str | None = None
|
|
headers: dict[str, str] = Field(default_factory=dict)
|
|
environment: dict[str, str] = Field(default_factory=dict)
|
|
permissions: list[str] = Field(default_factory=list)
|
|
startup_timeout_seconds: float
|
|
tool_timeout_seconds: float
|
|
secret_environment: dict[str, bool] = Field(default_factory=dict)
|
|
secret_headers: dict[str, bool] = Field(default_factory=dict)
|
|
trusted: bool = False
|
|
command_digest: str
|
|
command_summary: str
|
|
|
|
|
|
class McpServerListResponse(Contract):
|
|
items: list[McpServer] = Field(default_factory=list)
|
|
|
|
|
|
class McpToolSummary(Contract):
|
|
name: str
|
|
remote_name: str
|
|
description: str
|
|
permission: str | None = None
|
|
|
|
|
|
class McpToolSummaryListResponse(Contract):
|
|
items: list[McpToolSummary] = Field(default_factory=list)
|
|
|
|
|
|
class PluginCommandLocation(str, Enum):
|
|
command_palette = "command_palette"
|
|
context_menu = "context_menu"
|
|
toolbar = "toolbar"
|
|
|
|
|
|
class PluginCommand(Contract):
|
|
command_id: str
|
|
plugin_id: str
|
|
title: str
|
|
description: str = ""
|
|
icon: str | None = None
|
|
locations: list[PluginCommandLocation] = Field(default_factory=list)
|
|
when: list[str] = Field(default_factory=list)
|
|
parameters: dict[str, Any] = Field(default_factory=dict)
|
|
enabled: bool = True
|
|
|
|
|
|
class PluginCommandListResponse(Contract):
|
|
items: list[PluginCommand] = Field(default_factory=list)
|
|
|
|
|
|
class PluginCommandContext(Contract):
|
|
vault_id: str | None = None
|
|
note_id: str | None = None
|
|
file_path: str | None = None
|
|
selection: str | None = None
|
|
|
|
|
|
class PluginCommandExecuteRequest(Contract):
|
|
arguments: dict[str, Any] = Field(default_factory=dict)
|
|
context: PluginCommandContext = Field(default_factory=PluginCommandContext)
|
|
|
|
|
|
class PluginNotificationEffectPayload(Contract):
|
|
level: Literal["info", "success", "warning", "error"] = "info"
|
|
message: str = Field(min_length=1, max_length=4096)
|
|
|
|
|
|
class PluginNavigateEffectPayload(Contract):
|
|
route: Literal[
|
|
"vault-entry",
|
|
"workspace",
|
|
"search",
|
|
"chat",
|
|
"agent",
|
|
"tasks",
|
|
"skills",
|
|
"plugins",
|
|
"themes",
|
|
"settings",
|
|
]
|
|
|
|
|
|
class PluginRefreshEffectPayload(Contract):
|
|
scope: Literal["workspace", "commands", "settings", "plugins"]
|
|
|
|
|
|
class PluginJobEffectPayload(Contract):
|
|
job_id: str = Field(
|
|
min_length=1,
|
|
max_length=128,
|
|
pattern=r"^[A-Za-z0-9][A-Za-z0-9._:-]*$",
|
|
)
|
|
|
|
|
|
class PluginNoEffectPayload(Contract):
|
|
pass
|
|
|
|
|
|
class PluginNoEffect(Contract):
|
|
type: Literal["none"] = "none"
|
|
payload: PluginNoEffectPayload = Field(default_factory=PluginNoEffectPayload)
|
|
|
|
|
|
class PluginNotificationEffect(Contract):
|
|
type: Literal["notification"] = "notification"
|
|
payload: PluginNotificationEffectPayload
|
|
|
|
|
|
class PluginNavigateEffect(Contract):
|
|
type: Literal["navigate"] = "navigate"
|
|
payload: PluginNavigateEffectPayload
|
|
|
|
|
|
class PluginRefreshEffect(Contract):
|
|
type: Literal["refresh"] = "refresh"
|
|
payload: PluginRefreshEffectPayload
|
|
|
|
|
|
class PluginJobEffect(Contract):
|
|
type: Literal["job"] = "job"
|
|
payload: PluginJobEffectPayload
|
|
|
|
|
|
PluginCommandEffect = Annotated[
|
|
PluginNoEffect
|
|
| PluginNotificationEffect
|
|
| PluginNavigateEffect
|
|
| PluginRefreshEffect
|
|
| PluginJobEffect,
|
|
Field(discriminator="type"),
|
|
]
|
|
|
|
PLUGIN_COMMAND_EFFECT_TYPES = (
|
|
PluginNoEffect,
|
|
PluginNotificationEffect,
|
|
PluginNavigateEffect,
|
|
PluginRefreshEffect,
|
|
PluginJobEffect,
|
|
)
|
|
|
|
|
|
class PluginCommandResult(Contract):
|
|
command_id: str
|
|
status: Literal["completed"] = "completed"
|
|
effect: PluginCommandEffect = Field(default_factory=PluginNoEffect)
|
|
|
|
|
|
class PluginSettingType(str, Enum):
|
|
string = "string"
|
|
number = "number"
|
|
boolean = "boolean"
|
|
select = "select"
|
|
secret = "secret"
|
|
|
|
|
|
class PluginSettingField(Contract):
|
|
key: str
|
|
label: str
|
|
description: str = ""
|
|
type: PluginSettingType
|
|
required: bool = False
|
|
default: Any | None = None
|
|
minimum: float | None = None
|
|
maximum: float | None = None
|
|
options: list[str] = Field(default_factory=list)
|
|
|
|
|
|
class PluginSecretState(Contract):
|
|
configured: bool = False
|
|
|
|
|
|
class PluginSettingsSchema(Contract):
|
|
plugin_id: str
|
|
schema_version: int = Field(ge=1)
|
|
fields: list[PluginSettingField] = Field(default_factory=list)
|
|
values: dict[str, Any] = Field(default_factory=dict)
|
|
secrets: dict[str, PluginSecretState] = Field(default_factory=dict)
|
|
|
|
|
|
class PluginSettingsUpdateRequest(Contract):
|
|
schema_version: int = Field(ge=1)
|
|
values: dict[str, Any] = Field(default_factory=dict)
|
|
|
|
|
|
class PluginSecretWriteRequest(Contract):
|
|
secret: SecretStr
|
|
|
|
|
|
class PluginSecretStatus(Contract):
|
|
plugin_id: str
|
|
key: str
|
|
configured: bool
|
|
|
|
|
|
class PluginPermissionGrantRequest(Contract):
|
|
permissions: list[str] = Field(default_factory=list)
|
|
|
|
|
|
# Providers
|
|
class ProviderType(str, Enum):
|
|
mock = "mock"
|
|
openai_responses = "openai_responses"
|
|
openai_chat = "openai_chat"
|
|
openai_compatible = "openai_compatible"
|
|
anthropic_messages = "anthropic_messages"
|
|
ollama = "ollama"
|
|
|
|
|
|
class ProviderConfig(Contract):
|
|
provider_id: str
|
|
provider_type: ProviderType
|
|
name: str
|
|
base_url: str | None = None
|
|
default_model: str | None = None
|
|
credential_id: str | None = None
|
|
enabled: bool = True
|
|
capabilities: list[ModelCapability] = Field(default_factory=list)
|
|
|
|
|
|
class ProviderCreateRequest(Contract):
|
|
provider_type: ProviderType
|
|
name: str
|
|
base_url: str | None = None
|
|
default_model: str | None = None
|
|
credential_id: str | None = None
|
|
enabled: bool = True
|
|
|
|
|
|
class ProviderUpdateRequest(Contract):
|
|
name: str | None = None
|
|
base_url: str | None = None
|
|
default_model: str | None = None
|
|
credential_id: str | None = None
|
|
enabled: bool | None = None
|
|
|
|
|
|
class ProviderListResponse(Contract):
|
|
items: list[ProviderConfig] = Field(default_factory=list)
|
|
|
|
|
|
class ProviderPreset(Contract):
|
|
preset_id: str
|
|
name: str
|
|
provider_type: ProviderType
|
|
base_url: str
|
|
default_credential_id: str | None = None
|
|
requires_credential: bool = True
|
|
|
|
|
|
class ProviderPresetListResponse(Contract):
|
|
items: list[ProviderPreset] = Field(default_factory=list)
|
|
|
|
|
|
class CredentialWriteRequest(Contract):
|
|
api_key: SecretStr = Field(min_length=1, max_length=8192)
|
|
|
|
|
|
class CredentialStatus(Contract):
|
|
credential_id: str
|
|
configured: bool
|
|
|
|
|
|
class ModelInfo(Contract):
|
|
model: str
|
|
display_name: str
|
|
capabilities: list[ModelCapability] = Field(default_factory=list)
|
|
|
|
|
|
class ProviderModelsResponse(Contract):
|
|
provider_id: str
|
|
items: list[ModelInfo] = Field(default_factory=list)
|
|
|
|
|
|
class ProviderTestRequest(Contract):
|
|
provider_id: str
|
|
model: str | None = None
|
|
credential_context_id: str | None = None
|
|
|
|
|
|
class ProviderTestResponse(Contract):
|
|
provider_id: str
|
|
success: bool
|
|
latency_ms: int | None = None
|
|
message: str
|
|
|
|
|
|
# Tasks, media and index
|
|
class TaskStatus(str, Enum):
|
|
todo = "todo"
|
|
in_progress = "in_progress"
|
|
done = "done"
|
|
cancelled = "cancelled"
|
|
|
|
|
|
class Task(Contract):
|
|
task_id: str
|
|
title: str
|
|
description: str = ""
|
|
status: TaskStatus = TaskStatus.todo
|
|
note_id: str | None = None
|
|
due_at: datetime | None = None
|
|
created_at: datetime
|
|
updated_at: datetime
|
|
|
|
|
|
class TaskCreateRequest(Contract):
|
|
title: str = Field(min_length=1)
|
|
description: str = ""
|
|
note_id: str | None = None
|
|
due_at: datetime | None = None
|
|
|
|
|
|
class TaskUpdateRequest(Contract):
|
|
title: str | None = None
|
|
description: str | None = None
|
|
status: TaskStatus | None = None
|
|
note_id: str | None = None
|
|
due_at: datetime | None = None
|
|
|
|
|
|
class TaskListResponse(Contract):
|
|
items: list[Task] = Field(default_factory=list)
|
|
page: PageMeta = Field(default_factory=PageMeta)
|
|
|
|
|
|
class TranscriptionRequest(Contract):
|
|
attachment_id: str
|
|
language: str | None = None
|
|
diarization: bool = False
|
|
|
|
|
|
class TranscriptionJob(Contract):
|
|
job_id: str
|
|
attachment_id: str
|
|
status: Literal["queued", "processing", "completed", "failed"]
|
|
text: str | None = None
|
|
error_code: str | None = None
|
|
error_message: str | None = None
|
|
created_at: datetime
|
|
|
|
|
|
class IndexStatus(Contract):
|
|
status: Literal["idle", "queued", "running", "failed"] = "idle"
|
|
pending_jobs: int = 0
|
|
active_job_id: str | None = None
|
|
last_completed_at: datetime | None = None
|
|
error_message: str | None = None
|
|
|
|
|
|
class IndexRebuildRequest(Contract):
|
|
scope: Literal["all", "notes", "vectors"] = "all"
|
|
note_ids: list[str] = Field(default_factory=list)
|
|
force: bool = False
|
|
|
|
|
|
class IndexJob(Contract):
|
|
job_id: str
|
|
status: Literal["queued", "running", "completed", "failed"]
|
|
scope: Literal["all", "notes", "vectors"]
|
|
created_at: datetime
|