mirror of
https://github.com/langgenius/dify.git
synced 2026-09-02 22:36:15 +08:00
399 lines
12 KiB
TypeScript
399 lines
12 KiB
TypeScript
import type {
|
|
KnowledgeFsCrawlPreviewPageListResponse,
|
|
KnowledgeFsSourceConnectionListResponse,
|
|
KnowledgeFsSourceConnectionResponse,
|
|
KnowledgeFsSourceProviderListResponse,
|
|
KnowledgeFsSourceResponse,
|
|
KnowledgeFsSourceSyncPolicyPayload,
|
|
KnowledgeFsSourceSyncPolicyResponse,
|
|
KnowledgeFsSourceWorkflowResponse,
|
|
} from '@dify/contracts/api/console/knowledge-fs/types.gen'
|
|
|
|
export type Source = {
|
|
connectionId?: string
|
|
createdAt: string
|
|
credentialConfigured?: boolean
|
|
id: string
|
|
knowledgeSpaceId: string
|
|
lastSyncedAt?: string
|
|
metadata: Record<string, unknown>
|
|
name: string
|
|
permissionScope?: string[]
|
|
status: 'active' | 'syncing' | 'error' | 'disabled'
|
|
syncWorkflow?: SourceWorkflowRun
|
|
syncPolicy?: SourceSyncPolicy
|
|
type: 'upload' | 'object-storage' | 'connector' | 'web'
|
|
updatedAt: string
|
|
uri: string
|
|
version?: number
|
|
}
|
|
|
|
export type SourceDisplayStatus = Source['status'] | 'initializing'
|
|
export type InitialSourcePollingPhase =
|
|
| 'idle'
|
|
| 'awaiting'
|
|
| 'initializing'
|
|
| 'terminal'
|
|
| 'timed-out'
|
|
|
|
export type SourceProvider = {
|
|
authKinds: Array<'api-key' | 'endpoint' | 'oauth2'>
|
|
available: boolean
|
|
capabilities: Array<'website-crawl' | 'online-document' | 'online-drive'>
|
|
configuration: Array<{
|
|
description?: string
|
|
format?: 'password' | 'uri'
|
|
name: string
|
|
required: boolean
|
|
secret: boolean
|
|
type: 'boolean' | 'integer' | 'string'
|
|
}>
|
|
displayName: string
|
|
id: string
|
|
unavailableReason?: string
|
|
}
|
|
|
|
export type SourceConnection = {
|
|
authKind: 'api-key' | 'endpoint' | 'oauth2'
|
|
configuration: Record<string, boolean | number | string>
|
|
createdAt: string
|
|
errorCode?: string
|
|
expiresAt?: string
|
|
id: string
|
|
knowledgeSpaceId: string
|
|
name: string
|
|
providerId: string
|
|
scopes: string[]
|
|
status: 'provisioning' | 'active' | 'expired' | 'error' | 'revoked'
|
|
updatedAt: string
|
|
version: number
|
|
}
|
|
|
|
export type SourceWorkflowRun = {
|
|
canceledAt?: string
|
|
checkpoint: string
|
|
completedAt?: string
|
|
createdAt: string
|
|
cursor?: string
|
|
executionAttempts: number
|
|
id: string
|
|
knowledgeSpaceId: string
|
|
kind: string
|
|
lastErrorCode?: string
|
|
maxExecutionAttempts: number
|
|
progressCompleted: number
|
|
progressFailed: number
|
|
progressSkipped: number
|
|
progressTotal?: number
|
|
sourceId?: string
|
|
state: string
|
|
updatedAt: string
|
|
}
|
|
|
|
export type CrawlPreviewPage = {
|
|
description?: string
|
|
etag?: string
|
|
pageId: string
|
|
sourceUrl: string
|
|
title?: string
|
|
}
|
|
|
|
export type CrawlPreviewPageList = {
|
|
items: CrawlPreviewPage[]
|
|
nextCursor?: string
|
|
}
|
|
|
|
export type SourceSyncPolicy = {
|
|
createdAt: string
|
|
customIntervalSeconds?: number
|
|
enabled: boolean
|
|
expectedSourceVersion: number
|
|
id: string
|
|
knowledgeSpaceId: string
|
|
mode: 'provider' | 'manual' | 'interval' | 'custom'
|
|
nextRunAt?: string
|
|
revision: number
|
|
sourceId: string
|
|
updatedAt: string
|
|
}
|
|
|
|
export type SourceSyncPolicyBody = KnowledgeFsSourceSyncPolicyPayload
|
|
|
|
const SOURCE_WORKFLOW_SUCCESS_STATES = new Set([
|
|
'complete',
|
|
'completed',
|
|
'success',
|
|
'succeeded',
|
|
'zero_results',
|
|
])
|
|
const SOURCE_WORKFLOW_FAILURE_STATES = new Set([
|
|
'canceled',
|
|
'cancelled',
|
|
'error',
|
|
'exhausted',
|
|
'failed',
|
|
'timed_out',
|
|
'timeout',
|
|
])
|
|
const ASYNC_SOURCE_IMPORT_KINDS = new Set([
|
|
'crawl-preview-selection',
|
|
'online-document-import',
|
|
'online-drive-import',
|
|
])
|
|
|
|
function sourceImportMetadata(value: unknown) {
|
|
if (typeof value !== 'object' || value === null || Array.isArray(value)) return undefined
|
|
const metadata = value as Record<string, unknown>
|
|
if (
|
|
typeof metadata.kind !== 'string' ||
|
|
!ASYNC_SOURCE_IMPORT_KINDS.has(metadata.kind) ||
|
|
typeof metadata.workflowId !== 'string'
|
|
)
|
|
return undefined
|
|
return metadata
|
|
}
|
|
|
|
export function sourceWorkflowStatus(state: string): Source['status'] {
|
|
const normalized = state.trim().toLowerCase().replaceAll('-', '_').replaceAll(' ', '_')
|
|
if (SOURCE_WORKFLOW_FAILURE_STATES.has(normalized)) return 'error'
|
|
if (SOURCE_WORKFLOW_SUCCESS_STATES.has(normalized)) return 'active'
|
|
return 'syncing'
|
|
}
|
|
|
|
export function sourceWorkflowIsActive(workflow?: SourceWorkflowRun) {
|
|
return workflow !== undefined && sourceWorkflowStatus(workflow.state) === 'syncing'
|
|
}
|
|
|
|
export function isInitialSource(source: Source) {
|
|
const requestId = source.metadata.clientRequestId
|
|
|
|
return (
|
|
typeof requestId === 'string' &&
|
|
((requestId.startsWith('initial-source:') && requestId.length > 'initial-source:'.length) ||
|
|
(requestId.startsWith('initial-website-source:') &&
|
|
requestId.length > 'initial-website-source:'.length))
|
|
)
|
|
}
|
|
|
|
export function isInitialSourceForOperation(source: Source, operationId: string) {
|
|
const requestId = source.metadata.clientRequestId
|
|
return (
|
|
requestId === `initial-source:${operationId}` ||
|
|
requestId === `initial-website-source:${operationId}`
|
|
)
|
|
}
|
|
|
|
export function initialSourceWorkflowId(source: Source) {
|
|
const initialImport = source.metadata.initialImport
|
|
if (
|
|
typeof initialImport !== 'object' ||
|
|
initialImport === null ||
|
|
!('workflowId' in initialImport) ||
|
|
typeof initialImport.workflowId !== 'string'
|
|
)
|
|
return undefined
|
|
|
|
return initialImport.workflowId
|
|
}
|
|
|
|
export function sourceAsyncImportWorkflowId(source: Source) {
|
|
return (sourceImportMetadata(source.metadata.pendingImport)?.workflowId ??
|
|
sourceImportMetadata(source.metadata.lastImport)?.workflowId) as string | undefined
|
|
}
|
|
|
|
export function sourceHasPendingAsyncImport(source: Source) {
|
|
return sourceImportMetadata(source.metadata.pendingImport) !== undefined
|
|
}
|
|
|
|
export function sourceDisplayStatus(source: Source): SourceDisplayStatus {
|
|
if (isInitialSource(source) && source.status === 'disabled' && source.metadata.preview === true)
|
|
return 'initializing'
|
|
|
|
if (isInitialSource(source) && source.status === 'disabled' && source.metadata.initialImport) {
|
|
if (source.syncWorkflow) {
|
|
const retryStatus = sourceWorkflowStatus(source.syncWorkflow.state)
|
|
return retryStatus === 'active' ? source.status : retryStatus
|
|
}
|
|
|
|
return 'error'
|
|
}
|
|
|
|
if (sourceHasPendingAsyncImport(source) && source.status === 'disabled') return 'syncing'
|
|
|
|
return source.status
|
|
}
|
|
|
|
export function shouldHidePreviewSource(source: Source) {
|
|
return (
|
|
source.status === 'disabled' && source.metadata.preview === true && !isInitialSource(source)
|
|
)
|
|
}
|
|
|
|
export function sourceNeedsPolling(source: Source) {
|
|
return (
|
|
sourceDisplayStatus(source) === 'initializing' ||
|
|
sourceHasPendingAsyncImport(source) ||
|
|
source.status === 'syncing' ||
|
|
sourceWorkflowIsActive(source.syncWorkflow)
|
|
)
|
|
}
|
|
|
|
export function initialSourcePollingPhase(
|
|
sources: Source[],
|
|
awaitedOperationId: string | null,
|
|
timedOut: boolean,
|
|
): InitialSourcePollingPhase {
|
|
const awaitedSource = awaitedOperationId
|
|
? sources.find((source) => isInitialSourceForOperation(source, awaitedOperationId))
|
|
: undefined
|
|
const awaitingSource = Boolean(awaitedOperationId && !awaitedSource)
|
|
const initializing = sources.some((source) => sourceDisplayStatus(source) === 'initializing')
|
|
|
|
if (timedOut && (awaitingSource || initializing)) return 'timed-out'
|
|
if (awaitingSource) return 'awaiting'
|
|
if (initializing) return 'initializing'
|
|
if (awaitedSource) return 'terminal'
|
|
return 'idle'
|
|
}
|
|
|
|
export function sourceStatusWithSyncWorkflow(
|
|
status: Source['status'],
|
|
syncWorkflow?: SourceWorkflowRun,
|
|
): Source['status'] {
|
|
if (status === 'disabled' || !syncWorkflow) return status
|
|
return sourceWorkflowStatus(syncWorkflow.state)
|
|
}
|
|
|
|
export function sourceFromApi(source: KnowledgeFsSourceResponse): Source {
|
|
const syncWorkflow = source.sync_workflow
|
|
? sourceWorkflowFromApi(source.sync_workflow)
|
|
: undefined
|
|
return {
|
|
connectionId: source.connection_id ?? undefined,
|
|
createdAt: source.created_at,
|
|
credentialConfigured: source.credential_configured ?? undefined,
|
|
id: source.id,
|
|
knowledgeSpaceId: source.knowledge_space_id,
|
|
lastSyncedAt: source.last_synced_at ?? undefined,
|
|
metadata: source.metadata,
|
|
name: source.name,
|
|
permissionScope: source.permission_scope,
|
|
status: sourceStatusWithSyncWorkflow(source.status, syncWorkflow),
|
|
syncWorkflow,
|
|
syncPolicy: source.sync_policy ? sourceSyncPolicyFromApi(source.sync_policy) : undefined,
|
|
type: source.type,
|
|
updatedAt: source.updated_at,
|
|
uri: source.uri,
|
|
version: source.version,
|
|
}
|
|
}
|
|
|
|
export function sourceProviderListFromApi(
|
|
response: KnowledgeFsSourceProviderListResponse,
|
|
): SourceProvider[] {
|
|
return response.data.map((provider) => ({
|
|
authKinds: provider.auth_kinds,
|
|
available: provider.available,
|
|
capabilities: provider.capabilities,
|
|
configuration: provider.configuration.map((field) => ({
|
|
description: field.description ?? undefined,
|
|
format: field.format ?? undefined,
|
|
name: field.name,
|
|
required: field.required,
|
|
secret: field.secret,
|
|
type: field.type,
|
|
})),
|
|
displayName: provider.display_name,
|
|
id: provider.id,
|
|
unavailableReason: provider.unavailable_reason ?? undefined,
|
|
}))
|
|
}
|
|
|
|
export function sourceConnectionFromApi(
|
|
connection: KnowledgeFsSourceConnectionResponse,
|
|
): SourceConnection {
|
|
return {
|
|
authKind: connection.auth_kind,
|
|
configuration: connection.configuration,
|
|
createdAt: connection.created_at,
|
|
errorCode: connection.error_code ?? undefined,
|
|
expiresAt: connection.expires_at ?? undefined,
|
|
id: connection.id,
|
|
knowledgeSpaceId: connection.knowledge_space_id,
|
|
name: connection.name,
|
|
providerId: connection.provider_id,
|
|
scopes: connection.scopes,
|
|
status: connection.status,
|
|
updatedAt: connection.updated_at,
|
|
version: connection.version,
|
|
}
|
|
}
|
|
|
|
export function sourceConnectionListFromApi(response: KnowledgeFsSourceConnectionListResponse): {
|
|
items: SourceConnection[]
|
|
nextCursor?: string
|
|
} {
|
|
return {
|
|
items: response.data.map(sourceConnectionFromApi),
|
|
nextCursor: response.next_cursor ?? undefined,
|
|
}
|
|
}
|
|
|
|
export function sourceWorkflowFromApi(
|
|
workflow: KnowledgeFsSourceWorkflowResponse,
|
|
): SourceWorkflowRun {
|
|
return {
|
|
canceledAt: workflow.canceled_at ?? undefined,
|
|
checkpoint: workflow.checkpoint,
|
|
completedAt: workflow.completed_at ?? undefined,
|
|
createdAt: workflow.created_at,
|
|
cursor: workflow.cursor ?? undefined,
|
|
executionAttempts: workflow.execution_attempts,
|
|
id: workflow.id,
|
|
knowledgeSpaceId: workflow.knowledge_space_id,
|
|
kind: workflow.kind,
|
|
lastErrorCode: workflow.last_error_code ?? undefined,
|
|
maxExecutionAttempts: workflow.max_execution_attempts,
|
|
progressCompleted: workflow.progress_completed,
|
|
progressFailed: workflow.progress_failed,
|
|
progressSkipped: workflow.progress_skipped,
|
|
progressTotal: workflow.progress_total ?? undefined,
|
|
sourceId: workflow.source_id ?? undefined,
|
|
state: workflow.state,
|
|
updatedAt: workflow.updated_at,
|
|
}
|
|
}
|
|
|
|
export function crawlPreviewPageListFromApi(
|
|
response: KnowledgeFsCrawlPreviewPageListResponse,
|
|
): CrawlPreviewPageList {
|
|
return {
|
|
items: response.data.map((page) => ({
|
|
description: page.description ?? undefined,
|
|
etag: page.etag ?? undefined,
|
|
pageId: page.page_id,
|
|
sourceUrl: page.source_url,
|
|
title: page.title ?? undefined,
|
|
})),
|
|
nextCursor: response.next_cursor ?? undefined,
|
|
}
|
|
}
|
|
|
|
export function sourceSyncPolicyFromApi(
|
|
policy: KnowledgeFsSourceSyncPolicyResponse,
|
|
): SourceSyncPolicy {
|
|
return {
|
|
createdAt: policy.created_at,
|
|
customIntervalSeconds: policy.custom_interval_seconds ?? undefined,
|
|
enabled: policy.enabled,
|
|
expectedSourceVersion: policy.expected_source_version,
|
|
id: policy.id,
|
|
knowledgeSpaceId: policy.knowledge_space_id,
|
|
mode: policy.mode,
|
|
nextRunAt: policy.next_run_at ?? undefined,
|
|
revision: policy.revision,
|
|
sourceId: policy.source_id,
|
|
updatedAt: policy.updated_at,
|
|
}
|
|
}
|