Files
dify/api/services/knowledge_fs/product_dto.py
FFXNandautofix-ci[bot] f3f9b121a4 feat(knowledge): add GitHub tree previews to source selection (#45990)
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
2026-11-11 02:47:23 +00:00

4043 lines
169 KiB
Python

"""Typed product and BFF DTOs independent from Dify Dataset/Document models."""
from __future__ import annotations
import hashlib
import json
from datetime import UTC, datetime
from typing import Annotated, Literal, Self
from urllib.parse import urlsplit, urlunsplit
from uuid import UUID
from pydantic import (
AliasChoices,
BaseModel,
ConfigDict,
Field,
FiniteFloat,
JsonValue,
RootModel,
field_validator,
model_validator,
)
from fields.base import ResponseModel
from models.knowledge_fs import (
KnowledgeFSAppSpaceJoinStatus,
KnowledgeFSAppSpaceJoinType,
KnowledgeFSControlSpacePermissionRole,
KnowledgeFSControlSpaceState,
KnowledgeFSControlSpaceVisibility,
KnowledgeFSUpgradeJobStatus,
KnowledgeFSUpgradeStage,
)
from services.knowledge_fs.product_operations import KnowledgeFSProductPermission
from services.knowledge_fs.retrieval_contracts import (
KnowledgeFSAppBindingPayload,
KnowledgeFSMetadataFieldListResponse,
KnowledgeFSMetadataFieldResponse,
KnowledgeFSPublicErrorCode,
KnowledgeFSPublicFailureResponse,
KnowledgeFSQueryImageReference,
KnowledgeFSRetrievalCitationResponse,
KnowledgeFSRetrievalCustomMetadataCondition,
KnowledgeFSRetrievalCustomMetadataFilter,
KnowledgeFSRetrievalCustomMetadataOperator,
KnowledgeFSRetrievalFilterValue,
KnowledgeFSRetrievalMetadataFilters,
KnowledgeFSRetrievalQueryImageReference,
KnowledgeFSRetrievalReservedMetadataNames,
KnowledgeFSRetrievalTestItemResponse,
KnowledgeFSRetrievalTestMetricsResponse,
KnowledgeFSRetrievalTestPayload,
KnowledgeFSRetrievalTestResponse,
)
KnowledgeFSIconIdentity = Annotated[
str,
Field(max_length=72, pattern=r"^(?:builtin:)?[+a-z0-9_-]{1,64}$"),
]
KnowledgeFSIconBackground = Annotated[
str,
Field(pattern=r"^#[0-9A-Fa-f]{6}$"),
]
class KnowledgeFSModelIntent(BaseModel):
plugin_id: str = Field(
min_length=1,
max_length=255,
validation_alias=AliasChoices("plugin_id", "pluginId"),
serialization_alias="pluginId",
)
provider: str = Field(min_length=1, max_length=255)
model: str = Field(min_length=1, max_length=255)
model_config = ConfigDict(extra="forbid", populate_by_name=True, serialize_by_alias=True)
class KnowledgeFSRerankIntent(BaseModel):
enabled: bool
model: KnowledgeFSModelIntent | None = None
model_config = ConfigDict(extra="forbid")
@model_validator(mode="after")
def validate_enabled_model(self) -> KnowledgeFSRerankIntent:
if not self.enabled or self.model is None:
raise ValueError("Agent Knowledge Base retrieval requires an enabled rerank model")
return self
class KnowledgeFSScoreThresholdIntent(BaseModel):
enabled: bool
stage: Literal["mode-final", "rerank"] = "mode-final"
value: float | None = Field(default=None, ge=0, le=1)
model_config = ConfigDict(extra="forbid")
@model_validator(mode="after")
def validate_enabled_value(self) -> KnowledgeFSScoreThresholdIntent:
if self.enabled and self.value is None:
raise ValueError("Enabled score threshold requires a value")
return self
class KnowledgeFSRetrievalProfileIntent(BaseModel):
default_mode: Literal["fast", "research", "deep"] = Field(
validation_alias=AliasChoices("default_mode", "defaultMode"),
serialization_alias="defaultMode",
)
reasoning_model: KnowledgeFSModelIntent = Field(
validation_alias=AliasChoices("reasoning_model", "reasoningModel"),
serialization_alias="reasoningModel",
)
rerank: KnowledgeFSRerankIntent
score_threshold: KnowledgeFSScoreThresholdIntent = Field(
validation_alias=AliasChoices("score_threshold", "scoreThreshold"),
serialization_alias="scoreThreshold",
)
top_k: int = Field(
ge=1,
le=100,
validation_alias=AliasChoices("top_k", "topK"),
serialization_alias="topK",
)
model_config = ConfigDict(extra="forbid", populate_by_name=True, serialize_by_alias=True)
@model_validator(mode="after")
def validate_mode_threshold(self) -> KnowledgeFSRetrievalProfileIntent:
if self.default_mode != "research" and self.score_threshold.enabled and not self.rerank.enabled:
raise ValueError("Fast/Deep mode-final score threshold requires rerank")
return self
class KnowledgeFSInitialWebsiteCrawlOptionsPayload(BaseModel):
include_subpages: bool = True
limit: int = Field(default=100, ge=1, le=200)
model_config = ConfigDict(extra="forbid")
def normalize_knowledge_fs_source_url(source_url: str) -> str:
"""Normalize URL identity without dropping query parameters that may select content."""
value = source_url.strip()
parsed = urlsplit(value)
if parsed.scheme.lower() not in {"http", "https"} or parsed.hostname is None:
return value
host = parsed.hostname.lower()
if ":" in host:
host = f"[{host}]"
try:
port = parsed.port
except ValueError:
return value
default_port = (parsed.scheme.lower() == "http" and port == 80) or (
parsed.scheme.lower() == "https" and port == 443
)
netloc = host if port is None or default_port else f"{host}:{port}"
path = parsed.path or "/"
if path != "/":
path = path.rstrip("/")
return urlunsplit((parsed.scheme.lower(), netloc, path, parsed.query, ""))
class KnowledgeFSInitialWebsiteSelectionPayload(BaseModel):
page_id: str | None = Field(default=None, min_length=1, max_length=128, alias="pageId")
source_url: str = Field(min_length=1, max_length=4_096)
canonical_url: str | None = Field(default=None, min_length=1, max_length=4_096)
title: str | None = Field(default=None, max_length=500)
model_config = ConfigDict(extra="forbid", validate_by_alias=True, validate_by_name=True)
@field_validator("source_url")
@classmethod
def normalize_source_url(cls, source_url: str) -> str:
return source_url.strip()
@model_validator(mode="after")
def populate_canonical_url(self) -> KnowledgeFSInitialWebsiteSelectionPayload:
canonical_url = normalize_knowledge_fs_source_url(self.canonical_url or self.source_url)
object.__setattr__(self, "canonical_url", canonical_url)
return self
class KnowledgeFSOnlineDocumentWorkflowImportItemPayload(BaseModel):
etag: str | None = Field(default=None, max_length=1_024)
last_edited_time: str | None = Field(default=None, max_length=128, alias="lastEditedTime")
name: str | None = Field(default=None, max_length=500)
page_id: str = Field(min_length=1, max_length=1_024, alias="pageId")
provider_item_id: str = Field(min_length=1, max_length=1_024, alias="providerItemId")
type: str = Field(min_length=1, max_length=128)
workspace_id: str = Field(min_length=1, max_length=1_024, alias="workspaceId")
model_config = ConfigDict(extra="forbid", validate_by_alias=True, validate_by_name=True)
class KnowledgeFSOnlineDriveWorkflowImportItemPayload(BaseModel):
bucket: str | None = Field(default=None, max_length=1_024)
etag: str | None = Field(default=None, max_length=1_024)
id: str = Field(min_length=1, max_length=1_024)
mime_type: str | None = Field(default=None, max_length=255, alias="mimeType")
name: str = Field(min_length=1, max_length=500)
provider_item_id: str = Field(min_length=1, max_length=1_024, alias="providerItemId")
model_config = ConfigDict(extra="forbid", validate_by_alias=True, validate_by_name=True)
class KnowledgeFSInitialSyncPolicyPayload(BaseModel):
custom_interval_seconds: int | None = Field(default=None, ge=3_600, le=2_592_000)
sync_policy: Literal["daily", "manual", "custom"] = "daily"
model_config = ConfigDict(extra="forbid")
@model_validator(mode="after")
def validate_custom_interval(self) -> KnowledgeFSInitialSyncPolicyPayload:
if self.sync_policy == "custom" and self.custom_interval_seconds is None:
raise ValueError("custom_interval_seconds is required for a custom sync policy")
if self.sync_policy != "custom" and self.custom_interval_seconds is not None:
raise ValueError("custom_interval_seconds is only valid for a custom sync policy")
return self
class KnowledgeFSInitialDatasourceBindingPayload(BaseModel):
credential_id: str = Field(min_length=1, max_length=255, alias="credentialId")
datasource: str = Field(min_length=1, max_length=255)
plugin_id: str = Field(min_length=1, max_length=255, alias="pluginId")
provider: str = Field(min_length=1, max_length=255)
provider_display_name: str | None = Field(default=None, min_length=1, max_length=255, alias="providerDisplayName")
parameters: dict[str, JsonValue] = Field(default_factory=dict, max_length=50)
model_config = ConfigDict(extra="forbid", validate_by_alias=True, validate_by_name=True)
class KnowledgeFSInitialDatasourceSourcePayload(
KnowledgeFSInitialDatasourceBindingPayload, KnowledgeFSInitialSyncPolicyPayload
):
pass
class KnowledgeFSInitialWebsiteSourcePayload(KnowledgeFSInitialSyncPolicyPayload):
kind: Literal["website_crawl"]
name: str = Field(min_length=1, max_length=200)
provider: str = Field(min_length=1, max_length=255)
plugin_id: str | None = Field(default=None, min_length=1, max_length=255, alias="pluginId")
datasource: str = Field(default="crawl", min_length=1, max_length=255)
credential_id: str | None = Field(default=None, min_length=1, max_length=255, alias="credentialId")
provider_display_name: str | None = Field(default=None, min_length=1, max_length=255, alias="providerDisplayName")
parameters: dict[str, JsonValue] = Field(default_factory=dict, max_length=50)
preview_configuration_fingerprint: str | None = Field(
default=None, min_length=64, max_length=64, alias="previewConfigurationFingerprint"
)
preview_job_id: str | None = Field(default=None, min_length=1, max_length=255, alias="previewJobId")
root_url: str = Field(min_length=1, max_length=4_096)
crawl_options: KnowledgeFSInitialWebsiteCrawlOptionsPayload
selection: list[KnowledgeFSInitialWebsiteSelectionPayload] = Field(min_length=1, max_length=200)
model_config = ConfigDict(extra="forbid", validate_by_alias=True, validate_by_name=True)
@model_validator(mode="after")
def validate_selection(self) -> KnowledgeFSInitialWebsiteSourcePayload:
if self.crawl_options.limit < len(self.selection):
raise ValueError("initial website crawl limit must cover every selected URL")
if (
self.preview_configuration_fingerprint is not None
and self.preview_configuration_fingerprint != knowledge_fs_initial_preview_configuration_fingerprint(self)
):
raise ValueError("initial website preview configuration no longer matches")
return self
class KnowledgeFSInitialOnlineDocumentSourcePayload(KnowledgeFSInitialDatasourceSourcePayload):
kind: Literal["online_document"]
name: str = Field(min_length=1, max_length=200)
selection: list[KnowledgeFSOnlineDocumentWorkflowImportItemPayload] = Field(min_length=1, max_length=200)
class KnowledgeFSInitialOnlineDriveSourcePayload(KnowledgeFSInitialDatasourceSourcePayload):
kind: Literal["online_drive"]
name: str = Field(min_length=1, max_length=200)
selection: list[KnowledgeFSOnlineDriveWorkflowImportItemPayload] = Field(min_length=1, max_length=200)
class KnowledgeFSInitialSourcePreviewPayload(KnowledgeFSInitialDatasourceBindingPayload):
kind: Literal["online_document", "online_drive"]
class KnowledgeFSInitialWebsiteSourcePreviewPayload(KnowledgeFSInitialDatasourceBindingPayload):
kind: Literal["website_crawl"]
def knowledge_fs_initial_preview_configuration_fingerprint(
payload: KnowledgeFSInitialWebsiteSourcePayload | KnowledgeFSInitialWebsiteSourcePreviewPayload,
) -> str:
configuration = {
"credentialId": payload.credential_id,
"datasource": payload.datasource,
"parameters": payload.parameters,
"pluginId": payload.plugin_id,
"provider": payload.provider,
}
encoded = json.dumps(configuration, ensure_ascii=False, separators=(",", ":"), sort_keys=True).encode()
return hashlib.sha256(encoded).hexdigest()
class KnowledgeFSInitialSourcePreviewPageResponse(ResponseModel):
content: str | None = Field(default=None, exclude=True)
description: str | None = None
page_id: str | None = Field(default=None, validation_alias=AliasChoices("page_id", "pageId"))
source_url: str = Field(validation_alias=AliasChoices("source_url", "sourceUrl"))
title: str | None = None
class KnowledgeFSInitialSourcePreviewDocumentResponse(ResponseModel):
has_children: bool | None = Field(default=None, validation_alias=AliasChoices("has_children", "hasChildren"))
last_edited_time: str | None = Field(
default=None, validation_alias=AliasChoices("last_edited_time", "lastEditedTime")
)
name: str
page_id: str = Field(validation_alias=AliasChoices("page_id", "pageId"))
parent_id: str | None = Field(default=None, validation_alias=AliasChoices("parent_id", "parentId"))
provider_item_id: str = Field(validation_alias=AliasChoices("provider_item_id", "providerItemId"))
type: str
workspace_id: str = Field(validation_alias=AliasChoices("workspace_id", "workspaceId"))
workspace_name: str | None = Field(default=None, validation_alias=AliasChoices("workspace_name", "workspaceName"))
class KnowledgeFSInitialSourcePreviewFileResponse(ResponseModel):
bucket: str | None = None
id: str
mime_type: str | None = Field(default=None, validation_alias=AliasChoices("mime_type", "mimeType"))
name: str
provider_item_id: str = Field(validation_alias=AliasChoices("provider_item_id", "providerItemId"))
size: int = Field(ge=0)
type: str
class KnowledgeFSInitialSourcePreviewResponse(ResponseModel):
configuration_fingerprint: str | None = Field(
default=None,
validation_alias=AliasChoices("configuration_fingerprint", "configurationFingerprint"),
)
documents: list[KnowledgeFSInitialSourcePreviewDocumentResponse] = Field(default_factory=list)
files: list[KnowledgeFSInitialSourcePreviewFileResponse] = Field(default_factory=list)
kind: Literal["online_document", "online_drive", "website_crawl"]
next_cursor: str | None = Field(default=None, validation_alias=AliasChoices("next_cursor", "nextCursor"))
next_page_parameters: dict[str, JsonValue] | None = Field(
default=None,
validation_alias=AliasChoices("next_page_parameters", "nextPageParameters"),
)
pages: list[KnowledgeFSInitialSourcePreviewPageResponse] = Field(default_factory=list)
class KnowledgeFSInitialSourcePreviewJobCreateResponse(ResponseModel):
job_id: str = Field(validation_alias=AliasChoices("job_id", "jobId"))
status: Literal["pending"] = "pending"
class KnowledgeFSInitialSourcePreviewJobResponse(ResponseModel):
job_id: str = Field(validation_alias=AliasChoices("job_id", "jobId"))
result: KnowledgeFSInitialSourcePreviewResponse | None = None
status: Literal["pending", "running", "completed", "failed", "canceled"]
class KnowledgeFSNamespacePreviewCreatePayload(BaseModel):
credential_id: str = Field(min_length=1, max_length=255, alias="credentialId")
datasource: str = Field(min_length=1, max_length=255)
plugin_id: str = Field(min_length=1, max_length=1024, alias="pluginId")
provider: str = Field(min_length=1, max_length=255)
parameters: dict[str, JsonValue] = Field(default_factory=dict)
root_url: str = Field(min_length=1, max_length=4096, alias="rootUrl")
configuration_fingerprint: str = Field(min_length=64, max_length=64, alias="configurationFingerprint")
model_config = ConfigDict(extra="forbid", validate_by_alias=True, validate_by_name=True)
class KnowledgeFSNamespacePreviewConsumePayload(BaseModel):
preview_job_id: str = Field(min_length=1, max_length=255, alias="previewJobId")
page_ids: list[str] = Field(min_length=1, max_length=200, alias="pageIds")
configuration_fingerprint: str = Field(min_length=64, max_length=64, alias="configurationFingerprint")
model_config = ConfigDict(extra="forbid", validate_by_alias=True, validate_by_name=True)
class KnowledgeFSNamespacePreviewPageResponse(ResponseModel):
page_id: str = Field(validation_alias=AliasChoices("page_id", "pageId"))
source_url: str = Field(validation_alias=AliasChoices("source_url", "sourceUrl"))
title: str | None = None
description: str | None = None
class KnowledgeFSNamespacePreviewJobResponse(ResponseModel):
job_id: str = Field(validation_alias=AliasChoices("job_id", "jobId"))
status: Literal["queued", "running", "completed", "failed", "canceled", "consumed"]
configuration_fingerprint: str = Field(
validation_alias=AliasChoices("configuration_fingerprint", "configurationFingerprint")
)
expires_at: str = Field(validation_alias=AliasChoices("expires_at", "expiresAt"))
error_code: str | None = Field(default=None, validation_alias=AliasChoices("error_code", "errorCode"))
import_workflow_id: str | None = Field(
default=None, validation_alias=AliasChoices("import_workflow_id", "importWorkflowId")
)
pages: list[KnowledgeFSNamespacePreviewPageResponse] = Field(default_factory=list)
class KnowledgeFSNamespacePreviewImportResponse(ResponseModel):
workflow_id: str = Field(validation_alias=AliasChoices("workflow_id", "workflowId"))
KnowledgeFSInitialSourcePayload = Annotated[
KnowledgeFSInitialWebsiteSourcePayload
| KnowledgeFSInitialOnlineDocumentSourcePayload
| KnowledgeFSInitialOnlineDriveSourcePayload,
Field(discriminator="kind"),
]
class KnowledgeFSSpaceCreateMemberPayload(BaseModel):
account_id: str = Field(min_length=1, max_length=255)
role: Literal["viewer"]
model_config = ConfigDict(extra="forbid")
class KnowledgeFSSpaceCreatePayload(BaseModel):
name: str = Field(min_length=1, max_length=40)
slug: str = Field(min_length=1, max_length=160, pattern=r"^[a-z0-9]+(?:-[a-z0-9]+)*$")
icon: KnowledgeFSIconIdentity | None = None
description: str | None = Field(default=None, max_length=2_000)
visibility: KnowledgeFSControlSpaceVisibility = KnowledgeFSControlSpaceVisibility.ONLY_ME
members: list[KnowledgeFSSpaceCreateMemberPayload] = Field(default_factory=list, max_length=1_000)
embedding: KnowledgeFSModelIntent | None = None
retrieval: KnowledgeFSRetrievalProfileIntent | None = None
idempotency_key: str | None = Field(default=None, min_length=1, max_length=255)
initial_source: KnowledgeFSInitialSourcePayload | None = None
model_config = ConfigDict(extra="forbid")
@model_validator(mode="after")
def validate_initial_model_configuration(self) -> KnowledgeFSSpaceCreatePayload:
if self.retrieval is not None and self.embedding is None:
raise ValueError("Agent Knowledge Base retrieval requires an embedding model")
if self.visibility is KnowledgeFSControlSpaceVisibility.PARTIAL_MEMBERS:
if not self.members:
raise ValueError("Partial member visibility requires at least one member")
elif self.members:
raise ValueError("Initial members require partial member visibility")
if len({member.account_id for member in self.members}) != len(self.members):
raise ValueError("Initial members must be unique")
return self
class KnowledgeFSUpgradeJobResponse(ResponseModel):
id: str
old_dataset_id: str
new_control_space_id: str | None = None
status: KnowledgeFSUpgradeJobStatus
stage: KnowledgeFSUpgradeStage
snapshot_at: datetime
total_documents: int = Field(ge=0)
completed_documents: int = Field(ge=0)
total_sources: int = Field(ge=0)
completed_sources: int = Field(ge=0)
last_error_code: str | None = None
last_error_message: str | None = None
completed_at: datetime | None = None
class KnowledgeFSUpgradeRetryResponse(ResponseModel):
id: str
status: Literal["queued"] = "queued"
class KnowledgeFSUpgradeJobListResponse(ResponseModel):
data: list[KnowledgeFSUpgradeJobResponse]
type KnowledgeFSUpgradeBlockReason = Literal[
"feature_disabled",
"unsupported_dataset_provider",
"upgrade_in_progress",
"retry_required",
"already_upgraded",
]
class KnowledgeFSUpgradeDiscoveryResponse(ResponseModel):
job: KnowledgeFSUpgradeJobResponse | None = None
can_upgrade: bool
can_retry: bool
block_reason: KnowledgeFSUpgradeBlockReason | None = None
class KnowledgeFSUpgradeModelChoice(BaseModel):
provider: str = Field(min_length=1, max_length=255)
model: str = Field(min_length=1, max_length=255)
model_config = ConfigDict(extra="forbid")
class KnowledgeFSUpgradeModelsPayload(BaseModel):
embedding: KnowledgeFSUpgradeModelChoice
rerank: KnowledgeFSUpgradeModelChoice
reasoning: KnowledgeFSUpgradeModelChoice
model_config = ConfigDict(extra="forbid")
class KnowledgeFSUpgradeStartPayload(BaseModel):
# Older callers may omit the body; the server still resolves and validates all three models.
models: KnowledgeFSUpgradeModelsPayload | None = None
model_config = ConfigDict(extra="forbid")
type KnowledgeFSUpgradeModelUnavailableReason = Literal[
"missing",
"not_found",
"deprecated",
"no-configure",
"quota-exceeded",
"no-permission",
"disabled",
"credential-removed",
]
class KnowledgeFSUpgradeModelRecommendationResponse(ResponseModel):
value: KnowledgeFSUpgradeModelChoice | None
source: Literal["legacy", "workspace_default"] | None
available: bool
unavailable_reason: (
Literal[
"missing",
"not_found",
"deprecated",
"no-configure",
"quota-exceeded",
"no-permission",
"disabled",
"credential-removed",
]
| None
) = None
class KnowledgeFSUpgradeModelRecommendationsResponse(ResponseModel):
embedding: KnowledgeFSUpgradeModelRecommendationResponse
rerank: KnowledgeFSUpgradeModelRecommendationResponse
reasoning: KnowledgeFSUpgradeModelRecommendationResponse
class KnowledgeFSUpgradePreparationResponse(KnowledgeFSUpgradeDiscoveryResponse):
# A blocked upgrade does not need model-provider I/O merely to explain its block reason.
models: KnowledgeFSUpgradeModelRecommendationsResponse | None = None
class KnowledgeFSUpgradeModelIssueResponse(ResponseModel):
field: Literal["embedding", "reasoning", "rerank"]
reason: Literal[
"credential-removed",
"deprecated",
"disabled",
"missing",
"no-configure",
"no-permission",
"not_found",
"quota-exceeded",
]
provider: str | None = None
model: str | None = None
class KnowledgeFSUpgradeModelErrorDetailsResponse(ResponseModel):
issues: list[KnowledgeFSUpgradeModelIssueResponse] = Field(min_length=1, max_length=3)
class KnowledgeFSSpaceUpdatePayload(BaseModel):
name: str | None = Field(default=None, min_length=1, max_length=40)
icon: KnowledgeFSIconIdentity | None = None
icon_background: KnowledgeFSIconBackground | None = None
description: str | None = Field(default=None, max_length=2_000)
visibility: KnowledgeFSControlSpaceVisibility | None = None
model_config = ConfigDict(extra="forbid")
class KnowledgeFSSpaceListQuery(BaseModel):
page: int = Field(default=1, ge=1)
limit: int = Field(default=20, ge=1, le=100)
query: str | None = Field(default=None, max_length=255)
creator_ids: list[Annotated[str, Field(min_length=1, max_length=255)]] | None = Field(
default=None,
max_length=100,
description="Filter by creator account IDs",
)
tag_ids: list[Annotated[str, Field(min_length=1, max_length=255)]] | None = Field(
default=None,
max_length=100,
description="Filter by knowledge tag IDs using match-any semantics",
)
model_config = ConfigDict(extra="forbid")
@field_validator("creator_ids", "tag_ids")
@classmethod
def normalize_creator_ids(cls, value: list[str] | None) -> list[str] | None:
return value or None
@field_validator("query")
@classmethod
def normalize_query(cls, value: str | None) -> str | None:
normalized = value.strip() if value is not None else ""
return normalized or None
class KnowledgeFSCursorQuery(BaseModel):
limit: int = Field(default=50, ge=1, le=100)
cursor: str | None = Field(default=None, min_length=1, max_length=1_000)
model_config = ConfigDict(extra="forbid")
type KnowledgeFSDocumentDisplayStatus = Literal["ready", "queued", "processing", "failed", "disabled"]
class KnowledgeFSLogicalDocumentListQuery(KnowledgeFSCursorQuery):
query: str | None = Field(default=None, max_length=200)
status: KnowledgeFSDocumentDisplayStatus | None = None
@field_validator("query")
@classmethod
def normalize_query(cls, value: str | None) -> str | None:
return value.strip() or None if value is not None else None
# Who produced a retrieval trace: the console retrieval test, a KnowledgeFS workflow node, the
# service API, an agent, or an MCP client. Mirrors KnowledgeFS `AnswerTraceSourceSchema`.
type KnowledgeFSTraceSource = Literal["retrieval_test", "workflow", "service_api", "agent", "mcp"]
class KnowledgeFSTraceListQuery(KnowledgeFSCursorQuery):
source: KnowledgeFSTraceSource | None = Field(default=None)
class KnowledgeFSDocumentReferenceQuery(BaseModel):
document_asset_id: str = Field(min_length=1, max_length=255)
document_asset_version: int = Field(ge=1)
model_config = ConfigDict(extra="forbid")
type KnowledgeFSConsistencyClass = Literal[
"path-consistent",
"snapshot-consistent",
"cache-consistent",
"eventual-preview",
]
type KnowledgeFSResourceType = Literal["source", "document", "node", "artifact", "evidence", "workspace"]
KNOWLEDGE_FS_PATH_PATTERN = r"^/(?:sources|knowledge|evidence|workspaces)(?:/[^/\s]+)*$"
class KnowledgeFSListQuery(BaseModel):
path: str = Field(min_length=1, max_length=4_096, pattern=KNOWLEDGE_FS_PATH_PATTERN)
limit: int = Field(default=20, ge=1, le=100)
cursor: str | None = Field(default=None, min_length=1, max_length=8_192)
consistency_class: KnowledgeFSConsistencyClass | None = None
model_config = ConfigDict(extra="forbid")
class KnowledgeFSTreeQuery(KnowledgeFSListQuery):
depth: int | None = Field(default=None, ge=1, le=8)
class KnowledgeFSGrepQuery(KnowledgeFSListQuery):
query: str = Field(min_length=1, max_length=4_000)
timeout_ms: int | None = Field(default=None, ge=1, le=10_000)
@field_validator("query", mode="before")
@classmethod
def normalize_query(cls, value: object) -> object:
return value.strip() if isinstance(value, str) else value
class KnowledgeFSFindQuery(KnowledgeFSListQuery):
metadata_key: str | None = Field(default=None, min_length=1, max_length=120)
metadata_value: str | None = Field(default=None, min_length=1, max_length=4_000)
name_contains: str | None = Field(default=None, min_length=1, max_length=240)
resource_type: KnowledgeFSResourceType | None = None
class KnowledgeFSCatQuery(BaseModel):
path: str = Field(min_length=1, max_length=4_096, pattern=KNOWLEDGE_FS_PATH_PATTERN)
cursor: str | None = Field(default=None, min_length=1, max_length=8_192)
limit: int | None = Field(default=None, ge=1, le=100)
consistency_class: KnowledgeFSConsistencyClass | None = None
model_config = ConfigDict(extra="forbid")
class KnowledgeFSStatQuery(BaseModel):
path: str = Field(min_length=1, max_length=4_096, pattern=KNOWLEDGE_FS_PATH_PATTERN)
consistency_class: KnowledgeFSConsistencyClass | None = None
model_config = ConfigDict(extra="forbid")
class KnowledgeFSDiffQuery(BaseModel):
old_path: str = Field(min_length=1, max_length=4_096, pattern=KNOWLEDGE_FS_PATH_PATTERN)
new_path: str = Field(min_length=1, max_length=4_096, pattern=KNOWLEDGE_FS_PATH_PATTERN)
mode: Literal["line", "word"] | None = None
semantic: bool | None = None
consistency_class: KnowledgeFSConsistencyClass | None = None
model_config = ConfigDict(extra="forbid")
class KnowledgeFSEntryResponse(ResponseModel):
kind: Literal["directory", "resource"]
metadata: dict[str, JsonValue]
name: str
path: str
resource_type: KnowledgeFSResourceType | None = Field(
default=None, validation_alias=AliasChoices("resource_type", "resourceType")
)
target_id: str | None = Field(default=None, validation_alias=AliasChoices("target_id", "targetId"))
version: int | None = Field(default=None, ge=1)
class KnowledgeFSListResponse(ResponseModel):
consistency_class: KnowledgeFSConsistencyClass | None = Field(
default=None, validation_alias=AliasChoices("consistency_class", "consistencyClass")
)
items: list[KnowledgeFSEntryResponse]
next_cursor: str | None = Field(default=None, validation_alias=AliasChoices("next_cursor", "nextCursor"))
path: str
preview: bool | None = None
truncated: bool
class KnowledgeFSTreeNodeResponse(KnowledgeFSEntryResponse):
children: list[KnowledgeFSTreeNodeResponse] | None = None
class KnowledgeFSTreeResponse(ResponseModel):
consistency_class: KnowledgeFSConsistencyClass | None = Field(
default=None, validation_alias=AliasChoices("consistency_class", "consistencyClass")
)
next_cursor: str | None = Field(default=None, validation_alias=AliasChoices("next_cursor", "nextCursor"))
path: str
preview: bool | None = None
root: KnowledgeFSTreeNodeResponse
truncated: bool
class KnowledgeFSGrepMatchResponse(ResponseModel):
end_offset: int = Field(ge=0, validation_alias=AliasChoices("end_offset", "endOffset"))
kind: Literal["node", "segment"]
metadata: dict[str, JsonValue]
node_id: str | None = Field(default=None, validation_alias=AliasChoices("node_id", "nodeId"))
path: str
segment_id: str | None = Field(default=None, validation_alias=AliasChoices("segment_id", "segmentId"))
snippet: str
start_offset: int = Field(ge=0, validation_alias=AliasChoices("start_offset", "startOffset"))
class KnowledgeFSGrepResponse(ResponseModel):
matches: list[KnowledgeFSGrepMatchResponse]
next_cursor: str | None = Field(default=None, validation_alias=AliasChoices("next_cursor", "nextCursor"))
path: str
truncated: bool
class KnowledgeFSDiffOperationResponse(ResponseModel):
kind: Literal["equal", "insert", "delete"]
new_end: int | None = Field(default=None, ge=1, validation_alias=AliasChoices("new_end", "newEnd"))
new_start: int | None = Field(default=None, ge=1, validation_alias=AliasChoices("new_start", "newStart"))
old_end: int | None = Field(default=None, ge=1, validation_alias=AliasChoices("old_end", "oldEnd"))
old_start: int | None = Field(default=None, ge=1, validation_alias=AliasChoices("old_start", "oldStart"))
text: str
class KnowledgeFSSemanticDiffChangeResponse(ResponseModel):
category: str
evidence: list[str]
summary: str
class KnowledgeFSSemanticDiffResponse(ResponseModel):
changes: list[KnowledgeFSSemanticDiffChangeResponse]
metadata: dict[str, JsonValue]
model: str | None = None
summary: str
class KnowledgeFSDiffStatsResponse(ResponseModel):
delete: int = Field(ge=0)
equal: int = Field(ge=0)
insert: int = Field(ge=0)
class KnowledgeFSDiffResponse(ResponseModel):
mode: Literal["line", "word"]
new_path: str = Field(validation_alias=AliasChoices("new_path", "newPath"))
old_path: str = Field(validation_alias=AliasChoices("old_path", "oldPath"))
operations: list[KnowledgeFSDiffOperationResponse]
semantic: KnowledgeFSSemanticDiffResponse | None = None
stats: KnowledgeFSDiffStatsResponse
class KnowledgeFSCatResponse(ResponseModel):
content_type: str = Field(validation_alias=AliasChoices("content_type", "contentType"))
next_cursor: str | None = Field(default=None, validation_alias=AliasChoices("next_cursor", "nextCursor"))
path: str
text: str
truncated: bool
class KnowledgeFSStatResponse(ResponseModel):
consistency_class: KnowledgeFSConsistencyClass | None = Field(
default=None, validation_alias=AliasChoices("consistency_class", "consistencyClass")
)
content_type: str | None = Field(default=None, validation_alias=AliasChoices("content_type", "contentType"))
metadata: dict[str, JsonValue]
parser_status: Literal["pending", "parsed", "failed"] | None = Field(
default=None, validation_alias=AliasChoices("parser_status", "parserStatus")
)
path: str
resource_type: KnowledgeFSResourceType = Field(validation_alias=AliasChoices("resource_type", "resourceType"))
sha256: str | None = None
size_bytes: int | None = Field(default=None, ge=0, validation_alias=AliasChoices("size_bytes", "sizeBytes"))
target_id: str = Field(validation_alias=AliasChoices("target_id", "targetId"))
preview: bool | None = None
version: int | None = Field(default=None, ge=1)
class KnowledgeFSQualityListQuery(KnowledgeFSCursorQuery):
limit: int = Field(default=50, ge=1, le=100)
class KnowledgeFSSourceListQuery(KnowledgeFSCursorQuery):
limit: int = Field(default=50, ge=1, le=200)
class KnowledgeFSBackgroundTaskListQuery(BaseModel):
task_ids: str | None = Field(
default=None,
max_length=3699,
pattern=r"^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}(,[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}){0,99}$",
description="Comma-separated document or document_bulk task IDs for an exact lookup",
)
cursor: str | None = Field(default=None, min_length=1, max_length=8_192)
limit: int = Field(default=50, ge=1, le=100)
model_config = ConfigDict(extra="forbid")
class KnowledgeFSOverviewWindowQuery(BaseModel):
window: Literal["24h", "7d", "30d"] = "24h"
model_config = ConfigDict(extra="forbid")
class KnowledgeFSIdempotencyHeader(BaseModel):
idempotency_key: str = Field(
min_length=8,
max_length=255,
validation_alias=AliasChoices("Idempotency-Key", "idempotency-key", "idempotency_key"),
)
model_config = ConfigDict(extra="forbid")
@field_validator("idempotency_key")
@classmethod
def validate_header_value(cls, value: str) -> str:
if value != value.strip() or any(ord(character) < 32 or ord(character) > 126 for character in value):
raise ValueError("Idempotency-Key must use ASCII without surrounding whitespace or control characters")
return value
class KnowledgeFSTechnicalSummary(BaseModel):
knowledge_space_id: str = Field(validation_alias=AliasChoices("knowledge_space_id", "knowledgeSpaceId"))
revision: int = Field(ge=0)
name: str
slug: str
icon: str | None = None
icon_background: KnowledgeFSIconBackground | None = None
description: str | None = None
document_count: int = Field(
default=0,
ge=0,
validation_alias=AliasChoices("document_count", "documentCount"),
)
index_state: str | None = Field(default=None, validation_alias=AliasChoices("index_state", "indexState"))
model_profile: dict[str, object] | None = Field(
default=None,
validation_alias=AliasChoices("model_profile", "modelProfile"),
)
last_job_state: str | None = Field(
default=None,
validation_alias=AliasChoices("last_job_state", "lastJobState"),
)
model_config = ConfigDict(extra="forbid")
class KnowledgeFSBatchTechnicalSummaryResponse(BaseModel):
items: list[KnowledgeFSTechnicalSummary] = Field(max_length=100)
model_config = ConfigDict(extra="forbid")
class KnowledgeFSOverviewStatsWindowResponse(ResponseModel):
answer_rate: float = Field(ge=0, le=1, validation_alias=AliasChoices("answer_rate", "answerRate"))
answered_query_count: int = Field(
ge=0,
validation_alias=AliasChoices("answered_query_count", "answeredQueryCount"),
)
query_count: int = Field(ge=0, validation_alias=AliasChoices("query_count", "queryCount"))
since: datetime
class KnowledgeFSOverviewStatsCurrentResponse(ResponseModel):
fresh_source_count: int = Field(
ge=0,
validation_alias=AliasChoices("fresh_source_count", "freshSourceCount"),
)
knowledge_count: int = Field(
ge=0,
validation_alias=AliasChoices("knowledge_count", "knowledgeCount"),
)
latest_source_sync_at: datetime | None = Field(
default=None,
validation_alias=AliasChoices("latest_source_sync_at", "latestSourceSyncAt"),
)
linked_app_count: int = Field(
ge=0,
validation_alias=AliasChoices("linked_app_count", "linkedAppCount"),
)
source_count: int = Field(ge=0, validation_alias=AliasChoices("source_count", "sourceCount"))
stale_source_count: int = Field(
ge=0,
validation_alias=AliasChoices("stale_source_count", "staleSourceCount"),
)
class KnowledgeFSOverviewBaseStatsResponse(ResponseModel):
current: KnowledgeFSOverviewStatsCurrentResponse
generated_at: datetime = Field(validation_alias=AliasChoices("generated_at", "generatedAt"))
knowledge_space_id: str = Field(validation_alias=AliasChoices("knowledge_space_id", "knowledgeSpaceId"))
windows: dict[Literal["24h", "7d", "30d"], KnowledgeFSOverviewStatsWindowResponse]
class KnowledgeFSOverviewQueryOutcomeCountsResponse(ResponseModel):
answer_rate: float = Field(ge=0, le=1, validation_alias=AliasChoices("answer_rate", "answerRate"))
answered: int = Field(ge=0)
low_confidence: int = Field(
ge=0,
validation_alias=AliasChoices("low_confidence", "lowConfidence"),
)
no_evidence: int = Field(ge=0, validation_alias=AliasChoices("no_evidence", "noEvidence"))
query_count: int = Field(ge=0, validation_alias=AliasChoices("query_count", "queryCount"))
class KnowledgeFSOverviewQueryOutcomeBucketResponse(ResponseModel):
answered: int = Field(ge=0)
end_at: datetime = Field(validation_alias=AliasChoices("end_at", "endAt"))
low_confidence: int = Field(
ge=0,
validation_alias=AliasChoices("low_confidence", "lowConfidence"),
)
no_evidence: int = Field(ge=0, validation_alias=AliasChoices("no_evidence", "noEvidence"))
query_count: int = Field(ge=0, validation_alias=AliasChoices("query_count", "queryCount"))
start_at: datetime = Field(validation_alias=AliasChoices("start_at", "startAt"))
class KnowledgeFSOverviewQueryOutcomesResponse(ResponseModel):
buckets: list[KnowledgeFSOverviewQueryOutcomeBucketResponse]
current: KnowledgeFSOverviewQueryOutcomeCountsResponse
generated_at: datetime = Field(validation_alias=AliasChoices("generated_at", "generatedAt"))
knowledge_space_id: str = Field(validation_alias=AliasChoices("knowledge_space_id", "knowledgeSpaceId"))
previous: KnowledgeFSOverviewQueryOutcomeCountsResponse
previous_since: datetime = Field(validation_alias=AliasChoices("previous_since", "previousSince"))
since: datetime
window: Literal["24h", "7d", "30d"]
class KnowledgeFSOverviewSourceCategoriesResponse(ResponseModel):
crawl: int = Field(ge=0)
online_documents: int = Field(
ge=0,
validation_alias=AliasChoices("online_documents", "onlineDocuments"),
)
online_drives: int = Field(
ge=0,
validation_alias=AliasChoices("online_drives", "onlineDrives"),
)
uploads: int = Field(ge=0)
class KnowledgeFSOverviewInventoryDeltaResponse(ResponseModel):
added_last_7d: int = Field(
ge=0,
validation_alias=AliasChoices("added_last_7d", "addedLast7d"),
)
total: int = Field(ge=0)
class KnowledgeFSOverviewIndexCoverageResponse(ResponseModel):
indexed: int = Field(ge=0)
percentage: float = Field(ge=0, le=100)
total: int = Field(ge=0)
class KnowledgeFSOverviewInventoryResponse(ResponseModel):
generated_at: datetime = Field(validation_alias=AliasChoices("generated_at", "generatedAt"))
graph_entities: KnowledgeFSOverviewInventoryDeltaResponse = Field(
validation_alias=AliasChoices("graph_entities", "graphEntities")
)
graph_relations: KnowledgeFSOverviewInventoryDeltaResponse = Field(
validation_alias=AliasChoices("graph_relations", "graphRelations")
)
index_coverage: KnowledgeFSOverviewIndexCoverageResponse = Field(
validation_alias=AliasChoices("index_coverage", "indexCoverage")
)
knowledge_space_id: str = Field(validation_alias=AliasChoices("knowledge_space_id", "knowledgeSpaceId"))
source_categories: KnowledgeFSOverviewSourceCategoriesResponse = Field(
validation_alias=AliasChoices("source_categories", "sourceCategories")
)
class KnowledgeFSOverviewHealthComponentResponse(ResponseModel):
codes: list[str]
state: Literal["healthy", "degraded", "unavailable", "unknown"]
class KnowledgeFSOverviewHealthComponentsResponse(ResponseModel):
index: KnowledgeFSOverviewHealthComponentResponse
ingestion: KnowledgeFSOverviewHealthComponentResponse
profile_publication: KnowledgeFSOverviewHealthComponentResponse = Field(
validation_alias=AliasChoices("profile_publication", "profilePublication")
)
query_availability: KnowledgeFSOverviewHealthComponentResponse = Field(
validation_alias=AliasChoices("query_availability", "queryAvailability")
)
source_freshness: KnowledgeFSOverviewHealthComponentResponse = Field(
validation_alias=AliasChoices("source_freshness", "sourceFreshness")
)
worker_readiness: KnowledgeFSOverviewHealthComponentResponse = Field(
validation_alias=AliasChoices("worker_readiness", "workerReadiness")
)
class KnowledgeFSOverviewHealthResponse(ResponseModel):
components: KnowledgeFSOverviewHealthComponentsResponse
generated_at: datetime = Field(validation_alias=AliasChoices("generated_at", "generatedAt"))
knowledge_space_id: str = Field(validation_alias=AliasChoices("knowledge_space_id", "knowledgeSpaceId"))
state: Literal["healthy", "degraded", "unavailable", "unknown"]
class KnowledgeFSOverviewAttentionListQuery(BaseModel):
include_dismissed: bool = False
limit: int = Field(default=50, ge=1, le=100)
model_config = ConfigDict(extra="forbid")
class KnowledgeFSOverviewAttentionActionResponse(ResponseModel):
kind: Literal["open-resource", "review-permissions", "review-models"]
resource_id: str | None = Field(
default=None,
validation_alias=AliasChoices("resource_id", "resourceId"),
)
resource_type: Literal["knowledge-space", "document", "source", "failed-query"] = Field(
validation_alias=AliasChoices("resource_type", "resourceType")
)
class KnowledgeFSOverviewAttentionEvidenceResponse(ResponseModel):
code: str
observed_at: datetime = Field(validation_alias=AliasChoices("observed_at", "observedAt"))
value: float | str | None = None
class KnowledgeFSOverviewAttentionResourceResponse(ResponseModel):
id: str
type: Literal["knowledge-space", "document", "source", "failed-query"]
class KnowledgeFSOverviewAttentionResponse(ResponseModel):
action: KnowledgeFSOverviewAttentionActionResponse
dismissed_until: datetime | None = Field(
default=None,
validation_alias=AliasChoices("dismissed_until", "dismissedUntil"),
)
evidence: list[KnowledgeFSOverviewAttentionEvidenceResponse]
issue_key: str = Field(validation_alias=AliasChoices("issue_key", "issueKey"))
knowledge_space_id: str = Field(validation_alias=AliasChoices("knowledge_space_id", "knowledgeSpaceId"))
resource: KnowledgeFSOverviewAttentionResourceResponse
revision: int = Field(ge=1)
rule_id: Literal[
"stale-source",
"failed-document",
"low-quality-query",
"permission-readiness",
"model-readiness",
] = Field(validation_alias=AliasChoices("rule_id", "ruleId"))
severity: Literal["critical", "warning", "info"]
status: Literal["active", "dismissed", "resolved"]
title: str
updated_at: datetime = Field(validation_alias=AliasChoices("updated_at", "updatedAt"))
class KnowledgeFSOverviewAttentionListResponse(ResponseModel):
data: list[KnowledgeFSOverviewAttentionResponse] = Field(validation_alias=AliasChoices("data", "items"))
class KnowledgeFSOverviewActivityListQuery(BaseModel):
action: (
Literal[
"query.requested",
"query.completed",
"query.failed",
"document.published",
"document.failed",
"source.synced",
"source.failed",
"settings.updated",
"permission.updated",
"profile.published",
"worker.failed",
]
| None
) = None
actor_id: str | None = Field(default=None, min_length=1, max_length=255)
actor_type: Literal["member", "system"] | None = None
cursor: str | None = Field(default=None, min_length=1, max_length=512)
from_at: datetime | None = Field(default=None, validation_alias=AliasChoices("from_at", "from"))
limit: int = Field(default=50, ge=1, le=100)
resource_type: (
Literal[
"knowledge-space",
"query",
"document",
"source",
"permission",
"profile",
"publication",
"worker",
]
| None
) = None
result: Literal["pending", "success", "failure", "canceled"] | None = None
to_at: datetime | None = Field(default=None, validation_alias=AliasChoices("to_at", "to"))
model_config = ConfigDict(extra="forbid", populate_by_name=True)
@model_validator(mode="after")
def validate_time_range(self) -> KnowledgeFSOverviewActivityListQuery:
if self.actor_type == "system" and self.actor_id is not None:
raise ValueError("actor_id cannot be combined with the system actor type")
if self.from_at is not None and self.to_at is not None and self.from_at > self.to_at:
raise ValueError("from must not be after to")
return self
class KnowledgeFSOverviewActivityActorResponse(ResponseModel):
id: str | None = None
type: Literal["member", "system"]
class KnowledgeFSOverviewActivityResourceResponse(ResponseModel):
id: str | None = None
type: Literal[
"knowledge-space",
"query",
"document",
"source",
"permission",
"profile",
"publication",
"worker",
]
class KnowledgeFSOverviewActivityResponse(ResponseModel):
action: Literal[
"query.requested",
"query.completed",
"query.failed",
"document.published",
"document.failed",
"source.synced",
"source.failed",
"settings.updated",
"permission.updated",
"profile.published",
"worker.failed",
]
actor: KnowledgeFSOverviewActivityActorResponse
details: dict[str, bool | float | str]
id: str
occurred_at: datetime = Field(validation_alias=AliasChoices("occurred_at", "occurredAt"))
resource: KnowledgeFSOverviewActivityResourceResponse
result: Literal["pending", "success", "failure", "canceled"]
class KnowledgeFSOverviewActivityListResponse(ResponseModel):
data: list[KnowledgeFSOverviewActivityResponse] = Field(validation_alias=AliasChoices("data", "items"))
next_cursor: str | None = Field(
default=None,
validation_alias=AliasChoices("next_cursor", "nextCursor"),
)
class KnowledgeFSOverviewCountComparisonResponse(ResponseModel):
change_rate: float | None
previous_value: int = Field(ge=0)
value: int = Field(ge=0)
class KnowledgeFSOverviewRateComparisonResponse(ResponseModel):
change_percentage_points: float
previous_value: float = Field(ge=0, le=1)
value: float = Field(ge=0, le=1)
class KnowledgeFSOverviewStatsResponse(ResponseModel):
answer_rate: KnowledgeFSOverviewRateComparisonResponse
documents: int = Field(ge=0)
fresh_source_count: int = Field(ge=0)
freshness_seconds: int | None = Field(default=None, ge=0)
generated_at: datetime
knowledge_space_id: str
latest_source_sync_at: datetime | None = None
linked_apps: int = Field(ge=0)
queries: KnowledgeFSOverviewCountComparisonResponse
source_count: int = Field(ge=0)
stale_source_count: int = Field(ge=0)
window: Literal["24h", "7d", "30d"]
class KnowledgeFSSpaceResponse(ResponseModel):
control_space_id: str
created_at: datetime
state: KnowledgeFSControlSpaceState
visibility: KnowledgeFSControlSpaceVisibility
owner_account_id: str
knowledge_space_id: str | None
resource_version: int
permission_keys: list[KnowledgeFSProductPermission]
technical_status: Literal["available", "not_ready", "unavailable"]
technical_summary: KnowledgeFSTechnicalSummary | None = None
updated_at: datetime
@field_validator("created_at", "updated_at")
@classmethod
def normalize_control_space_timestamp(cls, value: datetime) -> datetime:
if value.tzinfo is None or value.utcoffset() is None:
return value.replace(tzinfo=UTC)
return value.astimezone(UTC)
class KnowledgeFSSpaceTagResponse(ResponseModel):
id: str
name: str
type: Literal["knowledge"] = "knowledge"
class KnowledgeFSSpaceTagListResponse(ResponseModel):
data: list[KnowledgeFSSpaceTagResponse]
class KnowledgeFSSpaceTagsReplacePayload(BaseModel):
tag_ids: list[str] = Field(default_factory=list, max_length=100)
model_config = ConfigDict(extra="forbid")
class KnowledgeFSSpaceListItemResponse(KnowledgeFSSpaceResponse):
linked_apps: int = Field(ge=0)
tags: list[KnowledgeFSSpaceTagResponse] = Field(default_factory=list)
class KnowledgeFSSpaceListResponse(ResponseModel):
data: list[KnowledgeFSSpaceListItemResponse]
page: int
limit: int
has_more: bool
class KnowledgeFSSpaceDetailResponse(KnowledgeFSSpaceResponse):
pass
class KnowledgeFSSpaceCreateResponse(ResponseModel):
control_space_id: str
state: KnowledgeFSControlSpaceState
operation_id: str
model_setup_required: bool
class KnowledgeFSPermissionResponse(ResponseModel):
account_id: str
role: KnowledgeFSControlSpacePermissionRole
status: str
revision: int
class KnowledgeFSPermissionListResponse(ResponseModel):
data: list[KnowledgeFSPermissionResponse]
class KnowledgeFSMemberBindingPayload(BaseModel):
account_id: str = Field(min_length=1)
role: KnowledgeFSControlSpacePermissionRole
model_config = ConfigDict(extra="forbid")
class KnowledgeFSMembersReplacePayload(BaseModel):
members: list[KnowledgeFSMemberBindingPayload] = Field(max_length=1_000)
model_config = ConfigDict(extra="forbid")
class KnowledgeFSExternalAccessPayload(BaseModel):
service_api_enabled: bool
agent_enabled: bool
workflow_enabled: bool
mcp_enabled: bool = False
model_config = ConfigDict(extra="forbid")
class KnowledgeFSExternalAccessResponse(ResponseModel):
service_api_enabled: bool
agent_enabled: bool
workflow_enabled: bool
mcp_enabled: bool
revision: int
class KnowledgeFSAppBindingResponse(ResponseModel):
id: str
app_id: str
caller_kind: KnowledgeFSAppSpaceJoinType
status: KnowledgeFSAppSpaceJoinStatus
revision: int
class KnowledgeFSAppBindingListResponse(ResponseModel):
data: list[KnowledgeFSAppBindingResponse]
class KnowledgeFSProfileModelSelection(BaseModel):
model: str = Field(min_length=1, max_length=256)
plugin_id: str = Field(min_length=1, max_length=256, alias="pluginId")
provider: str = Field(min_length=1, max_length=256)
model_config = ConfigDict(
extra="forbid",
validate_by_alias=True,
validate_by_name=True,
serialize_by_alias=True,
)
class KnowledgeFSProductRerankProfile(BaseModel):
enabled: bool
model: KnowledgeFSProfileModelSelection | None = None
model_config = ConfigDict(extra="forbid")
class KnowledgeFSProductScoreThreshold(BaseModel):
enabled: bool
stage: Literal["mode-final", "rerank"] = "mode-final"
value: float | None = Field(default=None, ge=0, le=1)
model_config = ConfigDict(extra="forbid")
class KnowledgeFSProductRetrievalProfile(BaseModel):
default_mode: Literal["deep", "fast", "research"] = Field(alias="defaultMode")
reasoning_model: KnowledgeFSProfileModelSelection = Field(alias="reasoningModel")
rerank: KnowledgeFSProductRerankProfile
score_threshold: KnowledgeFSProductScoreThreshold = Field(alias="scoreThreshold")
top_k: int = Field(ge=1, le=100, alias="topK")
model_config = ConfigDict(extra="forbid", validate_by_alias=True, validate_by_name=True)
@model_validator(mode="after")
def validate_mode_threshold(self) -> KnowledgeFSProductRetrievalProfile:
if self.default_mode != "research" and self.score_threshold.enabled and not self.rerank.enabled:
raise ValueError("Fast/Deep mode-final score threshold requires rerank")
return self
class KnowledgeFSRetrievalProfileUpdatePayload(BaseModel):
expected_revision: int = Field(ge=0, alias="expectedRevision")
profile: KnowledgeFSProductRetrievalProfile
model_config = ConfigDict(extra="forbid", validate_by_alias=True, validate_by_name=True)
class KnowledgeFSSettingsPayload(BaseModel):
embedding: KnowledgeFSProfileModelSelection | None = None
retrieval: KnowledgeFSProductRetrievalProfile | None = None
expected_revision: int = Field(ge=1, alias="expectedRevision")
model_config = ConfigDict(extra="forbid", validate_by_alias=True, validate_by_name=True)
@model_validator(mode="after")
def validate_setting_present(self) -> KnowledgeFSSettingsPayload:
if self.embedding is None and self.retrieval is None:
raise ValueError("At least one Agent Knowledge Base setting must be supplied")
if self.retrieval is not None and (not self.retrieval.rerank.enabled or self.retrieval.rerank.model is None):
raise ValueError("Agent Knowledge Base retrieval requires an enabled rerank model")
return self
class KnowledgeFSEmbeddingSettingsResponse(ResponseModel):
model: str
plugin_id: str = Field(validation_alias=AliasChoices("plugin_id", "pluginId"))
provider: str
dimension: int | None = Field(default=None, ge=1)
revision: int | None = Field(default=None, ge=1)
vector_space_id: str | None = Field(default=None, validation_alias=AliasChoices("vector_space_id", "vectorSpaceId"))
class KnowledgeFSRetrievalSettingsResponse(ResponseModel):
default_mode: Literal["deep", "fast", "research"] = Field(
validation_alias=AliasChoices("default_mode", "defaultMode")
)
reasoning_model: KnowledgeFSEmbeddingSettingsResponse = Field(
validation_alias=AliasChoices("reasoning_model", "reasoningModel")
)
rerank: KnowledgeFSProductRerankProfile
score_threshold: KnowledgeFSProductScoreThreshold = Field(
validation_alias=AliasChoices("score_threshold", "scoreThreshold")
)
top_k: int = Field(ge=1, le=100, validation_alias=AliasChoices("top_k", "topK"))
revision: int | None = Field(default=None, ge=1)
class KnowledgeFSReadinessCapabilities(ResponseModel):
deep: bool
ingest: bool
index: bool
source_sync: bool = Field(validation_alias=AliasChoices("source_sync", "sourceSync"))
query: bool
research: bool
class KnowledgeFSReadinessIssue(ResponseModel):
field: Literal["embedding", "reasoning", "rerank", "publication"]
code: Literal["missing", "unavailable", "incompatible", "validation_failed", "binding_missing"]
retryable: bool
class KnowledgeFSActiveProfileRevisions(ResponseModel):
embedding: int | None = Field(default=None, ge=1)
retrieval: int | None = Field(default=None, ge=1)
class KnowledgeFSSettingsResponse(ResponseModel):
revision: int = Field(ge=1)
configuration_state: Literal["active", "pending-validation", "setup-required", "validation-failed"] = Field(
validation_alias=AliasChoices("configuration_state", "configurationState")
)
active_profile_available: bool = Field(
validation_alias=AliasChoices("active_profile_available", "activeProfileAvailable")
)
active_profile_revisions: KnowledgeFSActiveProfileRevisions = Field(
validation_alias=AliasChoices("active_profile_revisions", "activeProfileRevisions")
)
capabilities: KnowledgeFSReadinessCapabilities
embedding: KnowledgeFSEmbeddingSettingsResponse | None
issues: list[KnowledgeFSReadinessIssue]
retrieval: KnowledgeFSRetrievalSettingsResponse | None
class KnowledgeFSProfileMigrationResponse(ResponseModel):
candidate_publication_fingerprint: str | None = Field(
default=None,
validation_alias=AliasChoices("candidate_publication_fingerprint", "candidatePublicationFingerprint"),
)
changed_kind: Literal["embedding", "retrieval"] = Field(
validation_alias=AliasChoices("changed_kind", "changedKind")
)
checkpoint: Literal["queued", "candidate-built", "evaluated", "activated"]
completed_at: datetime | None = Field(default=None, validation_alias=AliasChoices("completed_at", "completedAt"))
created_at: datetime = Field(validation_alias=AliasChoices("created_at", "createdAt"))
error_code: str | None = Field(default=None, validation_alias=AliasChoices("error_code", "errorCode"))
evaluation_summary: dict[str, bool | float | int | str] | None = Field(
default=None, validation_alias=AliasChoices("evaluation_summary", "evaluationSummary")
)
id: str
knowledge_space_id: str = Field(validation_alias=AliasChoices("knowledge_space_id", "knowledgeSpaceId"))
rebuild_scope: Literal[
"clone-publication",
"full-page-index-summary-outline",
"full-vector-space",
] = Field(validation_alias=AliasChoices("rebuild_scope", "rebuildScope"))
run_state: Literal["queued", "running", "succeeded", "failed", "canceled"] = Field(
validation_alias=AliasChoices("run_state", "runState")
)
updated_at: datetime = Field(validation_alias=AliasChoices("updated_at", "updatedAt"))
class KnowledgeFSSettingsUpdateResponse(ResponseModel):
migration: KnowledgeFSProfileMigrationResponse | None = None
settings: KnowledgeFSSettingsResponse
class KnowledgeFSDocumentCreatePayload(BaseModel):
name: str = Field(min_length=1, max_length=255)
text: str = Field(min_length=1, max_length=1_000_000)
idempotency_key: str = Field(min_length=1, max_length=255)
model_config = ConfigDict(extra="forbid")
class KnowledgeFSDocumentResponse(ResponseModel):
id: str
knowledge_space_id: str = Field(validation_alias=AliasChoices("knowledge_space_id", "knowledgeSpaceId"))
filename: str
metadata: dict[str, object]
mime_type: str = Field(validation_alias=AliasChoices("mime_type", "mimeType"))
object_key: str = Field(validation_alias=AliasChoices("object_key", "objectKey"))
parser_status: Literal["pending", "parsed", "failed"] = Field(
validation_alias=AliasChoices("parser_status", "parserStatus")
)
sha256: str
size_bytes: int = Field(ge=0, validation_alias=AliasChoices("size_bytes", "sizeBytes"))
source_id: str | None = Field(default=None, validation_alias=AliasChoices("source_id", "sourceId"))
version: int = Field(ge=1)
created_at: datetime = Field(validation_alias=AliasChoices("created_at", "createdAt"))
updated_at: datetime | None = Field(default=None, validation_alias=AliasChoices("updated_at", "updatedAt"))
class KnowledgeFSDocumentUploadCompilationJobResponse(ResponseModel):
id: str
stage: Literal["queued"]
class KnowledgeFSDocumentUploadLogicalDocumentResponse(ResponseModel):
id: str
revision: int = Field(ge=1)
class KnowledgeFSDocumentUploadAcceptedResponse(ResponseModel):
asset: KnowledgeFSDocumentResponse
asset_status_url: str | None = Field(
default=None, validation_alias=AliasChoices("asset_status_url", "assetStatusUrl")
)
compilation_job: KnowledgeFSDocumentUploadCompilationJobResponse = Field(
validation_alias=AliasChoices("compilation_job", "compilationJob")
)
document_revision: int = Field(ge=1, validation_alias=AliasChoices("document_revision", "documentRevision"))
logical_document: KnowledgeFSDocumentUploadLogicalDocumentResponse = Field(
validation_alias=AliasChoices("logical_document", "logicalDocument")
)
logical_document_id: str = Field(validation_alias=AliasChoices("logical_document_id", "logicalDocumentId"))
status: Literal["accepted"] | None = None
status_url: str = Field(validation_alias=AliasChoices("status_url", "statusUrl"))
class KnowledgeFSStagedUploadResponse(ResponseModel):
id: str
file_name: str = Field(validation_alias=AliasChoices("file_name", "fileName"))
content_type: str = Field(validation_alias=AliasChoices("content_type", "contentType"))
size_bytes: int = Field(gt=0, validation_alias=AliasChoices("size_bytes", "sizeBytes"))
status: Literal["uploaded", "claiming", "claimed", "failed", "aborted", "expired"]
expires_at: datetime = Field(validation_alias=AliasChoices("expires_at", "expiresAt"))
class KnowledgeFSDocumentStagedUploadPayload(BaseModel):
upload_id: str = Field(min_length=1, max_length=255)
model_config = ConfigDict(extra="forbid")
class KnowledgeFSDocumentStagedUploadAcceptedResponse(ResponseModel):
status: Literal["accepted"] = "accepted"
upload_id: str
document_asset_id: str
compilation_job_id: str
class KnowledgeFSDocumentCreateAcceptedResponse(
RootModel[KnowledgeFSDocumentStagedUploadAcceptedResponse | KnowledgeFSDocumentUploadAcceptedResponse]
):
"""Accepted staged or legacy multipart upload, preserving both response shapes."""
class KnowledgeFSDocumentListResponse(ResponseModel):
data: list[KnowledgeFSDocumentResponse] = Field(validation_alias=AliasChoices("data", "items"))
next_cursor: str | None = Field(default=None, validation_alias=AliasChoices("next_cursor", "nextCursor"))
class KnowledgeFSDocumentDownloadDescriptor(ResponseModel):
"""Trusted, internal description of an active or latest failed downloadable revision asset."""
document_id: str
filename: str
mime_type: str
object_key: str
sha256: str
size_bytes: int = Field(ge=0)
class KnowledgeFSDocumentBatchDownloadPayload(BaseModel):
document_ids: list[str] = Field(min_length=1, max_length=100)
model_config = ConfigDict(extra="forbid")
@field_validator("document_ids")
@classmethod
def validate_document_ids(cls, value: list[str]) -> list[str]:
normalized = [document_id.strip() for document_id in value]
if any(not document_id for document_id in normalized):
raise ValueError("document_ids must not contain empty identifiers")
if len(set(normalized)) != len(normalized):
raise ValueError("document_ids must be unique")
return normalized
class KnowledgeFSDocumentOutlineNodeResponse(ResponseModel):
child_node_ids: list[str] = Field(
default_factory=list, validation_alias=AliasChoices("child_node_ids", "childNodeIds")
)
children: list[KnowledgeFSDocumentOutlineNodeResponse] = Field(default_factory=list)
end_offset: int | None = Field(default=None, ge=0, validation_alias=AliasChoices("end_offset", "endOffset"))
end_page: int | None = Field(default=None, ge=1, validation_alias=AliasChoices("end_page", "endPage"))
id: str
level: int = Field(ge=1)
metadata: dict[str, object]
section_path: list[str] = Field(default_factory=list, validation_alias=AliasChoices("section_path", "sectionPath"))
source_element_ids: list[str] = Field(
default_factory=list, validation_alias=AliasChoices("source_element_ids", "sourceElementIds")
)
source_node_ids: list[str] = Field(
default_factory=list, validation_alias=AliasChoices("source_node_ids", "sourceNodeIds")
)
start_offset: int | None = Field(default=None, ge=0, validation_alias=AliasChoices("start_offset", "startOffset"))
start_page: int | None = Field(default=None, ge=1, validation_alias=AliasChoices("start_page", "startPage"))
summary: str | None = None
title: str
title_location: dict[str, object] | None = Field(
default=None, validation_alias=AliasChoices("title_location", "titleLocation")
)
toc_source: str = Field(validation_alias=AliasChoices("toc_source", "tocSource"))
class KnowledgeFSDocumentOutlineResponse(ResponseModel):
artifact_hash: str = Field(validation_alias=AliasChoices("artifact_hash", "artifactHash"))
created_at: datetime = Field(validation_alias=AliasChoices("created_at", "createdAt"))
document_asset_id: str = Field(validation_alias=AliasChoices("document_asset_id", "documentAssetId"))
id: str
knowledge_space_id: str = Field(validation_alias=AliasChoices("knowledge_space_id", "knowledgeSpaceId"))
metadata: dict[str, object]
nodes: list[KnowledgeFSDocumentOutlineNodeResponse]
outline_version: str = Field(validation_alias=AliasChoices("outline_version", "outlineVersion"))
parse_artifact_id: str = Field(validation_alias=AliasChoices("parse_artifact_id", "parseArtifactId"))
updated_at: datetime | None = Field(default=None, validation_alias=AliasChoices("updated_at", "updatedAt"))
version: int = Field(ge=1)
class KnowledgeFSDocumentMultimodalAssetVariant(BaseModel):
content_type: str | None = Field(default=None, validation_alias=AliasChoices("content_type", "contentType"))
object_key: str | None = Field(default=None, validation_alias=AliasChoices("object_key", "objectKey"))
sha256: str | None = None
class KnowledgeFSDocumentMultimodalAssetRef(KnowledgeFSDocumentMultimodalAssetVariant):
variants: dict[str, KnowledgeFSDocumentMultimodalAssetVariant] = Field(default_factory=dict)
class KnowledgeFSDocumentMultimodalItem(BaseModel):
asset_ref: KnowledgeFSDocumentMultimodalAssetRef | None = Field(
default=None, validation_alias=AliasChoices("asset_ref", "assetRef")
)
caption: str | None = None
end_offset: int | None = Field(default=None, ge=0, validation_alias=AliasChoices("end_offset", "endOffset"))
id: str
modality: Literal["code", "image", "page", "table"]
ocr_text: str | None = Field(default=None, validation_alias=AliasChoices("ocr_text", "ocrText"))
page_number: int | None = Field(default=None, ge=1, validation_alias=AliasChoices("page_number", "pageNumber"))
parse_element_id: str = Field(
min_length=1,
max_length=512,
validation_alias=AliasChoices("parse_element_id", "parseElementId"),
)
section_path: list[str] = Field(default_factory=list, validation_alias=AliasChoices("section_path", "sectionPath"))
start_offset: int | None = Field(default=None, ge=0, validation_alias=AliasChoices("start_offset", "startOffset"))
text_preview: str | None = Field(default=None, validation_alias=AliasChoices("text_preview", "textPreview"))
title: str | None = None
class KnowledgeFSDocumentMultimodalManifest(BaseModel):
artifact_hash: str = Field(validation_alias=AliasChoices("artifact_hash", "artifactHash"))
created_at: datetime = Field(validation_alias=AliasChoices("created_at", "createdAt"))
document_asset_id: str = Field(validation_alias=AliasChoices("document_asset_id", "documentAssetId"))
id: str
items: list[KnowledgeFSDocumentMultimodalItem]
knowledge_space_id: str = Field(validation_alias=AliasChoices("knowledge_space_id", "knowledgeSpaceId"))
manifest_version: str = Field(validation_alias=AliasChoices("manifest_version", "manifestVersion"))
updated_at: datetime | None = Field(default=None, validation_alias=AliasChoices("updated_at", "updatedAt"))
version: int = Field(ge=1)
class KnowledgeFSDocumentMultimodalItemResponse(ResponseModel):
asset_url: str | None = None
caption: str | None = None
end_offset: int | None = Field(default=None, ge=0)
id: str
modality: Literal["code", "image", "page", "table"]
ocr_text: str | None = None
page_number: int | None = Field(default=None, ge=1)
parse_element_id: str = Field(min_length=1, max_length=512)
section_path: list[str] = Field(default_factory=list)
start_offset: int | None = Field(default=None, ge=0)
text_preview: str | None = None
thumbnail_url: str | None = None
title: str | None = None
class KnowledgeFSDocumentMultimodalManifestResponse(ResponseModel):
artifact_hash: str
created_at: datetime
document_asset_id: str
id: str
items: list[KnowledgeFSDocumentMultimodalItemResponse]
manifest_version: str
updated_at: datetime | None = None
version: int = Field(ge=1)
class KnowledgeFSDocumentMultimodalAssetQuery(BaseModel):
variant: str | None = Field(default=None, min_length=1, max_length=64, pattern=r"^[A-Za-z0-9._=-]+$")
class KnowledgeFSDocumentRevisionResponse(ResponseModel):
activated_at: datetime | None = Field(default=None, validation_alias=AliasChoices("activated_at", "activatedAt"))
content_hash: str = Field(validation_alias=AliasChoices("content_hash", "contentHash"))
created_at: datetime = Field(validation_alias=AliasChoices("created_at", "createdAt"))
document_asset_id: str = Field(validation_alias=AliasChoices("document_asset_id", "documentAssetId"))
document_asset_version: int = Field(
ge=1, validation_alias=AliasChoices("document_asset_version", "documentAssetVersion")
)
document_id: str = Field(validation_alias=AliasChoices("document_id", "documentId"))
knowledge_space_id: str = Field(validation_alias=AliasChoices("knowledge_space_id", "knowledgeSpaceId"))
mime_type: str = Field(validation_alias=AliasChoices("mime_type", "mimeType"))
revision: int = Field(ge=1)
size_bytes: int = Field(ge=0, validation_alias=AliasChoices("size_bytes", "sizeBytes"))
state: Literal["active", "candidate", "failed", "superseded"]
class KnowledgeFSLogicalDocumentResponse(ResponseModel):
latest_task: KnowledgeFSBackgroundTaskResponse | None = Field(
default=None, validation_alias=AliasChoices("latest_task", "latestTask")
)
active: KnowledgeFSDocumentRevisionResponse | None
active_revision: int | None = Field(
default=None, ge=1, validation_alias=AliasChoices("active_revision", "activeRevision")
)
created_at: datetime = Field(validation_alias=AliasChoices("created_at", "createdAt"))
disabled_at: datetime | None = Field(default=None, validation_alias=AliasChoices("disabled_at", "disabledAt"))
disabled_by_subject_id: str | None = Field(
default=None, validation_alias=AliasChoices("disabled_by_subject_id", "disabledBySubjectId")
)
enabled: bool = True
id: str
knowledge_space_id: str = Field(validation_alias=AliasChoices("knowledge_space_id", "knowledgeSpaceId"))
provider_item_id: str | None = Field(
default=None, validation_alias=AliasChoices("provider_item_id", "providerItemId")
)
row_version: int = Field(ge=0, validation_alias=AliasChoices("row_version", "rowVersion"))
source_id: str | None = Field(default=None, validation_alias=AliasChoices("source_id", "sourceId"))
status: Literal["deleting", "failed", "pending", "ready"]
title: str
updated_at: datetime = Field(validation_alias=AliasChoices("updated_at", "updatedAt"))
user_metadata: dict[str, object] = Field(validation_alias=AliasChoices("user_metadata", "userMetadata"))
class KnowledgeFSLogicalDocumentListResponse(ResponseModel):
data: list[KnowledgeFSLogicalDocumentResponse] = Field(validation_alias=AliasChoices("data", "items"))
next_cursor: str | None = Field(default=None, validation_alias=AliasChoices("next_cursor", "nextCursor"))
class KnowledgeFSDocumentAvailabilityPayload(BaseModel):
enabled: bool
expected_row_version: int = Field(ge=0, alias="expectedRowVersion")
model_config = ConfigDict(extra="forbid", validate_by_alias=True, validate_by_name=True)
class KnowledgeFSBulkDocumentAvailabilityItem(BaseModel):
document_id: str = Field(alias="documentId")
expected_row_version: int = Field(ge=0, alias="expectedRowVersion")
model_config = ConfigDict(extra="forbid", validate_by_alias=True, validate_by_name=True)
class KnowledgeFSBulkDocumentAvailabilityPayload(BaseModel):
documents: list[KnowledgeFSBulkDocumentAvailabilityItem] = Field(min_length=1, max_length=100)
enabled: bool
model_config = ConfigDict(extra="forbid", validate_by_alias=True, validate_by_name=True)
class KnowledgeFSBulkDocumentAvailabilityFailureResponse(ResponseModel):
document_id: str = Field(validation_alias=AliasChoices("document_id", "documentId"))
status: Literal["conflict", "not_found"]
class KnowledgeFSBulkDocumentAvailabilityResponse(ResponseModel):
items: list[KnowledgeFSLogicalDocumentResponse | KnowledgeFSBulkDocumentAvailabilityFailureResponse]
total: int = Field(ge=0)
class KnowledgeFSDocumentRevisionListResponse(ResponseModel):
data: list[KnowledgeFSDocumentRevisionResponse] = Field(validation_alias=AliasChoices("data", "items"))
next_cursor: str | None = Field(default=None, validation_alias=AliasChoices("next_cursor", "nextCursor"))
class KnowledgeFSResolvedDocumentReferenceResponse(ResponseModel):
document_id: str = Field(validation_alias=AliasChoices("document_id", "documentId"))
revision: int = Field(ge=1)
class KnowledgeFSDocumentMetadataPayload(BaseModel):
expected_row_version: int = Field(ge=0, alias="expectedRowVersion")
patch: dict[str, object]
model_config = ConfigDict(extra="forbid", validate_by_alias=True, validate_by_name=True)
class KnowledgeFSMetadataFieldListQuery(BaseModel):
cursor: str | None = Field(default=None, min_length=1, max_length=1_000)
limit: int = Field(default=100, ge=1, le=100)
model_config = ConfigDict(extra="forbid")
class KnowledgeFSMetadataFieldCreatePayload(BaseModel):
name: str = Field(min_length=1, max_length=255)
type: Literal["string", "number", "time"]
model_config = ConfigDict(extra="forbid")
class KnowledgeFSMetadataFieldUpdatePayload(BaseModel):
expected_row_version: int = Field(ge=0, alias="expectedRowVersion")
name: str = Field(min_length=1, max_length=255)
model_config = ConfigDict(extra="forbid", validate_by_alias=True, validate_by_name=True)
class KnowledgeFSMetadataFieldDeleteQuery(BaseModel):
expected_row_version: int = Field(ge=0, alias="expectedRowVersion")
model_config = ConfigDict(extra="forbid", validate_by_alias=True, validate_by_name=True)
class KnowledgeFSMetadataFieldDeleteResponse(ResponseModel):
deleted: Literal[True]
class KnowledgeFSDocumentChunkResponse(ResponseModel):
created_at: datetime = Field(validation_alias=AliasChoices("created_at", "createdAt"))
document_id: str = Field(validation_alias=AliasChoices("document_id", "documentId"))
document_revision: int = Field(ge=1, validation_alias=AliasChoices("document_revision", "documentRevision"))
end_offset: int | None = Field(default=None, ge=0, validation_alias=AliasChoices("end_offset", "endOffset"))
enabled: bool
id: str
kind: Literal["chunk", "section", "table", "image", "summary"] = "chunk"
knowledge_space_id: str = Field(validation_alias=AliasChoices("knowledge_space_id", "knowledgeSpaceId"))
ordinal: int = Field(ge=0)
parent_chunk_id: str | None = Field(default=None, validation_alias=AliasChoices("parent_chunk_id", "parentChunkId"))
parse_element_ids: list[str] = Field(validation_alias=AliasChoices("parse_element_ids", "parseElementIds"))
section_path: list[str] = Field(default_factory=list, validation_alias=AliasChoices("section_path", "sectionPath"))
start_offset: int | None = Field(default=None, ge=0, validation_alias=AliasChoices("start_offset", "startOffset"))
text: str
token_count: int = Field(ge=0, validation_alias=AliasChoices("token_count", "tokenCount"))
user_metadata: dict[str, object] = Field(validation_alias=AliasChoices("user_metadata", "userMetadata"))
class KnowledgeFSDocumentChunkListQuery(KnowledgeFSCursorQuery):
query: str | None = Field(default=None, min_length=1, max_length=512)
class KnowledgeFSDocumentChunkListResponse(ResponseModel):
data: list[KnowledgeFSDocumentChunkResponse] = Field(validation_alias=AliasChoices("data", "items"))
next_cursor: str | None = Field(default=None, validation_alias=AliasChoices("next_cursor", "nextCursor"))
class KnowledgeFSDocumentDeletePayload(BaseModel):
expected_revision: int = Field(ge=1, alias="expectedRevision")
model_config = ConfigDict(extra="forbid", validate_by_alias=True, validate_by_name=True)
class KnowledgeFSLogicalDocumentDeletePayload(BaseModel):
expected_revision: int = Field(ge=0, alias="expectedRevision")
model_config = ConfigDict(extra="forbid", validate_by_alias=True, validate_by_name=True)
class KnowledgeFSBulkLogicalDocumentDeleteItemPayload(KnowledgeFSLogicalDocumentDeletePayload):
document_id: str = Field(min_length=1, alias="documentId")
class KnowledgeFSBulkLogicalDocumentDeletePayload(BaseModel):
documents: list[KnowledgeFSBulkLogicalDocumentDeleteItemPayload] = Field(min_length=1, max_length=100)
model_config = ConfigDict(extra="forbid", validate_by_alias=True, validate_by_name=True)
class KnowledgeFSBulkDocumentDeleteItemPayload(KnowledgeFSDocumentDeletePayload):
document_id: str = Field(min_length=1, alias="documentId")
class KnowledgeFSBulkDocumentDeletePayload(BaseModel):
documents: list[KnowledgeFSBulkDocumentDeleteItemPayload] = Field(min_length=1, max_length=100)
model_config = ConfigDict(extra="forbid", validate_by_alias=True, validate_by_name=True)
class KnowledgeFSDocumentReindexPayload(BaseModel):
all: bool | None = None
document_ids: list[str] | None = Field(default=None, min_length=1, max_length=100, alias="documentIds")
model_config = ConfigDict(extra="forbid", validate_by_alias=True, validate_by_name=True)
@model_validator(mode="after")
def validate_target(self) -> KnowledgeFSDocumentReindexPayload:
if bool(self.all) == bool(self.document_ids):
raise ValueError("Exactly one of all=true or document_ids is required")
return self
class KnowledgeFSDurableDeletionErrorResponse(ResponseModel):
code: str
message: str
retryable: bool
class KnowledgeFSDurableDeletionProgressResponse(ResponseModel):
completed_items: int = Field(ge=0, validation_alias=AliasChoices("completed_items", "completedItems"))
current_item_kind: str | None = Field(
default=None, validation_alias=AliasChoices("current_item_kind", "currentItemKind")
)
total_items: int | None = Field(default=None, ge=0, validation_alias=AliasChoices("total_items", "totalItems"))
class KnowledgeFSDurableDeletionJobResponse(ResponseModel):
checkpoint: Literal[
"completed", "deleting_derived_data", "deleting_objects", "deleting_primary_data", "quiescing", "requested"
]
completed_at: datetime | None = Field(default=None, validation_alias=AliasChoices("completed_at", "completedAt"))
created_at: datetime = Field(validation_alias=AliasChoices("created_at", "createdAt"))
error: KnowledgeFSDurableDeletionErrorResponse | None = None
id: str
knowledge_space_id: str = Field(validation_alias=AliasChoices("knowledge_space_id", "knowledgeSpaceId"))
mode: Literal["cascade", "keep"] | None = None
progress: KnowledgeFSDurableDeletionProgressResponse | None = None
retry_at: datetime | None = Field(default=None, validation_alias=AliasChoices("retry_at", "retryAt"))
run_state: Literal["canceled", "completed", "dispatch_pending", "failed", "queued", "retry_wait", "running"] = (
Field(validation_alias=AliasChoices("run_state", "runState"))
)
target_id: str = Field(validation_alias=AliasChoices("target_id", "targetId"))
target_type: Literal["document", "knowledge_space", "logical_document", "source"] = Field(
validation_alias=AliasChoices("target_type", "targetType")
)
updated_at: datetime = Field(validation_alias=AliasChoices("updated_at", "updatedAt"))
class KnowledgeFSDurableDeletionAcceptedResponse(ResponseModel):
document_title: str | None = Field(default=None, validation_alias=AliasChoices("document_title", "documentTitle"))
job: KnowledgeFSDurableDeletionJobResponse
status_url: str = Field(validation_alias=AliasChoices("status_url", "statusUrl"))
class KnowledgeFSBulkDeletionAcceptedItemResponse(ResponseModel):
document_id: str = Field(validation_alias=AliasChoices("document_id", "documentId"))
document_title: str | None = Field(default=None, validation_alias=AliasChoices("document_title", "documentTitle"))
job: KnowledgeFSDurableDeletionJobResponse
status_url: str = Field(validation_alias=AliasChoices("status_url", "statusUrl"))
class KnowledgeFSBulkDeletionResultResponse(ResponseModel):
document_id: str = Field(validation_alias=AliasChoices("document_id", "documentId"))
status: Literal["pending", "accepted", "rejected"]
job: KnowledgeFSDurableDeletionJobResponse | None = None
status_url: str | None = Field(default=None, validation_alias=AliasChoices("status_url", "statusUrl"))
error: KnowledgeFSDurableDeletionErrorResponse | None = None
class KnowledgeFSBulkDeletionAcceptedResponse(ResponseModel):
batch_id: str | None = Field(default=None, validation_alias=AliasChoices("batch_id", "batchId"))
status_url: str | None = Field(default=None, validation_alias=AliasChoices("status_url", "statusUrl"))
results: list[KnowledgeFSBulkDeletionResultResponse] = Field(default_factory=list)
items: list[KnowledgeFSBulkDeletionAcceptedItemResponse]
total: int = Field(ge=1)
class KnowledgeFSDocumentCompilationJobResponse(ResponseModel):
failure: KnowledgeFSPublicFailureResponse | None = None
base_head_revision: int | None = Field(
default=None, ge=0, validation_alias=AliasChoices("base_head_revision", "baseHeadRevision")
)
candidate_fingerprint: str | None = Field(
default=None, validation_alias=AliasChoices("candidate_fingerprint", "candidateFingerprint")
)
candidate_publication_id: str | None = Field(
default=None, validation_alias=AliasChoices("candidate_publication_id", "candidatePublicationId")
)
completed_at: float | None = Field(default=None, validation_alias=AliasChoices("completed_at", "completedAt"))
created_at: float = Field(validation_alias=AliasChoices("created_at", "createdAt"))
document_asset_id: str = Field(validation_alias=AliasChoices("document_asset_id", "documentAssetId"))
error: str | None = None
execution_attempts: int | None = Field(
default=None, ge=0, validation_alias=AliasChoices("execution_attempts", "executionAttempts")
)
id: str
knowledge_space_id: str = Field(validation_alias=AliasChoices("knowledge_space_id", "knowledgeSpaceId"))
max_execution_attempts: int | None = Field(
default=None, ge=1, validation_alias=AliasChoices("max_execution_attempts", "maxExecutionAttempts")
)
run_state: str | None = Field(default=None, validation_alias=AliasChoices("run_state", "runState"))
stage: Literal[
"canceled",
"failed",
"nodes_generated",
"outline_built",
"parsed",
"projection_built",
"published",
"queued",
"smoke_eval_passed",
]
updated_at: float = Field(validation_alias=AliasChoices("updated_at", "updatedAt"))
version: int = Field(ge=1)
class KnowledgeFSBulkJobFailureResponse(ResponseModel):
document_id: str = Field(validation_alias=AliasChoices("document_id", "documentId"))
document_title: str | None = Field(default=None, validation_alias=AliasChoices("document_title", "documentTitle"))
job_id: str | None = Field(default=None, validation_alias=AliasChoices("job_id", "jobId"))
error_code: str = Field(validation_alias=AliasChoices("error_code", "errorCode"))
error_message: str = Field(validation_alias=AliasChoices("error_message", "errorMessage"))
failure: KnowledgeFSPublicFailureResponse | None = None
class KnowledgeFSBulkJobResponse(ResponseModel):
failures: list[KnowledgeFSBulkJobFailureResponse] = Field(default_factory=list)
canceled_items: int = Field(ge=0, validation_alias=AliasChoices("canceled_items", "canceledItems"))
completed_items: int = Field(ge=0, validation_alias=AliasChoices("completed_items", "completedItems"))
created_at: datetime = Field(validation_alias=AliasChoices("created_at", "createdAt"))
failed_item_ids: list[str] = Field(validation_alias=AliasChoices("failed_item_ids", "failedItemIds"))
failed_items: int = Field(ge=0, validation_alias=AliasChoices("failed_items", "failedItems"))
id: str
knowledge_space_id: str = Field(validation_alias=AliasChoices("knowledge_space_id", "knowledgeSpaceId"))
status: Literal["canceled", "completed", "failed", "running"]
total_items: int = Field(ge=0, validation_alias=AliasChoices("total_items", "totalItems"))
type: Literal["document_delete", "document_reindex", "document_upload"]
updated_at: datetime = Field(validation_alias=AliasChoices("updated_at", "updatedAt"))
class KnowledgeFSBackgroundTaskFailureResponse(ResponseModel):
document_id: str = Field(validation_alias=AliasChoices("document_id", "documentId"))
document_title: str | None = Field(default=None, validation_alias=AliasChoices("document_title", "documentTitle"))
error_code: str = Field(validation_alias=AliasChoices("error_code", "errorCode"))
error_message: str = Field(validation_alias=AliasChoices("error_message", "errorMessage"))
failure: KnowledgeFSPublicFailureResponse
job_id: str | None = Field(default=None, validation_alias=AliasChoices("job_id", "jobId"))
class KnowledgeFSSemanticEnrichmentResponse(ResponseModel):
error_code: str | None = Field(default=None, validation_alias=AliasChoices("error_code", "errorCode"))
error_message: str | None = Field(default=None, validation_alias=AliasChoices("error_message", "errorMessage"))
failure: KnowledgeFSPublicFailureResponse | None = None
nodes_completed: int = Field(ge=0, validation_alias=AliasChoices("nodes_completed", "nodesCompleted"))
nodes_total: int | None = Field(default=None, ge=0, validation_alias=AliasChoices("nodes_total", "nodesTotal"))
provider_calls: int | None = Field(
default=None, ge=0, validation_alias=AliasChoices("provider_calls", "providerCalls")
)
provider_calls_maximum: int | None = Field(
default=None, ge=0, validation_alias=AliasChoices("provider_calls_maximum", "providerCallsMaximum")
)
state: Literal["not_scheduled", "pending", "running", "ready", "failed", "disabled"]
updated_at: datetime | None = Field(default=None, validation_alias=AliasChoices("updated_at", "updatedAt"))
class KnowledgeFSBackgroundTaskResponse(ResponseModel):
can_cancel: bool = Field(validation_alias=AliasChoices("can_cancel", "canCancel"))
can_retry: bool = Field(validation_alias=AliasChoices("can_retry", "canRetry"))
completed_at: datetime | None = Field(default=None, validation_alias=AliasChoices("completed_at", "completedAt"))
created_at: datetime = Field(validation_alias=AliasChoices("created_at", "createdAt"))
document_id: str | None = Field(default=None, validation_alias=AliasChoices("document_id", "documentId"))
document_title: str | None = Field(default=None, validation_alias=AliasChoices("document_title", "documentTitle"))
document_revision: int | None = Field(
default=None, ge=1, validation_alias=AliasChoices("document_revision", "documentRevision")
)
error_code: str | None = Field(default=None, validation_alias=AliasChoices("error_code", "errorCode"))
error_message: str | None = Field(default=None, validation_alias=AliasChoices("error_message", "errorMessage"))
failure: KnowledgeFSPublicFailureResponse | None = None
failures: list[KnowledgeFSBackgroundTaskFailureResponse] | None = None
id: str
knowledge_space_id: str = Field(validation_alias=AliasChoices("knowledge_space_id", "knowledgeSpaceId"))
operation: Literal[
"document_delete",
"document_processing",
"document_reindex",
"document_upload",
"source_bulk",
"source_crawl_import",
"source_crawl_preview",
"source_online_document_import",
"source_online_drive_import",
"source_sync",
]
progress_completed: int = Field(ge=0, validation_alias=AliasChoices("progress_completed", "progressCompleted"))
progress_failed: int = Field(ge=0, validation_alias=AliasChoices("progress_failed", "progressFailed"))
progress_percent: int = Field(ge=0, le=100, validation_alias=AliasChoices("progress_percent", "progressPercent"))
progress_total: int = Field(ge=0, validation_alias=AliasChoices("progress_total", "progressTotal"))
semantic_enrichment: KnowledgeFSSemanticEnrichmentResponse | None = Field(
default=None, validation_alias=AliasChoices("semantic_enrichment", "semanticEnrichment")
)
source_id: str | None = Field(default=None, validation_alias=AliasChoices("source_id", "sourceId"))
source_title: str | None = Field(default=None, validation_alias=AliasChoices("source_title", "sourceTitle"))
state: Literal["canceled", "completed", "failed", "queued", "running"]
task_kind: Literal["document", "document_bulk", "source"] = Field(
validation_alias=AliasChoices("task_kind", "taskKind")
)
updated_at: datetime = Field(validation_alias=AliasChoices("updated_at", "updatedAt"))
class KnowledgeFSBackgroundTaskListResponse(ResponseModel):
data: list[KnowledgeFSBackgroundTaskResponse] = Field(validation_alias=AliasChoices("data", "items"))
next_cursor: str | None = Field(default=None, validation_alias=AliasChoices("next_cursor", "nextCursor"))
class KnowledgeFSDocumentReindexItemResponse(ResponseModel):
asset: KnowledgeFSDocumentResponse | None = None
compilation_job: dict[str, object] | None = Field(
default=None, validation_alias=AliasChoices("compilation_job", "compilationJob")
)
document_id: str | None = Field(default=None, validation_alias=AliasChoices("document_id", "documentId"))
status: Literal["disabled", "not_found", "queued", "failed", "pending"]
code: str | None = None
error: str | None = None
status_url: str | None = Field(default=None, validation_alias=AliasChoices("status_url", "statusUrl"))
class KnowledgeFSDocumentReindexResponse(ResponseModel):
bulk_job_id: str = Field(validation_alias=AliasChoices("bulk_job_id", "bulkJobId"))
items: list[KnowledgeFSDocumentReindexItemResponse]
total: int = Field(ge=0)
class KnowledgeFSSourceCreatePayload(BaseModel):
connection_id: str | None = Field(default=None, alias="connectionId")
credentials: dict[str, object] | None = None
metadata: dict[str, object] = Field(default_factory=dict)
name: str = Field(min_length=1, max_length=200)
permission_scope: list[str] = Field(default_factory=list, max_length=1_000, alias="permissionScope")
status: Literal["active", "disabled", "error", "syncing"] | None = None
type: Literal["connector", "object-storage", "upload", "web"]
uri: str = Field(min_length=1, max_length=4_096)
model_config = ConfigDict(extra="forbid", validate_by_alias=True, validate_by_name=True)
@model_validator(mode="after")
def validate_credential_binding(self) -> KnowledgeFSSourceCreatePayload:
if self.connection_id is not None and self.credentials is not None:
raise ValueError("connection_id and credentials are mutually exclusive")
return self
class KnowledgeFSSourceSyncPolicyResponse(ResponseModel):
created_at: datetime = Field(validation_alias=AliasChoices("created_at", "createdAt"))
custom_interval_seconds: int | None = Field(
default=None, validation_alias=AliasChoices("custom_interval_seconds", "customIntervalSeconds")
)
enabled: bool
expected_source_version: int = Field(
ge=1, validation_alias=AliasChoices("expected_source_version", "expectedSourceVersion")
)
id: str
knowledge_space_id: str = Field(validation_alias=AliasChoices("knowledge_space_id", "knowledgeSpaceId"))
mode: Literal["manual", "interval", "custom"]
next_run_at: datetime | None = Field(default=None, validation_alias=AliasChoices("next_run_at", "nextRunAt"))
revision: int = Field(ge=1)
source_id: str = Field(validation_alias=AliasChoices("source_id", "sourceId"))
updated_at: datetime = Field(validation_alias=AliasChoices("updated_at", "updatedAt"))
class KnowledgeFSSourceResponse(ResponseModel):
sync_workflow: KnowledgeFSSourceWorkflowResponse | None = Field(
default=None, validation_alias=AliasChoices("sync_workflow", "syncWorkflow")
)
id: str
connection_id: str | None = Field(default=None, validation_alias=AliasChoices("connection_id", "connectionId"))
credential_configured: bool | None = Field(
default=None, validation_alias=AliasChoices("credential_configured", "credentialConfigured")
)
created_at: datetime = Field(validation_alias=AliasChoices("created_at", "createdAt"))
knowledge_space_id: str = Field(validation_alias=AliasChoices("knowledge_space_id", "knowledgeSpaceId"))
last_synced_at: datetime | None = Field(
default=None, validation_alias=AliasChoices("last_synced_at", "lastSyncedAt")
)
metadata: dict[str, object]
name: str
permission_scope: list[str] = Field(validation_alias=AliasChoices("permission_scope", "permissionScope"))
status: Literal["active", "disabled", "error", "syncing"]
sync_policy: KnowledgeFSSourceSyncPolicyResponse | None = Field(
default=None, validation_alias=AliasChoices("sync_policy", "syncPolicy")
)
type: Literal["connector", "object-storage", "upload", "web"]
updated_at: datetime = Field(validation_alias=AliasChoices("updated_at", "updatedAt"))
uri: str
version: int = Field(ge=1)
class KnowledgeFSSourceListResponse(ResponseModel):
data: list[KnowledgeFSSourceResponse] = Field(validation_alias=AliasChoices("data", "items"))
next_cursor: str | None = Field(default=None, validation_alias=AliasChoices("next_cursor", "nextCursor"))
class KnowledgeFSSourceEditWebsiteSelectionPayload(BaseModel):
kind: Literal["website_crawl"]
source_urls: list[str] = Field(min_length=1, max_length=200, alias="sourceUrls")
model_config = ConfigDict(extra="forbid", validate_by_alias=True, validate_by_name=True)
class KnowledgeFSSourceEditOnlineDocumentSelectionPayload(BaseModel):
items: list[KnowledgeFSOnlineDocumentWorkflowImportItemPayload] = Field(min_length=1, max_length=200)
kind: Literal["online_document"]
model_config = ConfigDict(extra="forbid")
class KnowledgeFSSourceEditOnlineDriveSelectionPayload(BaseModel):
items: list[KnowledgeFSOnlineDriveWorkflowImportItemPayload] = Field(min_length=1, max_length=200)
kind: Literal["online_drive"]
model_config = ConfigDict(extra="forbid")
KnowledgeFSSourceEditSelectionPayload = Annotated[
KnowledgeFSSourceEditWebsiteSelectionPayload
| KnowledgeFSSourceEditOnlineDocumentSelectionPayload
| KnowledgeFSSourceEditOnlineDriveSelectionPayload,
Field(discriminator="kind"),
]
class KnowledgeFSSyncPolicyFields(BaseModel):
"""Sync policy fields and rules shared by every endpoint that accepts a sync policy."""
custom_interval_seconds: int | None = Field(default=None, ge=3_600, le=2_592_000, alias="customIntervalSeconds")
enabled: bool
mode: Literal["manual", "interval", "custom"]
model_config = ConfigDict(extra="forbid", validate_by_alias=True, validate_by_name=True)
@model_validator(mode="after")
def validate_custom_interval(self) -> Self:
if self.mode == "custom" and self.custom_interval_seconds is None:
raise ValueError("customIntervalSeconds is required for a custom sync policy")
if self.mode != "custom" and self.custom_interval_seconds is not None:
raise ValueError("customIntervalSeconds is only valid for a custom sync policy")
return self
class KnowledgeFSSourceEditSyncPolicyPayload(KnowledgeFSSyncPolicyFields):
pass
class KnowledgeFSSourceUpdatePayload(BaseModel):
expected_version: int | None = Field(default=None, ge=1, alias="expectedVersion")
metadata: dict[str, object] | None = None
name: str | None = Field(default=None, min_length=1, max_length=200)
provider_parameters: dict[str, bool | FiniteFloat | str] | None = Field(
default=None, max_length=50, alias="providerParameters"
)
selection: KnowledgeFSSourceEditSelectionPayload | None = None
sync_after_update: bool | None = Field(default=None, alias="syncAfterUpdate")
sync_policy: KnowledgeFSSourceEditSyncPolicyPayload | None = Field(default=None, alias="syncPolicy")
status: Literal["active", "disabled", "error", "syncing"] | None = None
uri: str | None = Field(default=None, min_length=1, max_length=4_096)
model_config = ConfigDict(extra="forbid", validate_by_alias=True, validate_by_name=True)
@field_validator("provider_parameters")
@classmethod
def validate_provider_parameter_keys(
cls, value: dict[str, bool | float | str] | None
) -> dict[str, bool | float | str] | None:
if value is not None and any(not key or len(key) > 255 for key in value):
raise ValueError("Provider parameter keys must contain between 1 and 255 characters")
return value
@model_validator(mode="after")
def validate_update_present(self) -> KnowledgeFSSourceUpdatePayload:
if self.metadata is not None and "parameters" in self.metadata:
raise ValueError("Use providerParameters to update provider parameters")
if self.selection is not None and self.sync_policy is None:
raise ValueError("syncPolicy is required when selection is provided")
if all(
value is None
for value in (
self.metadata,
self.name,
self.provider_parameters,
self.selection,
self.status,
self.sync_policy,
self.uri,
)
):
raise ValueError("At least one source update is required")
return self
class KnowledgeFSAtomicSourceUpdatePayload(KnowledgeFSSourceUpdatePayload):
"""Internal command carrying policy CAS alongside the source configuration CAS."""
expected_policy_revision: int | None = Field(default=None, ge=0, alias="expectedPolicyRevision")
class KnowledgeFSSourceDeletePayload(BaseModel):
expected_revision: int = Field(ge=1, alias="expectedRevision")
model_config = ConfigDict(extra="forbid", validate_by_alias=True, validate_by_name=True)
class KnowledgeFSSourceDeleteQuery(BaseModel):
documents: Literal["cascade", "keep"] = "cascade"
model_config = ConfigDict(extra="forbid")
class KnowledgeFSSourceCredentialTestResponse(ResponseModel):
code: KnowledgeFSPublicErrorCode | None = None
error: str | None = None
failure: KnowledgeFSPublicFailureResponse | None = None
valid: bool
@model_validator(mode="after")
def normalize_public_failure(self) -> KnowledgeFSSourceCredentialTestResponse:
if not self.valid and self.failure is not None:
self.code = self.failure.code
self.error = self.failure.message
else:
self.code = None
self.error = None
self.failure = None
return self
class KnowledgeFSSourceWorkflowResponse(ResponseModel):
canceled_at: datetime | None = Field(default=None, validation_alias=AliasChoices("canceled_at", "canceledAt"))
checkpoint: str
completed_at: datetime | None = Field(default=None, validation_alias=AliasChoices("completed_at", "completedAt"))
created_at: datetime = Field(validation_alias=AliasChoices("created_at", "createdAt"))
cursor: str | None = None
execution_attempts: int = Field(ge=0, validation_alias=AliasChoices("execution_attempts", "executionAttempts"))
failure: KnowledgeFSPublicFailureResponse | None = None
id: str
knowledge_space_id: str = Field(validation_alias=AliasChoices("knowledge_space_id", "knowledgeSpaceId"))
kind: str
last_error_code: KnowledgeFSPublicErrorCode | None = Field(
default=None, validation_alias=AliasChoices("last_error_code", "lastErrorCode")
)
max_execution_attempts: int = Field(
ge=1, validation_alias=AliasChoices("max_execution_attempts", "maxExecutionAttempts")
)
progress_completed: int = Field(ge=0, validation_alias=AliasChoices("progress_completed", "progressCompleted"))
progress_failed: int = Field(ge=0, validation_alias=AliasChoices("progress_failed", "progressFailed"))
progress_skipped: int = Field(ge=0, validation_alias=AliasChoices("progress_skipped", "progressSkipped"))
progress_total: int | None = Field(
default=None, ge=0, validation_alias=AliasChoices("progress_total", "progressTotal")
)
source_id: str | None = Field(default=None, validation_alias=AliasChoices("source_id", "sourceId"))
state: str
updated_at: datetime = Field(validation_alias=AliasChoices("updated_at", "updatedAt"))
@model_validator(mode="after")
def normalize_public_failure(self) -> KnowledgeFSSourceWorkflowResponse:
if self.state == "failed" and self.failure is not None:
self.last_error_code = self.failure.code
else:
self.failure = None
self.last_error_code = None
return self
class KnowledgeFSSourceImportConfigurationPayload(BaseModel):
expected_version: int = Field(ge=1, alias="expectedVersion")
metadata: dict[str, object] | None = None
name: str | None = Field(default=None, min_length=1, max_length=200)
provider_parameters: dict[str, bool | FiniteFloat | str] | None = Field(
default=None,
max_length=50,
alias="providerParameters",
)
status: Literal["active", "disabled", "error", "syncing"] | None = None
uri: str | None = Field(default=None, min_length=1, max_length=4_096)
model_config = ConfigDict(extra="forbid", validate_by_alias=True, validate_by_name=True)
class _KnowledgeFSAtomicSourceImportFields(BaseModel):
source_update: KnowledgeFSSourceImportConfigurationPayload | None = Field(default=None, alias="sourceUpdate")
desired_sync_policy: KnowledgeFSSourceEditSyncPolicyPayload | None = Field(default=None, alias="desiredSyncPolicy")
model_config = ConfigDict(extra="forbid", validate_by_alias=True, validate_by_name=True)
@model_validator(mode="after")
def validate_atomic_fields(self) -> _KnowledgeFSAtomicSourceImportFields:
if (self.source_update is None) != (self.desired_sync_policy is None):
raise ValueError("sourceUpdate and desiredSyncPolicy must be provided together")
return self
class KnowledgeFSOnlineDocumentWorkflowImportPayload(_KnowledgeFSAtomicSourceImportFields):
items: list[KnowledgeFSOnlineDocumentWorkflowImportItemPayload] = Field(min_length=1, max_length=200)
kind: Literal["online-document-import"]
model_config = ConfigDict(extra="forbid")
class KnowledgeFSOnlineDriveWorkflowImportPayload(_KnowledgeFSAtomicSourceImportFields):
items: list[KnowledgeFSOnlineDriveWorkflowImportItemPayload] = Field(min_length=1, max_length=200)
kind: Literal["online-drive-import"]
model_config = ConfigDict(extra="forbid")
class KnowledgeFSSourceWorkflowImportPayload(
RootModel[
Annotated[
KnowledgeFSOnlineDocumentWorkflowImportPayload | KnowledgeFSOnlineDriveWorkflowImportPayload,
Field(discriminator="kind"),
]
]
):
pass
class KnowledgeFSSourceProviderFieldResponse(ResponseModel):
description: str | None = None
format: Literal["password", "uri"] | None = None
name: str
required: bool
secret: bool
type: Literal["boolean", "integer", "string"]
class KnowledgeFSSourceProviderResponse(ResponseModel):
auth_kinds: list[Literal["api-key", "endpoint", "oauth2"]] = Field(
validation_alias=AliasChoices("auth_kinds", "authKinds")
)
available: bool
capabilities: list[Literal["website-crawl", "online-document", "online-drive"]]
configuration: list[KnowledgeFSSourceProviderFieldResponse]
display_name: str = Field(validation_alias=AliasChoices("display_name", "displayName"))
id: str
unavailable_reason: str | None = Field(
default=None, validation_alias=AliasChoices("unavailable_reason", "unavailableReason")
)
class KnowledgeFSSourceProviderListResponse(ResponseModel):
data: list[KnowledgeFSSourceProviderResponse] = Field(validation_alias=AliasChoices("data", "items"))
class KnowledgeFSSourceConnectionCreatePayload(BaseModel):
auth_kind: Literal["api-key", "endpoint"] = Field(alias="authKind")
configuration: dict[str, bool | int | str] = Field(default_factory=dict)
credentials: dict[str, object]
name: str = Field(min_length=1, max_length=160)
provider_id: str = Field(min_length=1, max_length=128, alias="providerId")
model_config = ConfigDict(extra="forbid", validate_by_alias=True, validate_by_name=True)
class KnowledgeFSSourceConnectionResponse(ResponseModel):
auth_kind: Literal["api-key", "endpoint", "oauth2"] = Field(validation_alias=AliasChoices("auth_kind", "authKind"))
configuration: dict[str, bool | int | str]
created_at: datetime = Field(validation_alias=AliasChoices("created_at", "createdAt"))
error_code: str | None = Field(default=None, validation_alias=AliasChoices("error_code", "errorCode"))
expires_at: datetime | None = Field(default=None, validation_alias=AliasChoices("expires_at", "expiresAt"))
id: str
knowledge_space_id: str = Field(validation_alias=AliasChoices("knowledge_space_id", "knowledgeSpaceId"))
name: str
provider_id: str = Field(validation_alias=AliasChoices("provider_id", "providerId"))
scopes: list[str]
status: Literal["provisioning", "active", "expired", "error", "revoked"]
updated_at: datetime = Field(validation_alias=AliasChoices("updated_at", "updatedAt"))
version: int = Field(ge=1)
class KnowledgeFSSourceConnectionListQuery(BaseModel):
cursor: str | None = Field(default=None, min_length=1, max_length=4_096)
limit: int = Field(default=50, ge=1, le=200)
model_config = ConfigDict(extra="forbid")
class KnowledgeFSSourceConnectionListResponse(ResponseModel):
data: list[KnowledgeFSSourceConnectionResponse] = Field(validation_alias=AliasChoices("data", "items"))
next_cursor: str | None = Field(default=None, validation_alias=AliasChoices("next_cursor", "nextCursor"))
class KnowledgeFSSourceConnectionRefreshPayload(BaseModel):
expected_version: int = Field(ge=1, alias="expectedVersion")
model_config = ConfigDict(extra="forbid", validate_by_alias=True, validate_by_name=True)
class KnowledgeFSSourceSyncPolicyPayload(KnowledgeFSSyncPolicyFields):
expected_revision: int = Field(ge=0, alias="expectedRevision")
expected_source_version: int = Field(ge=1, alias="expectedSourceVersion")
class KnowledgeFSSourceWorkflowCancelPayload(BaseModel):
reason: str | None = Field(default=None, max_length=1_000)
model_config = ConfigDict(extra="forbid")
class KnowledgeFSCrawlPreviewPageResponse(ResponseModel):
description: str | None = None
etag: str | None = None
page_id: str = Field(validation_alias=AliasChoices("page_id", "pageId"))
source_url: str = Field(validation_alias=AliasChoices("source_url", "sourceUrl"))
title: str | None = None
class KnowledgeFSCrawlPreviewPageListQuery(BaseModel):
cursor: str | None = Field(default=None, min_length=1, max_length=4_096)
limit: int = Field(default=50, ge=1, le=200)
model_config = ConfigDict(extra="forbid")
class KnowledgeFSCrawlPreviewPageListResponse(ResponseModel):
data: list[KnowledgeFSCrawlPreviewPageResponse] = Field(validation_alias=AliasChoices("data", "items"))
next_cursor: str | None = Field(default=None, validation_alias=AliasChoices("next_cursor", "nextCursor"))
class KnowledgeFSCrawlPreviewSelectionPayload(BaseModel):
page_ids: list[str] = Field(min_length=1, max_length=200, alias="pageIds")
model_config = ConfigDict(extra="forbid", validate_by_alias=True, validate_by_name=True)
class KnowledgeFSDeferredSyncPolicyPayload(KnowledgeFSSyncPolicyFields):
pass
class KnowledgeFSAsyncCrawlPreviewImportPayload(BaseModel):
kind: Literal["crawl-preview-selection"]
page_ids: list[str] = Field(min_length=1, max_length=200, alias="pageIds")
preview_workflow_id: str = Field(min_length=1, max_length=255, alias="previewWorkflowId")
sync_policy: KnowledgeFSDeferredSyncPolicyPayload = Field(alias="syncPolicy")
model_config = ConfigDict(extra="forbid", validate_by_alias=True, validate_by_name=True)
class KnowledgeFSAsyncWebsiteCrawlImportPayload(BaseModel):
kind: Literal["website-crawl-import"]
source_urls: list[str] = Field(min_length=1, max_length=200, alias="sourceUrls")
sync_policy: KnowledgeFSDeferredSyncPolicyPayload = Field(alias="syncPolicy")
model_config = ConfigDict(extra="forbid", validate_by_alias=True, validate_by_name=True)
class KnowledgeFSAsyncOnlineDocumentImportPayload(BaseModel):
items: list[KnowledgeFSOnlineDocumentWorkflowImportItemPayload] = Field(min_length=1, max_length=200)
kind: Literal["online-document-import"]
sync_policy: KnowledgeFSDeferredSyncPolicyPayload = Field(alias="syncPolicy")
model_config = ConfigDict(extra="forbid", validate_by_alias=True, validate_by_name=True)
class KnowledgeFSAsyncOnlineDriveImportPayload(BaseModel):
items: list[KnowledgeFSOnlineDriveWorkflowImportItemPayload] = Field(min_length=1, max_length=200)
kind: Literal["online-drive-import"]
sync_policy: KnowledgeFSDeferredSyncPolicyPayload = Field(alias="syncPolicy")
model_config = ConfigDict(extra="forbid", validate_by_alias=True, validate_by_name=True)
KnowledgeFSAsyncSourceImport = Annotated[
KnowledgeFSAsyncCrawlPreviewImportPayload
| KnowledgeFSAsyncWebsiteCrawlImportPayload
| KnowledgeFSAsyncOnlineDocumentImportPayload
| KnowledgeFSAsyncOnlineDriveImportPayload,
Field(discriminator="kind"),
]
class KnowledgeFSAsyncSourceImportPayload(RootModel[KnowledgeFSAsyncSourceImport]):
pass
class KnowledgeFSCrawlImportPagePayload(BaseModel):
content: str = Field(max_length=10_000_000)
description: str | None = None
source_url: str = Field(min_length=1, max_length=4_096, alias="sourceUrl")
title: str | None = Field(default=None, max_length=500)
model_config = ConfigDict(extra="forbid", validate_by_alias=True, validate_by_name=True)
class KnowledgeFSCrawlImportPayload(_KnowledgeFSAtomicSourceImportFields):
source_urls: list[str] = Field(min_length=1, max_length=200, alias="sourceUrls")
pages: list[KnowledgeFSCrawlImportPagePayload] | None = Field(default=None, min_length=1, max_length=200)
replace_existing_selection: bool = Field(default=False, alias="replaceExistingSelection")
model_config = ConfigDict(extra="forbid", validate_by_alias=True, validate_by_name=True)
@field_validator("source_urls")
@classmethod
def validate_source_urls(cls, source_urls: list[str]) -> list[str]:
normalized = [source_url.strip() for source_url in source_urls]
if any(not source_url or len(source_url) > 4_096 for source_url in normalized):
raise ValueError("source URLs must be non-empty and at most 4096 characters")
return normalized
@model_validator(mode="after")
def validate_pages(self) -> KnowledgeFSCrawlImportPayload:
if self.source_update is not None and self.pages is not None:
raise ValueError("Atomic source edits require sourceUrls without inline pages")
if self.pages is not None and [page.source_url for page in self.pages] != self.source_urls:
raise ValueError("crawl import pages must match source URLs in order")
return self
class KnowledgeFSCrawledPageResponse(ResponseModel):
content: str
description: str | None = None
source_url: str = Field(validation_alias=AliasChoices("source_url", "sourceUrl"))
title: str | None = None
class KnowledgeFSSourceCrawlResponse(ResponseModel):
completed: int | None = Field(default=None, ge=0)
failed: int | None = Field(default=None, ge=0)
imported: int | None = Field(default=None, ge=0)
pages: list[KnowledgeFSCrawledPageResponse]
replaced: int | None = Field(default=None, ge=0)
skipped: int | None = Field(default=None, ge=0)
status: str | None = None
total: int | None = Field(default=None, ge=0)
class KnowledgeFSSourcePagesQuery(BaseModel):
cursor: str | None = Field(default=None, min_length=1, max_length=4_096)
limit: int = Field(default=50, ge=1, le=200)
parent_id: str | None = Field(default=None, min_length=1, max_length=4_096, alias="parentId")
view: Literal["tree"] | None = None
model_config = ConfigDict(extra="forbid")
class KnowledgeFSSourcePageResponse(ResponseModel):
has_children: bool | None = Field(default=None, validation_alias=AliasChoices("has_children", "hasChildren"))
last_edited_time: str | None = Field(
default=None, validation_alias=AliasChoices("last_edited_time", "lastEditedTime")
)
page_id: str = Field(validation_alias=AliasChoices("page_id", "pageId"))
page_name: str = Field(validation_alias=AliasChoices("page_name", "pageName"))
parent_id: str | None = Field(default=None, validation_alias=AliasChoices("parent_id", "parentId"))
type: str
class KnowledgeFSSourceWorkspacePagesResponse(ResponseModel):
pages: list[KnowledgeFSSourcePageResponse]
total: int | None = Field(default=None, ge=0)
workspace_id: str | None = Field(default=None, validation_alias=AliasChoices("workspace_id", "workspaceId"))
workspace_name: str | None = Field(default=None, validation_alias=AliasChoices("workspace_name", "workspaceName"))
class KnowledgeFSSourcePagesResponse(ResponseModel):
next_cursor: str | None = Field(default=None, validation_alias=AliasChoices("next_cursor", "nextCursor"))
workspaces: list[KnowledgeFSSourceWorkspacePagesResponse]
class KnowledgeFSSourceImportPagePayload(BaseModel):
last_edited_time: str | None = Field(default=None, alias="lastEditedTime")
name: str | None = Field(default=None, min_length=1, max_length=200)
page_id: str = Field(min_length=1, alias="pageId")
type: str = Field(min_length=1)
workspace_id: str = Field(min_length=1, alias="workspaceId")
model_config = ConfigDict(extra="forbid", validate_by_alias=True, validate_by_name=True)
class KnowledgeFSSourceImportPagesPayload(BaseModel):
pages: list[KnowledgeFSSourceImportPagePayload] = Field(min_length=1, max_length=200)
model_config = ConfigDict(extra="forbid")
class KnowledgeFSSourceFilesQuery(BaseModel):
bucket: str | None = None
continuation_token: str | None = Field(default=None, min_length=1, max_length=4_096, alias="continuationToken")
max_keys: int | None = Field(default=None, ge=1, le=1_000, alias="maxKeys")
prefix: str | None = None
model_config = ConfigDict(extra="forbid", validate_by_alias=True, validate_by_name=True)
class KnowledgeFSSourceFileResponse(ResponseModel):
id: str
name: str
size: float | None = Field(default=None, ge=0)
type: str
class KnowledgeFSSourceFileBucketResponse(ResponseModel):
bucket: str | None = None
continuation_token: str | None = Field(
default=None, validation_alias=AliasChoices("continuation_token", "continuationToken")
)
files: list[KnowledgeFSSourceFileResponse]
is_truncated: bool | None = Field(default=None, validation_alias=AliasChoices("is_truncated", "isTruncated"))
class KnowledgeFSSourceFilesResponse(ResponseModel):
buckets: list[KnowledgeFSSourceFileBucketResponse]
class KnowledgeFSSourceImportFilePayload(BaseModel):
bucket: str | None = None
id: str = Field(min_length=1)
mime_type: str | None = Field(default=None, alias="mimeType")
name: str = Field(min_length=1, max_length=255)
model_config = ConfigDict(extra="forbid", validate_by_alias=True, validate_by_name=True)
class KnowledgeFSSourceImportFilesPayload(BaseModel):
files: list[KnowledgeFSSourceImportFilePayload] = Field(min_length=1, max_length=200)
model_config = ConfigDict(extra="forbid")
class KnowledgeFSSourceImportedDocumentResponse(ResponseModel):
document_asset_id: str = Field(validation_alias=AliasChoices("document_asset_id", "documentAssetId"))
filename: str
class KnowledgeFSSourceImportFailureResponse(ResponseModel):
code: KnowledgeFSPublicErrorCode
error: str
failure: KnowledgeFSPublicFailureResponse | None = None
filename: str
@model_validator(mode="after")
def normalize_public_failure(self) -> KnowledgeFSSourceImportFailureResponse:
self.error = (
self.failure.message
if self.failure is not None
else "Agent Knowledge Base could not import this source document."
)
if self.failure is not None:
self.code = self.failure.code
return self
class KnowledgeFSSourceImportResponse(ResponseModel):
documents: list[KnowledgeFSSourceImportedDocumentResponse]
failed: list[KnowledgeFSSourceImportFailureResponse]
skipped: list[str]
class KnowledgeFSQueryImageResponse(ResponseModel):
"""One query image a retrieval run was asked with, enriched for console display.
The gateway persists only the UploadFile reference and static metadata; the console fills in
the file name and a short-lived signed preview URL for files the caller still owns.
"""
upload_file_id: str = Field(validation_alias=AliasChoices("upload_file_id", "uploadFileId"))
byte_size: int | None = Field(default=None, ge=0, validation_alias=AliasChoices("byte_size", "byteSize"))
mime_type: str | None = Field(default=None, validation_alias=AliasChoices("mime_type", "mimeType"))
name: str | None = None
preview_url: str | None = None
class _KnowledgeFSQueryModalities(BaseModel):
query: str | None = Field(default=None, max_length=16_000)
query_images: list[KnowledgeFSQueryImageReference] = Field(
default_factory=list,
max_length=4,
alias="queryImages",
exclude_if=lambda value: not value,
)
@field_validator("query")
@classmethod
def validate_query_bytes(cls, value: str | None) -> str | None:
if value is not None and len(value.encode("utf-8")) > 16_384:
raise ValueError("query must not exceed 16384 UTF-8 bytes")
return value
@model_validator(mode="after")
def validate_query_modality(self) -> _KnowledgeFSQueryModalities:
if not (self.query and self.query.strip()) and not self.query_images:
raise ValueError("At least one of query or queryImages is required")
if len({image.upload_file_id for image in self.query_images}) != len(self.query_images):
raise ValueError("queryImages must not contain duplicate uploadFileId values")
return self
class KnowledgeFSQueryCreatePayload(_KnowledgeFSQueryModalities):
mode: Literal["auto", "deep", "fast", "research"] | None = None
active_document_ids: list[str] = Field(
default_factory=list,
max_length=100,
alias="activeDocumentIds",
)
active_entity_ids: list[str] = Field(
default_factory=list,
max_length=100,
alias="activeEntityIds",
)
session_id: str | None = Field(
default=None,
alias="sessionId",
exclude_if=lambda value: value is None,
)
model_config = ConfigDict(extra="forbid", validate_by_alias=True, validate_by_name=True)
class KnowledgeFSQueryResponse(ResponseModel):
id: str
status: str
answer: str | None = None
trace_id: str | None = None
class KnowledgeFSWorkflowFailedRetrievalCapturePayload(BaseModel):
event_id: UUID = Field(
validation_alias=AliasChoices("event_id", "eventId"),
serialization_alias="eventId",
)
query: str = Field(min_length=1, max_length=16_000)
mode: Literal["deep", "fast", "research"]
retrieval_trace_id: str = Field(
min_length=1,
max_length=512,
validation_alias=AliasChoices("retrieval_trace_id", "retrievalTraceId"),
serialization_alias="retrievalTraceId",
)
model_config = ConfigDict(extra="forbid", populate_by_name=True, serialize_by_alias=True)
@field_validator("query", "retrieval_trace_id", mode="before")
@classmethod
def normalize_required_text(cls, value: object) -> object:
if not isinstance(value, str):
return value
normalized = value.strip()
if not normalized:
raise ValueError("Workflow failed-retrieval capture fields must not be empty")
return normalized
class KnowledgeFSWorkflowFailedRetrievalCaptureResponse(ResponseModel):
failed_query_id: UUID = Field(validation_alias=AliasChoices("failed_query_id", "failedQueryId"))
verdict: Literal["retrieval-miss", "coverage-gap", "irrelevant", "uncertain"]
bad_case_id: UUID | None = Field(
default=None,
validation_alias=AliasChoices("bad_case_id", "badCaseId"),
)
class KnowledgeFSResearchTaskLimits(BaseModel):
max_retrieval_steps: int | None = Field(default=None, ge=1, alias="maxRetrievalSteps")
max_scanned_resources: int | None = Field(default=None, ge=1, alias="maxScannedResources")
max_tool_calls: int | None = Field(default=None, ge=1, alias="maxToolCalls")
timeout_ms: int | None = Field(default=None, ge=1, alias="timeoutMs")
model_config = ConfigDict(extra="forbid", validate_by_alias=True, validate_by_name=True)
class KnowledgeFSResearchTaskCreatePayload(_KnowledgeFSQueryModalities):
mode: Literal["auto", "deep", "fast", "research"] | None = None
top_k: int | None = Field(default=None, ge=1, le=50, alias="topK")
budget_usd: float | None = Field(default=None, ge=0, alias="budgetUsd")
limits: KnowledgeFSResearchTaskLimits | None = None
metadata: dict[str, object] = Field(default_factory=dict)
model_config = ConfigDict(extra="forbid", validate_by_alias=True, validate_by_name=True)
class KnowledgeFSResearchTaskResponse(ResponseModel):
id: str
knowledge_space_id: str = Field(validation_alias=AliasChoices("knowledge_space_id", "knowledgeSpaceId"))
query: str
query_images: list[KnowledgeFSQueryImageResponse] = Field(
default_factory=list,
validation_alias=AliasChoices("query_images", "queryImages"),
exclude_if=lambda value: not value,
)
budget_usd: float | None = Field(default=None, ge=0, validation_alias=AliasChoices("budget_usd", "budgetUsd"))
completed_at: float | None = Field(default=None, validation_alias=AliasChoices("completed_at", "completedAt"))
cost: dict[str, object]
limits: KnowledgeFSResearchTaskLimits | None = None
stage: Literal[
"queued",
"planning",
"retrieving",
"analyzing",
"generating",
"paused",
"completed",
"failed",
"canceled",
]
mode: Literal["auto", "deep", "fast", "research"] | None = None
top_k: int | None = Field(default=None, validation_alias=AliasChoices("top_k", "topK"))
metadata: dict[str, object]
error: str | None = None
failure: KnowledgeFSPublicFailureResponse | None = None
created_at: float = Field(validation_alias=AliasChoices("created_at", "createdAt"))
updated_at: float = Field(validation_alias=AliasChoices("updated_at", "updatedAt"))
class KnowledgeFSResearchTaskListResponse(ResponseModel):
data: list[KnowledgeFSResearchTaskResponse] = Field(validation_alias=AliasChoices("data", "items"))
next_cursor: str | None = Field(default=None, validation_alias=AliasChoices("next_cursor", "nextCursor"))
class KnowledgeFSResearchTaskPlanPayload(_KnowledgeFSQueryModalities):
budget_usd: float | None = Field(default=None, ge=0, alias="budgetUsd")
mode: Literal["auto", "deep", "fast", "research"] | None = None
top_k: int | None = Field(default=None, ge=1, le=50, alias="topK")
model_config = ConfigDict(extra="forbid", validate_by_alias=True, validate_by_name=True)
class KnowledgeFSResearchTaskPlanBudgetResponse(ResponseModel):
budget_usd: float | None = Field(default=None, ge=0, validation_alias=AliasChoices("budget_usd", "budgetUsd"))
exceeds_budget: bool = Field(validation_alias=AliasChoices("exceeds_budget", "exceedsBudget"))
remaining_budget_usd: float | None = Field(
default=None, validation_alias=AliasChoices("remaining_budget_usd", "remainingBudgetUsd")
)
class KnowledgeFSResearchTaskRetrievalPlanResponse(ResponseModel):
dense_top_k: int = Field(ge=0, validation_alias=AliasChoices("dense_top_k", "denseTopK"))
fts_top_k: int = Field(ge=0, validation_alias=AliasChoices("fts_top_k", "ftsTopK"))
fusion_limit: int = Field(ge=0, validation_alias=AliasChoices("fusion_limit", "fusionLimit"))
query_language: Literal["cjk", "latin", "mixed-cjk-latin", "other"] = Field(
validation_alias=AliasChoices("query_language", "queryLanguage")
)
requested_mode: Literal["auto", "deep", "fast", "research"] = Field(
validation_alias=AliasChoices("requested_mode", "requestedMode")
)
rerank_candidate_limit: int = Field(
ge=0, validation_alias=AliasChoices("rerank_candidate_limit", "rerankCandidateLimit")
)
resolved_mode: Literal["deep", "fast", "research"] = Field(
validation_alias=AliasChoices("resolved_mode", "resolvedMode")
)
strategy_version: str = Field(validation_alias=AliasChoices("strategy_version", "strategyVersion"))
top_k: int = Field(ge=1, validation_alias=AliasChoices("top_k", "topK"))
class KnowledgeFSResearchTaskPlanResponse(ResponseModel):
budget: KnowledgeFSResearchTaskPlanBudgetResponse
estimates: dict[str, object]
knowledge_space_id: str = Field(validation_alias=AliasChoices("knowledge_space_id", "knowledgeSpaceId"))
query: str
query_images: list[KnowledgeFSQueryImageReference] = Field(
default_factory=list,
validation_alias=AliasChoices("query_images", "queryImages"),
exclude_if=lambda value: not value,
)
retrieval_plan: KnowledgeFSResearchTaskRetrievalPlanResponse = Field(
validation_alias=AliasChoices("retrieval_plan", "retrievalPlan")
)
steps: list[dict[str, object]]
strategy_version: Literal["research-dry-run-planner-v1"] = Field(
validation_alias=AliasChoices("strategy_version", "strategyVersion")
)
class KnowledgeFSResearchTaskPartialsQuery(KnowledgeFSCursorQuery):
limit: int = Field(default=25, ge=1, le=100)
class KnowledgeFSResearchTaskStreamQuery(BaseModel):
knowledge_space_id: str = Field(min_length=1, max_length=255, alias="knowledgeSpaceId")
cursor: str | None = Field(default=None, min_length=1, max_length=1_000)
limit: int = Field(default=25, ge=1, le=100)
model_config = ConfigDict(extra="forbid", validate_by_alias=True, validate_by_name=True)
class KnowledgeFSResearchTaskPartialResponse(ResponseModel):
answer: str | None = Field(default=None, min_length=1, max_length=20_000)
evidence_bundle: dict[str, object] = Field(validation_alias=AliasChoices("evidence_bundle", "evidenceBundle"))
knowledge_space_id: str = Field(validation_alias=AliasChoices("knowledge_space_id", "knowledgeSpaceId"))
research_task_job_id: str = Field(validation_alias=AliasChoices("research_task_job_id", "researchTaskJobId"))
sequence: int = Field(ge=1)
class KnowledgeFSResearchTaskPartialListResponse(ResponseModel):
data: list[KnowledgeFSResearchTaskPartialResponse] = Field(validation_alias=AliasChoices("data", "items"))
next_cursor: str | None = Field(default=None, validation_alias=AliasChoices("next_cursor", "nextCursor"))
class KnowledgeFSAnswerTraceStepResponse(ResponseModel):
ended_at: datetime | None = Field(default=None, validation_alias=AliasChoices("ended_at", "endedAt"))
metadata: dict[str, object]
name: str
started_at: datetime = Field(validation_alias=AliasChoices("started_at", "startedAt"))
status: Literal["error", "ok", "skipped"]
class KnowledgeFSAnswerTraceResponse(ResponseModel):
created_at: datetime = Field(validation_alias=AliasChoices("created_at", "createdAt"))
evidence_bundle_id: str | None = Field(
default=None, validation_alias=AliasChoices("evidence_bundle_id", "evidenceBundleId")
)
id: str
knowledge_space_id: str = Field(validation_alias=AliasChoices("knowledge_space_id", "knowledgeSpaceId"))
mode: Literal["auto", "deep", "fast", "research"]
query: str
query_images: list[KnowledgeFSQueryImageResponse] = Field(
default_factory=list,
validation_alias=AliasChoices("query_images", "queryImages"),
exclude_if=lambda value: not value,
)
source: KnowledgeFSTraceSource = "retrieval_test"
steps: list[KnowledgeFSAnswerTraceStepResponse]
class KnowledgeFSTraceEntriesQuery(KnowledgeFSCursorQuery):
limit: int = Field(default=100, ge=1, le=200)
class KnowledgeFSTraceEntryResponse(ResponseModel):
kind: Literal["directory", "resource"]
metadata: dict[str, object]
name: str
path: str
resource_type: str | None = Field(default=None, validation_alias=AliasChoices("resource_type", "resourceType"))
target_id: str | None = Field(default=None, validation_alias=AliasChoices("target_id", "targetId"))
version: int | None = Field(default=None, ge=1)
class KnowledgeFSTraceEntryListResponse(ResponseModel):
consistency_class: str | None = Field(
default=None, validation_alias=AliasChoices("consistency_class", "consistencyClass")
)
data: list[KnowledgeFSTraceEntryResponse] = Field(validation_alias=AliasChoices("data", "items"))
next_cursor: str | None = Field(default=None, validation_alias=AliasChoices("next_cursor", "nextCursor"))
path: str
preview: bool | None = None
truncated: bool
class KnowledgeFSTraceProfileResponse(ResponseModel):
embedding_model: str | None = Field(
default=None, validation_alias=AliasChoices("embedding_model", "embeddingModel")
)
embedding_vector_space_id: str | None = Field(
default=None, validation_alias=AliasChoices("embedding_vector_space_id", "embeddingVectorSpaceId")
)
projection_publication_id: str | None = Field(
default=None, validation_alias=AliasChoices("projection_publication_id", "projectionPublicationId")
)
projection_version: int | None = Field(
default=None, ge=1, validation_alias=AliasChoices("projection_version", "projectionVersion")
)
reasoning_model: str | None = Field(
default=None, validation_alias=AliasChoices("reasoning_model", "reasoningModel")
)
rerank_model: str | None = Field(default=None, validation_alias=AliasChoices("rerank_model", "rerankModel"))
retrieval_profile_revision: int | None = Field(
default=None, ge=1, validation_alias=AliasChoices("retrieval_profile_revision", "retrievalProfileRevision")
)
class KnowledgeFSTraceScoresResponse(ResponseModel):
final: float | None = Field(default=None, ge=0, le=1)
rerank: float | None = Field(default=None, ge=0, le=1)
retrieval: float | None = Field(default=None, ge=0, le=1)
class KnowledgeFSTraceStageResponse(ResponseModel):
candidate_count: int | None = Field(
default=None, ge=0, validation_alias=AliasChoices("candidate_count", "candidateCount")
)
name: str
status: Literal["error", "ok", "skipped"]
class KnowledgeFSTraceResponse(ResponseModel):
id: str
completed: bool
created_at: datetime = Field(validation_alias=AliasChoices("created_at", "createdAt"))
duration_ms: int | None = Field(default=None, ge=0, validation_alias=AliasChoices("duration_ms", "durationMs"))
evidence_bundle_id: str | None = Field(
default=None, validation_alias=AliasChoices("evidence_bundle_id", "evidenceBundleId")
)
evidence_state: str | None = Field(default=None, validation_alias=AliasChoices("evidence_state", "evidenceState"))
final_score: float | None = Field(
default=None, ge=0, le=1, validation_alias=AliasChoices("final_score", "finalScore")
)
mode: Literal["auto", "deep", "fast", "research"]
open_bad_case_id: str | None = Field(
default=None, validation_alias=AliasChoices("open_bad_case_id", "openBadCaseId")
)
profile: KnowledgeFSTraceProfileResponse
query: str
query_images: list[KnowledgeFSQueryImageResponse] = Field(
default_factory=list,
validation_alias=AliasChoices("query_images", "queryImages"),
exclude_if=lambda value: not value,
)
result_count: int = Field(ge=0, validation_alias=AliasChoices("result_count", "resultCount"))
scores: KnowledgeFSTraceScoresResponse
source: KnowledgeFSTraceSource = "retrieval_test"
stages: list[KnowledgeFSTraceStageResponse]
class KnowledgeFSTraceListResponse(ResponseModel):
data: list[KnowledgeFSTraceResponse] = Field(validation_alias=AliasChoices("data", "items"))
next_cursor: str | None = Field(default=None, validation_alias=AliasChoices("next_cursor", "nextCursor"))
class KnowledgeFSGoldenQuestionPayload(BaseModel):
annotation: str = Field(default="", max_length=2_000)
evidence_text: str = Field(default="", max_length=8_000)
expected_evidence_ids: list[str] = Field(default_factory=list, max_length=50)
match_policy: Literal["all", "any"] = "all"
question: str = Field(min_length=1, max_length=4_000)
source_bad_case_id: str | None = Field(default=None, max_length=255)
tags: list[str] = Field(default_factory=list, max_length=50)
model_config = ConfigDict(extra="forbid")
@field_validator("annotation", "evidence_text", "question", mode="before")
@classmethod
def strip_text(cls, value: object) -> object:
return value.strip() if isinstance(value, str) else value
@field_validator("expected_evidence_ids", "tags")
@classmethod
def normalize_string_list(cls, value: list[str]) -> list[str]:
return list(dict.fromkeys(item.strip() for item in value if item.strip()))
class KnowledgeFSGoldenQuestionRemotePayload(BaseModel):
expected_evidence_ids: list[str] = Field(
default_factory=list,
serialization_alias="expectedEvidenceIds",
)
metadata: dict[str, object]
question: str
tags: list[str]
model_config = ConfigDict(extra="forbid", serialize_by_alias=True)
class KnowledgeFSGoldenQuestionUpdateRemotePayload(BaseModel):
expected_evidence_ids: list[str] | None = Field(default=None, serialization_alias="expectedEvidenceIds")
metadata: dict[str, object]
question: str
tags: list[str]
model_config = ConfigDict(extra="forbid", serialize_by_alias=True)
class KnowledgeFSGoldenQuestionResponse(ResponseModel):
id: str
question: str
annotation: str
evidence_text: str = ""
expected_evidence_ids: list[str] = Field(
default_factory=list, validation_alias=AliasChoices("expected_evidence_ids", "expectedEvidenceIds")
)
match_policy: Literal["all", "any"] = "all"
status: Literal["active", "draft", "stale", "paused"]
status_reason: Literal["source-deleted", "source-disabled"] | None = None
tags: list[str]
created_at: datetime = Field(validation_alias=AliasChoices("created_at", "createdAt"))
updated_at: datetime = Field(validation_alias=AliasChoices("updated_at", "updatedAt"))
@model_validator(mode="before")
@classmethod
def read_annotation_metadata(cls, value: object) -> object:
if not isinstance(value, dict):
return value
metadata = value.get("metadata")
annotation = metadata.get("annotation") if isinstance(metadata, dict) else None
evidence_text = metadata.get("evidenceText") if isinstance(metadata, dict) else None
match_policy = metadata.get("matchPolicy") if isinstance(metadata, dict) else None
status = metadata.get("lifecycleStatus") if isinstance(metadata, dict) else None
expected_evidence_ids = value.get("expectedEvidenceIds", value.get("expected_evidence_ids", []))
if status not in {"active", "draft", "stale"}:
status = "active" if isinstance(expected_evidence_ids, list) and expected_evidence_ids else "draft"
status_reason = None
if isinstance(metadata, dict):
if status == "stale" and metadata.get("staleReason") == "source-deleted":
status_reason = "source-deleted"
elif status == "active" and metadata.get("sourceAvailability") == "disabled":
status = "paused"
status_reason = "source-disabled"
return {
**value,
"annotation": annotation if isinstance(annotation, str) else "",
"evidence_text": evidence_text if isinstance(evidence_text, str) else "",
"match_policy": match_policy if match_policy in {"all", "any"} else "all",
"status": status,
"status_reason": status_reason,
}
class KnowledgeFSGoldenQuestionListResponse(ResponseModel):
data: list[KnowledgeFSGoldenQuestionResponse] = Field(validation_alias=AliasChoices("data", "items"))
next_cursor: str | None = Field(default=None, validation_alias=AliasChoices("next_cursor", "nextCursor"))
class KnowledgeFSGoldenQuestionEvidenceMatchPayload(BaseModel):
evidence: str | None = Field(default=None, min_length=1, max_length=8_000)
minimum_similarity: float = Field(default=0.7, ge=0, le=1)
node_ids: list[str] = Field(default_factory=list, max_length=50)
top_k: int = Field(default=5, ge=1, le=10)
model_config = ConfigDict(extra="forbid")
@field_validator("evidence", mode="before")
@classmethod
def strip_evidence(cls, value: object) -> object:
return value.strip() if isinstance(value, str) else value
@field_validator("node_ids")
@classmethod
def normalize_node_ids(cls, value: list[str]) -> list[str]:
return list(dict.fromkeys(item.strip() for item in value if item.strip()))
@model_validator(mode="after")
def require_one_lookup(self) -> KnowledgeFSGoldenQuestionEvidenceMatchPayload:
if bool(self.evidence) == bool(self.node_ids):
raise ValueError("Provide exactly one of evidence or node_ids")
return self
class KnowledgeFSGoldenQuestionEvidenceMatchRemotePayload(BaseModel):
evidence_texts: list[str] | None = Field(default=None, serialization_alias="evidenceTexts")
minimum_similarity: float = Field(serialization_alias="minimumSimilarity")
node_ids: list[str] | None = Field(default=None, serialization_alias="nodeIds")
top_k: int = Field(serialization_alias="topK")
model_config = ConfigDict(extra="forbid", serialize_by_alias=True)
class KnowledgeFSGoldenQuestionEvidenceCandidateResponse(ResponseModel):
document_asset_id: str = Field(validation_alias=AliasChoices("document_asset_id", "documentAssetId"))
node_id: str = Field(validation_alias=AliasChoices("node_id", "nodeId"))
page_number: int | None = Field(default=None, validation_alias=AliasChoices("page_number", "pageNumber"))
projection_id: str | None = Field(default=None, validation_alias=AliasChoices("projection_id", "projectionId"))
score: float | None = Field(default=None, ge=0, le=1)
section_path: list[str] = Field(validation_alias=AliasChoices("section_path", "sectionPath"))
text: str
class KnowledgeFSGoldenQuestionEvidenceMatchResponse(ResponseModel):
candidates: list[KnowledgeFSGoldenQuestionEvidenceCandidateResponse]
evidence: str
matched: bool
class KnowledgeFSGoldenQuestionBulkImportRowPayload(BaseModel):
evidence: str = Field(min_length=1, max_length=8_000)
question: str = Field(min_length=1, max_length=4_000)
tags: list[str] = Field(default_factory=list, max_length=50)
model_config = ConfigDict(extra="forbid")
@field_validator("evidence", "question", mode="before")
@classmethod
def strip_required_text(cls, value: object) -> object:
return value.strip() if isinstance(value, str) else value
@field_validator("tags")
@classmethod
def normalize_tags(cls, value: list[str]) -> list[str]:
return list(dict.fromkeys(tag.strip() for tag in value if tag.strip()))
class KnowledgeFSGoldenQuestionBulkImportPayload(BaseModel):
match_policy: Literal["all", "any"] = "all"
minimum_similarity: float = Field(default=0.7, ge=0, le=1)
rows: list[KnowledgeFSGoldenQuestionBulkImportRowPayload] = Field(min_length=1, max_length=500)
model_config = ConfigDict(extra="forbid")
class KnowledgeFSGoldenQuestionBulkImportRemoteRowPayload(BaseModel):
evidence: str
metadata: dict[str, object]
question: str
tags: list[str]
model_config = ConfigDict(extra="forbid")
class KnowledgeFSGoldenQuestionBulkImportRemotePayload(BaseModel):
match_policy: Literal["all", "any"] = Field(serialization_alias="matchPolicy")
minimum_similarity: float = Field(serialization_alias="minimumSimilarity")
rows: list[KnowledgeFSGoldenQuestionBulkImportRemoteRowPayload]
model_config = ConfigDict(extra="forbid", serialize_by_alias=True)
class KnowledgeFSGoldenQuestionBulkImportItemResponse(ResponseModel):
expected_evidence_id: str | None = Field(
default=None, validation_alias=AliasChoices("expected_evidence_id", "expectedEvidenceId")
)
question_id: str = Field(validation_alias=AliasChoices("question_id", "questionId"))
row_index: int = Field(ge=0, validation_alias=AliasChoices("row_index", "rowIndex"))
similarity: float | None = Field(default=None, ge=0, le=1)
status: Literal["active", "draft"]
class KnowledgeFSGoldenQuestionBulkImportResponse(ResponseModel):
active_count: int = Field(ge=0, validation_alias=AliasChoices("active_count", "activeCount"))
draft_count: int = Field(ge=0, validation_alias=AliasChoices("draft_count", "draftCount"))
items: list[KnowledgeFSGoldenQuestionBulkImportItemResponse]
class KnowledgeFSBadCaseUpdatePayload(BaseModel):
expected_revision: int = Field(ge=1, serialization_alias="expectedRevision")
reason: str | None = Field(default=None, min_length=1, max_length=4_000)
replay_run_id: str | None = Field(default=None, serialization_alias="replayRunId")
status: Literal["open", "replaying", "fixed", "dismissed"]
tags: list[str] | None = Field(default=None, max_length=50)
model_config = ConfigDict(extra="forbid", serialize_by_alias=True)
@field_validator("reason", mode="before")
@classmethod
def strip_optional_reason(cls, value: object) -> object:
return value.strip() if isinstance(value, str) else value
class KnowledgeFSBadCaseCreatePayload(BaseModel):
reason: str = Field(min_length=1, max_length=4_000)
tags: list[str] = Field(default_factory=list, max_length=50)
trace_id: str = Field(min_length=1, serialization_alias="traceId")
model_config = ConfigDict(extra="forbid", serialize_by_alias=True)
@field_validator("reason", mode="before")
@classmethod
def strip_reason(cls, value: object) -> object:
return value.strip() if isinstance(value, str) else value
@field_validator("tags")
@classmethod
def normalize_tags(cls, value: list[str]) -> list[str]:
return list(dict.fromkeys(tag.strip() for tag in value if tag.strip()))
class KnowledgeFSBadCaseResponse(ResponseModel):
id: str
question: str = Field(default="", validation_alias=AliasChoices("question", "query"))
reason: str
replay_run_id: str | None = Field(
default=None,
validation_alias=AliasChoices("replay_run_id", "replayRunId"),
)
revision: int = Field(ge=1)
status: Literal["open", "replaying", "fixed", "dismissed"]
tags: list[str]
created_at: datetime = Field(validation_alias=AliasChoices("created_at", "createdAt"))
updated_at: datetime = Field(validation_alias=AliasChoices("updated_at", "updatedAt"))
class KnowledgeFSBadCaseListResponse(ResponseModel):
data: list[KnowledgeFSBadCaseResponse] = Field(validation_alias=AliasChoices("data", "items"))
next_cursor: str | None = Field(default=None, validation_alias=AliasChoices("next_cursor", "nextCursor"))
class KnowledgeFSBadCaseTraceReferenceResponse(ResponseModel):
trace_id: str = Field(validation_alias=AliasChoices("trace_id", "traceId"))
class KnowledgeFSQualityReplayPayload(BaseModel):
golden_question_ids: list[str] | None = Field(
default=None,
min_length=1,
max_length=1000,
serialization_alias="goldenQuestionIds",
)
mode: Literal["deep", "fast", "research"] | None = None
selection: Literal["all-active"] | None = None
model_config = ConfigDict(extra="forbid", serialize_by_alias=True)
@model_validator(mode="after")
def validate_selection(self) -> KnowledgeFSQualityReplayPayload:
if (self.golden_question_ids is None) == (self.selection is None):
raise ValueError("provide exactly one of golden_question_ids or selection")
return self
class KnowledgeFSQualityReplayDetailQuery(BaseModel):
evidence_item_id: UUID | None = None
class KnowledgeFSQualityReplayEvidenceItem(ResponseModel):
available: bool
document_name: str | None = Field(
default=None,
validation_alias=AliasChoices("document_name", "documentName"),
)
matched: bool
ordinal: int = Field(ge=1)
page_number: int | None = Field(
default=None,
ge=1,
validation_alias=AliasChoices("page_number", "pageNumber"),
)
section_path: list[str] = Field(
default_factory=list,
validation_alias=AliasChoices("section_path", "sectionPath"),
)
text: str | None = None
class KnowledgeFSQualityReplayEvidenceDiff(ResponseModel):
evidence_items: list[KnowledgeFSQualityReplayEvidenceItem] | None = Field(
default=None,
validation_alias=AliasChoices("evidence_items", "evidenceItems"),
)
expected_count: int = Field(ge=0, validation_alias=AliasChoices("expected_count", "expectedCount"))
matched_count: int = Field(ge=0, validation_alias=AliasChoices("matched_count", "matchedCount"))
missing_count: int = Field(ge=0, validation_alias=AliasChoices("missing_count", "missingCount"))
retrieved_count: int = Field(ge=0, validation_alias=AliasChoices("retrieved_count", "retrievedCount"))
class KnowledgeFSQualityReplayMetrics(ResponseModel):
dense_candidates: int | None = Field(
default=None, ge=0, validation_alias=AliasChoices("dense_candidates", "denseCandidates")
)
fts_candidates: int | None = Field(
default=None, ge=0, validation_alias=AliasChoices("fts_candidates", "ftsCandidates")
)
fused_candidates: int | None = Field(
default=None, ge=0, validation_alias=AliasChoices("fused_candidates", "fusedCandidates")
)
graph_expansion_candidates: int | None = Field(
default=None, ge=0, validation_alias=AliasChoices("graph_expansion_candidates", "graphExpansionCandidates")
)
page_index_matched_nodes: int | None = Field(
default=None, ge=0, validation_alias=AliasChoices("page_index_matched_nodes", "pageIndexMatchedNodes")
)
permission_filtered_candidates: int | None = Field(
default=None,
ge=0,
validation_alias=AliasChoices("permission_filtered_candidates", "permissionFilteredCandidates"),
)
rerank_candidates: int | None = Field(
default=None, ge=0, validation_alias=AliasChoices("rerank_candidates", "rerankCandidates")
)
score_threshold_filtered_candidates: int | None = Field(
default=None,
ge=0,
validation_alias=AliasChoices("score_threshold_filtered_candidates", "scoreThresholdFilteredCandidates"),
)
summary_candidates: int | None = Field(
default=None, ge=0, validation_alias=AliasChoices("summary_candidates", "summaryCandidates")
)
total_ms: float | None = Field(default=None, ge=0, validation_alias=AliasChoices("total_ms", "totalMs"))
class KnowledgeFSQualityReplayItemResult(ResponseModel):
evidence_diff: KnowledgeFSQualityReplayEvidenceDiff = Field(
validation_alias=AliasChoices("evidence_diff", "evidenceDiff")
)
metrics: KnowledgeFSQualityReplayMetrics
passed: bool
class KnowledgeFSQualityReplayItem(ResponseModel):
golden_question_id: str = Field(validation_alias=AliasChoices("golden_question_id", "goldenQuestionId"))
id: str
match_policy: Literal["all", "any"] = Field(validation_alias=AliasChoices("match_policy", "matchPolicy"))
ordinal: int = Field(ge=1)
question: str
result: KnowledgeFSQualityReplayItemResult | None = None
state: Literal["queued", "running", "passed", "failed", "canceled"]
class KnowledgeFSQualityReplayEmbeddingProvenance(ResponseModel):
dimension: int = Field(gt=0)
model: str
vector_space_id: str = Field(validation_alias=AliasChoices("vector_space_id", "vectorSpaceId"))
class KnowledgeFSQualityReplayProjectionProvenance(ResponseModel):
projection_version: int = Field(gt=0, validation_alias=AliasChoices("projection_version", "projectionVersion"))
class KnowledgeFSQualityReplayRetrievalProvenance(ResponseModel):
profile_revision: int = Field(gt=0, validation_alias=AliasChoices("profile_revision", "profileRevision"))
reasoning_model: str = Field(validation_alias=AliasChoices("reasoning_model", "reasoningModel"))
rerank_model: str | None = Field(default=None, validation_alias=AliasChoices("rerank_model", "rerankModel"))
class KnowledgeFSQualityReplayProvenance(ResponseModel):
embedding: KnowledgeFSQualityReplayEmbeddingProvenance | None = None
projection: KnowledgeFSQualityReplayProjectionProvenance
retrieval: KnowledgeFSQualityReplayRetrievalProvenance
class KnowledgeFSQualityReplaySummary(ResponseModel):
completed: int = Field(ge=0)
failed: int = Field(ge=0)
hit_rate: float = Field(ge=0, le=1, validation_alias=AliasChoices("hit_rate", "hitRate"))
passed: int = Field(ge=0)
total: int = Field(ge=0)
class KnowledgeFSQualityReplayResponse(ResponseModel):
attempt: int = Field(ge=0)
created_at: datetime = Field(validation_alias=AliasChoices("created_at", "createdAt"))
error: str | None = None
id: str
items: list[KnowledgeFSQualityReplayItem]
knowledge_space_id: str = Field(validation_alias=AliasChoices("knowledge_space_id", "knowledgeSpaceId"))
mode: Literal["deep", "fast", "research"]
provenance: KnowledgeFSQualityReplayProvenance
revision: int = Field(ge=1)
state: Literal["queued", "running", "passed", "failed", "canceled"]
summary: KnowledgeFSQualityReplaySummary
updated_at: datetime = Field(validation_alias=AliasChoices("updated_at", "updatedAt"))
class KnowledgeFSQualityReplayListQuery(BaseModel):
cursor: str | None = Field(default=None, max_length=1000)
limit: int = Field(default=20, ge=1, le=100)
mode: Literal["deep", "fast", "research"] | None = None
state: Literal["queued", "running", "passed", "failed", "canceled"] | None = None
class KnowledgeFSQualityReplayListResponse(ResponseModel):
data: list[KnowledgeFSQualityReplayResponse] = Field(validation_alias=AliasChoices("data", "items"))
next_cursor: str | None = Field(default=None, validation_alias=AliasChoices("next_cursor", "nextCursor"))
class KnowledgeFSUploadSessionResponse(ResponseModel):
compilation_job_id: str | None = Field(
default=None, validation_alias=AliasChoices("compilation_job_id", "compilationJobId")
)
completed_at: int | None = Field(default=None, validation_alias=AliasChoices("completed_at", "completedAt"))
document_asset_id: str | None = Field(
default=None, validation_alias=AliasChoices("document_asset_id", "documentAssetId")
)
expected_size_bytes: int = Field(gt=0, validation_alias=AliasChoices("expected_size_bytes", "expectedSizeBytes"))
expires_at: int = Field(ge=0, validation_alias=AliasChoices("expires_at", "expiresAt"))
id: str = Field(min_length=1, max_length=255)
mode: Literal["multipart", "single", "small_fallback"]
multipart_part_count: int | None = Field(
default=None, ge=1, validation_alias=AliasChoices("multipart_part_count", "multipartPartCount")
)
multipart_part_size_bytes: int | None = Field(
default=None,
gt=0,
validation_alias=AliasChoices("multipart_part_size_bytes", "multipartPartSizeBytes"),
)
status: Literal[
"creating",
"ready",
"completing",
"completed",
"aborting",
"aborted",
"expired",
"failed",
]
class KnowledgeFSUploadSessionCreatePayload(BaseModel):
checksum_sha256_base64: str = Field(
min_length=1,
max_length=255,
alias="checksumSha256Base64",
)
content_type: str = Field(min_length=1, max_length=255, alias="contentType")
expected_size_bytes: int = Field(gt=0, alias="expectedSizeBytes")
file_name: str = Field(min_length=1, max_length=512, alias="fileName")
model_config = ConfigDict(extra="forbid", validate_by_alias=True, validate_by_name=True)
class KnowledgeFSUploadSessionCreateRemotePayload(KnowledgeFSUploadSessionCreatePayload):
idempotency_key: str = Field(min_length=8, max_length=255, alias="idempotencyKey")
class KnowledgeFSPresignedUploadResponse(ResponseModel):
expires_at: int = Field(ge=0, validation_alias=AliasChoices("expires_at", "expiresAt"))
headers: dict[str, str]
method: Literal["PUT"]
url: str = Field(min_length=1, max_length=8_192)
class KnowledgeFSUploadSessionCreateResponse(ResponseModel):
session: KnowledgeFSUploadSessionResponse
upload: KnowledgeFSPresignedUploadResponse | None = None
class KnowledgeFSUploadPartPresignPayload(BaseModel):
checksum_sha256_base64: str = Field(
min_length=1,
max_length=255,
alias="checksumSha256Base64",
)
content_length: int = Field(gt=0, alias="contentLength")
model_config = ConfigDict(extra="forbid", validate_by_alias=True, validate_by_name=True)
class KnowledgeFSUploadSessionPartPayload(BaseModel):
checksum_sha256_base64: str | None = Field(
default=None,
min_length=1,
max_length=255,
alias="checksumSha256Base64",
)
etag: str = Field(min_length=1, max_length=255)
part_number: int = Field(ge=1, le=10_000, alias="partNumber")
model_config = ConfigDict(extra="forbid", validate_by_alias=True, validate_by_name=True)
class KnowledgeFSUploadSessionCompletePayload(BaseModel):
parts: list[KnowledgeFSUploadSessionPartPayload] | None = Field(default=None, max_length=10_000)
model_config = ConfigDict(extra="forbid")
class KnowledgeFSUploadSessionAbortPayload(BaseModel):
model_config = ConfigDict(extra="forbid")
class KnowledgeFSUploadSessionMutationResponse(ResponseModel):
session: KnowledgeFSUploadSessionResponse
class KnowledgeFSSmallFileUploadResponse(ResponseModel):
session: KnowledgeFSUploadSessionResponse
class KnowledgeFSStreamCapabilityPayload(BaseModel):
control_space_id: str = Field(min_length=1, max_length=255)
model_config = ConfigDict(extra="forbid")
class KnowledgeFSStreamCapabilityResponse(ResponseModel):
token: str
expires_at: datetime
operation_id: Literal["streamResearchTask"]
url: str
class KnowledgeFSQueryStreamCapabilityResponse(ResponseModel):
token: str
expires_at: datetime
operation_id: Literal["createQuery"]
url: str
class KnowledgeFSAdmittedQueryRequest(KnowledgeFSQueryCreatePayload):
knowledge_space_id: str = Field(min_length=1, alias="knowledgeSpaceId")
model_config = ConfigDict(
extra="forbid",
serialize_by_alias=True,
validate_by_alias=True,
validate_by_name=True,
)
class KnowledgeFSQueryAdmissionResponse(ResponseModel):
trace_id: str
expires_at: datetime
operation_id: Literal["createQuery"]
request: KnowledgeFSAdmittedQueryRequest
token: str
url: str
class KnowledgeFSJWKResponse(ResponseModel):
alg: Literal["RS256"]
e: str
kid: str
kty: Literal["RSA"]
n: str
use: Literal["sig"]
class KnowledgeFSJWKSResponse(ResponseModel):
keys: list[KnowledgeFSJWKResponse]
__all__ = [
"KnowledgeFSActiveProfileRevisions",
"KnowledgeFSAdmittedQueryRequest",
"KnowledgeFSAnswerTraceResponse",
"KnowledgeFSAppBindingListResponse",
"KnowledgeFSAppBindingPayload",
"KnowledgeFSAppBindingResponse",
"KnowledgeFSAsyncCrawlPreviewImportPayload",
"KnowledgeFSAsyncOnlineDocumentImportPayload",
"KnowledgeFSAsyncOnlineDriveImportPayload",
"KnowledgeFSAsyncSourceImport",
"KnowledgeFSAsyncSourceImportPayload",
"KnowledgeFSAsyncWebsiteCrawlImportPayload",
"KnowledgeFSBackgroundTaskFailureResponse",
"KnowledgeFSBackgroundTaskListQuery",
"KnowledgeFSBackgroundTaskListResponse",
"KnowledgeFSBackgroundTaskResponse",
"KnowledgeFSBulkDeletionAcceptedResponse",
"KnowledgeFSBulkDocumentAvailabilityFailureResponse",
"KnowledgeFSBulkDocumentAvailabilityItem",
"KnowledgeFSBulkDocumentAvailabilityPayload",
"KnowledgeFSBulkDocumentAvailabilityResponse",
"KnowledgeFSBulkDocumentDeletePayload",
"KnowledgeFSBulkJobResponse",
"KnowledgeFSBulkLogicalDocumentDeletePayload",
"KnowledgeFSCrawlImportPayload",
"KnowledgeFSCrawlPreviewPageListQuery",
"KnowledgeFSCrawlPreviewPageListResponse",
"KnowledgeFSCrawlPreviewSelectionPayload",
"KnowledgeFSCursorQuery",
"KnowledgeFSDeferredSyncPolicyPayload",
"KnowledgeFSDocumentAvailabilityPayload",
"KnowledgeFSDocumentBatchDownloadPayload",
"KnowledgeFSDocumentChunkListQuery",
"KnowledgeFSDocumentChunkListResponse",
"KnowledgeFSDocumentChunkResponse",
"KnowledgeFSDocumentCompilationJobResponse",
"KnowledgeFSDocumentCreatePayload",
"KnowledgeFSDocumentDeletePayload",
"KnowledgeFSDocumentDownloadDescriptor",
"KnowledgeFSDocumentListResponse",
"KnowledgeFSDocumentMetadataPayload",
"KnowledgeFSDocumentMultimodalAssetQuery",
"KnowledgeFSDocumentMultimodalAssetRef",
"KnowledgeFSDocumentMultimodalAssetVariant",
"KnowledgeFSDocumentMultimodalItem",
"KnowledgeFSDocumentMultimodalItemResponse",
"KnowledgeFSDocumentMultimodalManifest",
"KnowledgeFSDocumentMultimodalManifestResponse",
"KnowledgeFSDocumentOutlineResponse",
"KnowledgeFSDocumentReferenceQuery",
"KnowledgeFSDocumentReindexPayload",
"KnowledgeFSDocumentReindexResponse",
"KnowledgeFSDocumentResponse",
"KnowledgeFSDocumentRevisionListResponse",
"KnowledgeFSDocumentStagedUploadAcceptedResponse",
"KnowledgeFSDocumentStagedUploadPayload",
"KnowledgeFSDocumentUploadAcceptedResponse",
"KnowledgeFSDocumentUploadCompilationJobResponse",
"KnowledgeFSDocumentUploadLogicalDocumentResponse",
"KnowledgeFSDurableDeletionAcceptedResponse",
"KnowledgeFSExternalAccessPayload",
"KnowledgeFSExternalAccessResponse",
"KnowledgeFSIdempotencyHeader",
"KnowledgeFSInitialDatasourceBindingPayload",
"KnowledgeFSInitialOnlineDocumentSourcePayload",
"KnowledgeFSInitialOnlineDriveSourcePayload",
"KnowledgeFSInitialSourcePayload",
"KnowledgeFSInitialSourcePreviewDocumentResponse",
"KnowledgeFSInitialSourcePreviewFileResponse",
"KnowledgeFSInitialSourcePreviewJobCreateResponse",
"KnowledgeFSInitialSourcePreviewJobResponse",
"KnowledgeFSInitialSourcePreviewPageResponse",
"KnowledgeFSInitialSourcePreviewPayload",
"KnowledgeFSInitialSourcePreviewResponse",
"KnowledgeFSInitialWebsiteCrawlOptionsPayload",
"KnowledgeFSInitialWebsiteSelectionPayload",
"KnowledgeFSInitialWebsiteSourcePayload",
"KnowledgeFSInitialWebsiteSourcePreviewPayload",
"KnowledgeFSJWKResponse",
"KnowledgeFSJWKSResponse",
"KnowledgeFSLogicalDocumentDeletePayload",
"KnowledgeFSLogicalDocumentListResponse",
"KnowledgeFSLogicalDocumentResponse",
"KnowledgeFSMemberBindingPayload",
"KnowledgeFSMembersReplacePayload",
"KnowledgeFSMetadataFieldListResponse",
"KnowledgeFSMetadataFieldResponse",
"KnowledgeFSModelIntent",
"KnowledgeFSOnlineDocumentWorkflowImportItemPayload",
"KnowledgeFSOnlineDriveWorkflowImportItemPayload",
"KnowledgeFSOverviewBaseStatsResponse",
"KnowledgeFSOverviewCountComparisonResponse",
"KnowledgeFSOverviewHealthComponentResponse",
"KnowledgeFSOverviewHealthComponentsResponse",
"KnowledgeFSOverviewHealthResponse",
"KnowledgeFSOverviewIndexCoverageResponse",
"KnowledgeFSOverviewInventoryDeltaResponse",
"KnowledgeFSOverviewInventoryResponse",
"KnowledgeFSOverviewQueryOutcomeBucketResponse",
"KnowledgeFSOverviewQueryOutcomeCountsResponse",
"KnowledgeFSOverviewQueryOutcomesResponse",
"KnowledgeFSOverviewRateComparisonResponse",
"KnowledgeFSOverviewSourceCategoriesResponse",
"KnowledgeFSOverviewStatsCurrentResponse",
"KnowledgeFSOverviewStatsResponse",
"KnowledgeFSOverviewStatsWindowResponse",
"KnowledgeFSOverviewWindowQuery",
"KnowledgeFSPermissionListResponse",
"KnowledgeFSPermissionResponse",
"KnowledgeFSPresignedUploadResponse",
"KnowledgeFSPublicErrorCode",
"KnowledgeFSPublicFailureResponse",
"KnowledgeFSQualityListQuery",
"KnowledgeFSQueryAdmissionResponse",
"KnowledgeFSQueryCreatePayload",
"KnowledgeFSQueryImageReference",
"KnowledgeFSQueryResponse",
"KnowledgeFSQueryStreamCapabilityResponse",
"KnowledgeFSReadinessCapabilities",
"KnowledgeFSReadinessIssue",
"KnowledgeFSRerankIntent",
"KnowledgeFSResearchTaskCreatePayload",
"KnowledgeFSResearchTaskLimits",
"KnowledgeFSResearchTaskListResponse",
"KnowledgeFSResearchTaskPartialListResponse",
"KnowledgeFSResearchTaskPartialsQuery",
"KnowledgeFSResearchTaskPlanPayload",
"KnowledgeFSResearchTaskPlanResponse",
"KnowledgeFSResearchTaskResponse",
"KnowledgeFSResolvedDocumentReferenceResponse",
"KnowledgeFSRetrievalCitationResponse",
"KnowledgeFSRetrievalCustomMetadataCondition",
"KnowledgeFSRetrievalCustomMetadataFilter",
"KnowledgeFSRetrievalCustomMetadataOperator",
"KnowledgeFSRetrievalFilterValue",
"KnowledgeFSRetrievalMetadataFilters",
"KnowledgeFSRetrievalProfileIntent",
"KnowledgeFSRetrievalQueryImageReference",
"KnowledgeFSRetrievalReservedMetadataNames",
"KnowledgeFSRetrievalTestItemResponse",
"KnowledgeFSRetrievalTestMetricsResponse",
"KnowledgeFSRetrievalTestPayload",
"KnowledgeFSRetrievalTestResponse",
"KnowledgeFSScoreThresholdIntent",
"KnowledgeFSSettingsPayload",
"KnowledgeFSSettingsResponse",
"KnowledgeFSSmallFileUploadResponse",
"KnowledgeFSSourceConnectionCreatePayload",
"KnowledgeFSSourceConnectionListQuery",
"KnowledgeFSSourceConnectionListResponse",
"KnowledgeFSSourceConnectionRefreshPayload",
"KnowledgeFSSourceConnectionResponse",
"KnowledgeFSSourceCrawlResponse",
"KnowledgeFSSourceCreatePayload",
"KnowledgeFSSourceCredentialTestResponse",
"KnowledgeFSSourceDeletePayload",
"KnowledgeFSSourceDeleteQuery",
"KnowledgeFSSourceEditOnlineDocumentSelectionPayload",
"KnowledgeFSSourceEditOnlineDriveSelectionPayload",
"KnowledgeFSSourceEditSelectionPayload",
"KnowledgeFSSourceEditSyncPolicyPayload",
"KnowledgeFSSourceEditWebsiteSelectionPayload",
"KnowledgeFSSourceFilesQuery",
"KnowledgeFSSourceFilesResponse",
"KnowledgeFSSourceImportFilesPayload",
"KnowledgeFSSourceImportPagesPayload",
"KnowledgeFSSourceImportResponse",
"KnowledgeFSSourceListQuery",
"KnowledgeFSSourceListResponse",
"KnowledgeFSSourcePagesQuery",
"KnowledgeFSSourcePagesResponse",
"KnowledgeFSSourceProviderListResponse",
"KnowledgeFSSourceResponse",
"KnowledgeFSSourceSyncPolicyPayload",
"KnowledgeFSSourceSyncPolicyResponse",
"KnowledgeFSSourceUpdatePayload",
"KnowledgeFSSourceWorkflowCancelPayload",
"KnowledgeFSSourceWorkflowImportPayload",
"KnowledgeFSSourceWorkflowResponse",
"KnowledgeFSSpaceCreatePayload",
"KnowledgeFSSpaceCreateResponse",
"KnowledgeFSSpaceDetailResponse",
"KnowledgeFSSpaceListItemResponse",
"KnowledgeFSSpaceListQuery",
"KnowledgeFSSpaceListResponse",
"KnowledgeFSSpaceUpdatePayload",
"KnowledgeFSStagedUploadResponse",
"KnowledgeFSStreamCapabilityPayload",
"KnowledgeFSStreamCapabilityResponse",
"KnowledgeFSTechnicalSummary",
"KnowledgeFSTraceEntriesQuery",
"KnowledgeFSTraceEntryListResponse",
"KnowledgeFSTraceListResponse",
"KnowledgeFSTraceResponse",
"KnowledgeFSUploadPartPresignPayload",
"KnowledgeFSUploadSessionAbortPayload",
"KnowledgeFSUploadSessionCompletePayload",
"KnowledgeFSUploadSessionCreatePayload",
"KnowledgeFSUploadSessionCreateRemotePayload",
"KnowledgeFSUploadSessionCreateResponse",
"KnowledgeFSUploadSessionMutationResponse",
"KnowledgeFSUploadSessionPartPayload",
"KnowledgeFSUploadSessionResponse",
"KnowledgeFSWorkflowFailedRetrievalCapturePayload",
"KnowledgeFSWorkflowFailedRetrievalCaptureResponse",
]
class KnowledgeFSServiceSourceCreatePayload(BaseModel):
connection_id: str | None = Field(default=None, alias="connectionId")
metadata: dict[str, object] = Field(default_factory=dict)
name: str = Field(min_length=1, max_length=200)
permission_scope: list[str] = Field(default_factory=list, max_length=0, alias="permissionScope")
status: Literal["active", "disabled", "error", "syncing"] | None = None
type: Literal["connector", "object-storage", "upload", "web"]
uri: str = Field(min_length=1, max_length=4_096)
model_config = ConfigDict(extra="forbid", validate_by_alias=True, validate_by_name=True)
@field_validator("metadata")
@classmethod
def validate_metadata(cls, value: dict[str, object]) -> dict[str, object]:
if "syncPolicy" in value:
raise ValueError("Use the source sync-policy endpoint to configure durable scheduling")
return value
class KnowledgeFSServiceSourceUpdatePayload(BaseModel):
expected_version: int | None = Field(default=None, ge=1, alias="expectedVersion")
metadata: dict[str, object] | None = None
name: str | None = Field(default=None, min_length=1, max_length=200)
provider_parameters: dict[str, bool | FiniteFloat | str] | None = Field(
default=None, max_length=50, alias="providerParameters"
)
sync_after_update: bool | None = Field(default=None, alias="syncAfterUpdate")
status: Literal["active", "disabled", "error", "syncing"] | None = None
uri: str | None = Field(default=None, min_length=1, max_length=4_096)
model_config = ConfigDict(extra="forbid", validate_by_alias=True, validate_by_name=True)
@model_validator(mode="after")
def validate_update(self) -> KnowledgeFSServiceSourceUpdatePayload:
if self.metadata is not None:
if "parameters" in self.metadata:
raise ValueError("Use providerParameters to update provider parameters")
if "syncPolicy" in self.metadata:
raise ValueError("Use the source sync-policy endpoint to configure durable scheduling")
if self.provider_parameters is not None and any(not key or len(key) > 255 for key in self.provider_parameters):
raise ValueError("Provider parameter keys must contain between 1 and 255 characters")
if all(value is None for value in (self.metadata, self.name, self.provider_parameters, self.status, self.uri)):
raise ValueError("At least one source update is required")
return self
class KnowledgeFSSourceWorkflowListQuery(KnowledgeFSCursorQuery):
source_id: str | None = Field(default=None, min_length=1, max_length=255, alias="sourceId")
model_config = ConfigDict(extra="forbid", validate_by_alias=True, validate_by_name=True)
class KnowledgeFSSourceWorkflowListResponse(ResponseModel):
data: list[KnowledgeFSSourceWorkflowResponse] = Field(validation_alias=AliasChoices("data", "items"))
next_cursor: str | None = Field(default=None, validation_alias=AliasChoices("next_cursor", "nextCursor"))
class KnowledgeFSServiceSourceConnectionCreatePayload(BaseModel):
"""Dify owns datasource secrets; clients supply an opaque binding in configuration."""
auth_kind: Literal["endpoint"] = Field(default="endpoint", alias="authKind")
credentials: dict[str, object] = Field(default_factory=dict, max_length=0)
configuration: dict[str, bool | int | str] = Field(default_factory=dict)
name: str = Field(min_length=1, max_length=160)
provider_id: str = Field(min_length=1, max_length=128, alias="providerId")
model_config = ConfigDict(extra="forbid", validate_by_alias=True, validate_by_name=True)
class KnowledgeFSDocumentProcessingTaskResponse(ResponseModel):
id: str
knowledge_space_id: str = Field(validation_alias=AliasChoices("knowledge_space_id", "knowledgeSpaceId"))
document_id: str = Field(validation_alias=AliasChoices("document_id", "documentId"))
document_revision: int = Field(ge=1, validation_alias=AliasChoices("document_revision", "documentRevision"))
state: Literal[
"dispatch_pending", "queued", "running", "retry_wait", "succeeded", "failed", "canceled", "superseded"
]
stage: Literal[
"queued", "parsed", "outline_built", "nodes_generated", "projection_built", "smoke_eval_passed", "published"
]
semantic_enrichment: KnowledgeFSSemanticEnrichmentResponse | None = Field(
default=None, validation_alias=AliasChoices("semantic_enrichment", "semanticEnrichment")
)
progress_percent: int = Field(ge=0, le=100, validation_alias=AliasChoices("progress_percent", "progressPercent"))
created_at: datetime = Field(validation_alias=AliasChoices("created_at", "createdAt"))
updated_at: datetime = Field(validation_alias=AliasChoices("updated_at", "updatedAt"))
completed_at: datetime | None = Field(default=None, validation_alias=AliasChoices("completed_at", "completedAt"))
retry_at: datetime | None = Field(default=None, validation_alias=AliasChoices("retry_at", "retryAt"))
failure: KnowledgeFSPublicFailureResponse | None = None
error_code: KnowledgeFSPublicErrorCode | None = Field(
default=None, validation_alias=AliasChoices("error_code", "errorCode")
)
error_message: str | None = Field(default=None, validation_alias=AliasChoices("error_message", "errorMessage"))
phase: str | None = None
active_operations: list[str] | None = Field(
default=None, validation_alias=AliasChoices("active_operations", "activeOperations")
)
class KnowledgeFSDocumentProcessingTaskListResponse(ResponseModel):
data: list[KnowledgeFSDocumentProcessingTaskResponse] = Field(validation_alias=AliasChoices("data", "items"))
next_cursor: str | None = Field(default=None, validation_alias=AliasChoices("next_cursor", "nextCursor"))
class KnowledgeFSServiceQueryImageUploadResponse(ResponseModel):
upload_file_id: str
byte_size: int = Field(ge=1)
mime_type: str