mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-08-20 11:31:47 +08:00
ee899a267b
#### PR Dependency Tree * **PR #15448** 👈 This tree was auto-generated by [Charcoal](https://github.com/danerwilliams/charcoal) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Added workspace artifact upload, browsing, removal, deduplication, and library ownership support. * Copilot now supports scoped document and artifact search, canvas reading, live editor context, and frontend tools. * Added scope and focus selectors with source-resolution receipts in chat. * Added embedding health, progress, synchronization, and retrieval capabilities. * Added BYOK policy visibility, provider restrictions, endpoint dialect selection, and validation. * Added delegated editor interactions and userdata document authorization. * **Bug Fixes** * Improved attachment handling, cancellation, access control, retrieval fallbacks, workspace synchronization, and configuration validation. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
941 lines
26 KiB
TypeScript
941 lines
26 KiB
TypeScript
import serverNativeModule, {
|
|
type AssertSafeUrlRequest,
|
|
type BackendRuntimeHealth,
|
|
type BuiltInPromptRenderContract,
|
|
type BuiltInPromptSessionContract,
|
|
type BuiltInPromptSpec,
|
|
type BuiltInRouteOptions,
|
|
type CanonicalChatRequestContract,
|
|
type CanonicalStructuredRequestContract,
|
|
type CapabilityAttachmentContract,
|
|
type CapabilityModelCapability,
|
|
type CommandResponse,
|
|
type CompileScopeInput,
|
|
type ContentPolicyScanInput,
|
|
type ContentPolicyScanResult,
|
|
type DocumentEmbeddingProjectionInput,
|
|
type EmbeddingHealth,
|
|
type EnsureWorkspaceBlobArtifactInput,
|
|
type ImageInspection,
|
|
type ImageInspectionOptions,
|
|
type LicenseError,
|
|
type LicenseHealthRequest,
|
|
type LicenseInfo,
|
|
type LicenseKeyRequest,
|
|
type LicenseRecurringRequest,
|
|
type LicenseResponse,
|
|
type LicenseSeatsRequest,
|
|
type LlmCoreMessage,
|
|
type LlmEmbeddingRequestContract,
|
|
type LlmImageRequestContract,
|
|
type LlmRequestContract,
|
|
type LlmRerankRequestContract,
|
|
type LlmStructuredRequestContract,
|
|
type MatchEmbeddingCandidatesInput,
|
|
type ModelConditionsContract,
|
|
type PortalResponse,
|
|
type PromptMessageContract,
|
|
type PromptRenderResult,
|
|
type PromptSessionResult,
|
|
type PromptStructuredResponseContract,
|
|
type PutWorkspaceArtifactInput,
|
|
type ReadEmbeddingSourceContentInput,
|
|
type RemoteAttachmentFetchRequest,
|
|
type RemoteAttachmentFetchResponse,
|
|
type RemoteMimeTypeRequest,
|
|
type ResolvedEntitlement,
|
|
type ResolveEntitlementInput,
|
|
type RuntimeBlobCleanupExecuteResult,
|
|
type RuntimeBlobCleanupPlanResult,
|
|
type RuntimeBlobCleanupResult,
|
|
type RuntimeBlobCompleteResult,
|
|
type RuntimeBlobMetadataBackfillResult,
|
|
type RuntimeDocBlobRefsResult,
|
|
type RuntimeDocCompactionResult,
|
|
type RuntimeEmbeddingCandidate,
|
|
type RuntimeEmbeddingSourceContent,
|
|
type RuntimeEmbeddingWorkspaceState,
|
|
type RuntimeMagicLinkOtpConsumeResult,
|
|
type RuntimeMultipartUploadInit,
|
|
type RuntimeMultipartUploadPart,
|
|
type RuntimeObjectGetResult,
|
|
type RuntimeObjectListEntry,
|
|
type RuntimeObjectMetadata,
|
|
type RuntimeObjectStoragePutOptions,
|
|
type RuntimePresignedObjectRequest,
|
|
type RuntimeRetrievalScope,
|
|
type RuntimeTurnScopeSnapshot,
|
|
type RuntimeVerificationTokenRecord,
|
|
type RuntimeWorkspaceArtifact,
|
|
type RuntimeWorkspaceInviteLinkRecord,
|
|
type RuntimeWorkspaceStatsDailyRecalibrationResult,
|
|
type SafeFetchRequest,
|
|
type SafeFetchResponse,
|
|
type StorageProviderCapabilities,
|
|
type StorageRuntimeHealth,
|
|
type SyncEmbeddingStateInput,
|
|
type Tokenizer,
|
|
} from '@affine/server-native';
|
|
|
|
export type {
|
|
BuiltInManagedTarget,
|
|
BuiltInManagedTargetTier,
|
|
BuiltInRouteOptions,
|
|
ByokCapabilityInput,
|
|
ByokCatalogModelOutput,
|
|
ByokCatalogOutput,
|
|
ByokCatalogProviderOutput,
|
|
ByokEndpointInput,
|
|
ByokLocalLeaseOutput,
|
|
ByokModelDeclarationInput,
|
|
ByokModelProbeCheckOutput,
|
|
ByokModelProbeOutput,
|
|
ByokPolicyOutput,
|
|
ByokProbeCheckInput,
|
|
ByokProbeResultOutput,
|
|
ByokProbeStatusOutput,
|
|
ByokProfileDefinitionInput,
|
|
ByokProfileOutput,
|
|
ByokValidationOutput,
|
|
CopilotAccessProjection,
|
|
CopilotExecuteInput,
|
|
CopilotRouteCheckInput,
|
|
CopilotTargetOverrideInput,
|
|
CreateByokLocalLeaseInput,
|
|
CreateByokLocalLeaseProviderInput,
|
|
CreateByokProfileInput,
|
|
ProbeByokDraftInput,
|
|
ProbeByokProfileInput,
|
|
ReorderByokProfilesInput,
|
|
ReplaceByokProfileInput,
|
|
RotateByokCredentialInput,
|
|
} from '@affine/server-native';
|
|
|
|
export type {
|
|
AssertSafeUrlRequest,
|
|
BackendRuntimeHealth,
|
|
CapabilityAttachmentContract,
|
|
CapabilityModelCapability,
|
|
CommandResponse,
|
|
CompileScopeInput,
|
|
ContentPolicyScanInput,
|
|
ContentPolicyScanResult,
|
|
DocumentEmbeddingProjectionInput,
|
|
EmbeddingHealth,
|
|
EnsureWorkspaceBlobArtifactInput,
|
|
ImageInspection,
|
|
ImageInspectionOptions,
|
|
LicenseError,
|
|
LicenseHealthRequest,
|
|
LicenseInfo,
|
|
LicenseKeyRequest,
|
|
LicenseRecurringRequest,
|
|
LicenseResponse,
|
|
LicenseSeatsRequest,
|
|
MatchEmbeddingCandidatesInput,
|
|
ModelConditionsContract,
|
|
PortalResponse,
|
|
PromptMessageContract,
|
|
PromptStructuredResponseContract,
|
|
PutWorkspaceArtifactInput,
|
|
ReadEmbeddingSourceContentInput,
|
|
RemoteAttachmentFetchRequest,
|
|
RemoteAttachmentFetchResponse,
|
|
RemoteMimeTypeRequest,
|
|
ResolvedEntitlement,
|
|
ResolveEntitlementInput,
|
|
RuntimeBlobCleanupExecuteResult,
|
|
RuntimeBlobCleanupPlanResult,
|
|
RuntimeBlobCleanupResult,
|
|
RuntimeBlobCompleteResult,
|
|
RuntimeBlobMetadataBackfillResult,
|
|
RuntimeDocBlobRefsResult,
|
|
RuntimeDocCompactionResult,
|
|
RuntimeEmbeddingCandidate,
|
|
RuntimeEmbeddingSourceContent,
|
|
RuntimeEmbeddingWorkspaceState,
|
|
RuntimeMagicLinkOtpConsumeResult,
|
|
RuntimeMultipartUploadInit,
|
|
RuntimeMultipartUploadPart,
|
|
RuntimeObjectGetResult,
|
|
RuntimeObjectListEntry,
|
|
RuntimeObjectMetadata,
|
|
RuntimeObjectStoragePutOptions,
|
|
RuntimePresignedObjectRequest,
|
|
RuntimeRetrievalScope,
|
|
RuntimeTurnScopeSnapshot,
|
|
RuntimeVerificationTokenRecord,
|
|
RuntimeWorkspaceArtifact,
|
|
RuntimeWorkspaceInviteLinkRecord,
|
|
RuntimeWorkspaceStatsDailyRecalibrationResult,
|
|
SafeFetchRequest,
|
|
SafeFetchResponse,
|
|
StorageProviderCapabilities,
|
|
StorageRuntimeHealth,
|
|
SyncEmbeddingStateInput,
|
|
};
|
|
|
|
export type ActionEventType =
|
|
| 'action_start'
|
|
| 'step_start'
|
|
| 'attachment'
|
|
| 'step_end'
|
|
| 'action_done'
|
|
| 'error';
|
|
|
|
export type ActionRunStatus =
|
|
| 'created'
|
|
| 'running'
|
|
| 'succeeded'
|
|
| 'failed'
|
|
| 'aborted';
|
|
|
|
export type NativeActionEvent = {
|
|
type: ActionEventType;
|
|
actionId: string;
|
|
actionVersion: string;
|
|
status?: ActionRunStatus;
|
|
stepId?: string;
|
|
attachment?: unknown;
|
|
result?: unknown;
|
|
errorCode?: string;
|
|
errorMessage?: string;
|
|
trace?: unknown;
|
|
};
|
|
|
|
export type CopilotActionRecipe = {
|
|
actionId: string;
|
|
actionVersion: string;
|
|
slot: string;
|
|
promptRef: string;
|
|
responseContract: { schema: Record<string, unknown>; strict: boolean } | null;
|
|
outputProjection: string;
|
|
};
|
|
|
|
export function getCopilotActionRecipe(
|
|
actionId: string,
|
|
actionVersion?: string
|
|
): CopilotActionRecipe {
|
|
return JSON.parse(
|
|
serverNativeModule.copilotActionRecipe(actionId, actionVersion)
|
|
) as CopilotActionRecipe;
|
|
}
|
|
|
|
import type {
|
|
ToolCallRequest,
|
|
ToolCallResult,
|
|
} from './plugins/copilot/runtime/contracts/tool-contract';
|
|
|
|
export const mergeUpdatesInApplyWay = serverNativeModule.mergeUpdatesInApplyWay;
|
|
export const authorizeUserdataDocSubject =
|
|
serverNativeModule.authorizeUserdataDocSubject;
|
|
export const authSessionAccessTokenKeyId =
|
|
serverNativeModule.authSessionAccessTokenKeyId;
|
|
export const createAuthSessionRefreshToken =
|
|
serverNativeModule.createAuthSessionRefreshToken;
|
|
export const parseAuthSessionRefreshToken =
|
|
serverNativeModule.parseAuthSessionRefreshToken;
|
|
export const signAuthSessionAccessToken =
|
|
serverNativeModule.signAuthSessionAccessToken;
|
|
export const verifyAuthSessionAccessToken =
|
|
serverNativeModule.verifyAuthSessionAccessToken;
|
|
|
|
export async function validateDocUpdate(
|
|
update: Buffer,
|
|
options: { signal?: AbortSignal; timeoutMs?: number } = {}
|
|
): Promise<boolean> {
|
|
const signals = [];
|
|
if (options.signal) {
|
|
signals.push(options.signal);
|
|
}
|
|
if (options.timeoutMs !== undefined) {
|
|
signals.push(AbortSignal.timeout(options.timeoutMs));
|
|
}
|
|
const signal =
|
|
signals.length === 0
|
|
? undefined
|
|
: signals.length === 1
|
|
? signals[0]
|
|
: AbortSignal.any(signals);
|
|
|
|
if (signal?.aborted) {
|
|
throw signal.reason;
|
|
}
|
|
|
|
return await new Promise<boolean>((resolve, reject) => {
|
|
let settled = false;
|
|
const settle = (callback: () => void) => {
|
|
if (settled) return;
|
|
settled = true;
|
|
callback();
|
|
};
|
|
const onAbort = () => {
|
|
settle(() =>
|
|
reject(
|
|
signal?.reason instanceof Error
|
|
? signal.reason
|
|
: new Error('Doc update validation aborted')
|
|
)
|
|
);
|
|
};
|
|
signal?.addEventListener('abort', onAbort, { once: true });
|
|
serverNativeModule
|
|
.validateDocUpdate(update)
|
|
.then(
|
|
result => settle(() => resolve(result)),
|
|
error => settle(() => reject(error))
|
|
)
|
|
.finally(() => {
|
|
signal?.removeEventListener('abort', onAbort);
|
|
});
|
|
});
|
|
}
|
|
|
|
export const verifyChallengeResponse = async (
|
|
response: any,
|
|
bits: number,
|
|
resource: string
|
|
) => {
|
|
if (typeof response !== 'string' || !response || !resource) return false;
|
|
return serverNativeModule.verifyChallengeResponse(response, bits, resource);
|
|
};
|
|
|
|
export const mintChallengeResponse = async (resource: string, bits: number) => {
|
|
if (!resource) return null;
|
|
return serverNativeModule.mintChallengeResponse(resource, bits);
|
|
};
|
|
|
|
const ENCODER_CACHE = new Map<string, Tokenizer>();
|
|
|
|
export function getTokenEncoder(model?: string | null): Tokenizer | null {
|
|
if (!model) return null;
|
|
const cached = ENCODER_CACHE.get(model);
|
|
if (cached) return cached;
|
|
if (model.startsWith('gpt')) {
|
|
const encoder = serverNativeModule.fromModelName(model);
|
|
if (encoder) ENCODER_CACHE.set(model, encoder);
|
|
return encoder;
|
|
} else if (model.startsWith('dall')) {
|
|
// dalle don't need to calc the token
|
|
return null;
|
|
} else {
|
|
// c100k based model
|
|
const encoder = serverNativeModule.fromModelName('gpt-4');
|
|
if (encoder) ENCODER_CACHE.set('gpt-4', encoder);
|
|
return encoder;
|
|
}
|
|
}
|
|
|
|
export const getMime = serverNativeModule.getMime;
|
|
export const inspectImageForProxy = serverNativeModule.inspectImageForProxy;
|
|
export const fetchRemoteAttachment = serverNativeModule.fetchRemoteAttachment;
|
|
export const inferRemoteMimeType = serverNativeModule.inferRemoteMimeType;
|
|
export const assertSafeUrl = serverNativeModule.assertSafeUrl;
|
|
export const scanContentPolicyV1 = serverNativeModule.scanContentPolicyV1;
|
|
export const safeFetch = serverNativeModule.safeFetch;
|
|
export const activateLicense = serverNativeModule.activateLicense;
|
|
export const checkLicenseHealth = serverNativeModule.checkLicenseHealth;
|
|
export const createCustomerPortal =
|
|
serverNativeModule.createLicenseCustomerPortal;
|
|
export const deactivateLicense = serverNativeModule.deactivateLicense;
|
|
export const updateLicenseRecurring = serverNativeModule.updateLicenseRecurring;
|
|
export const updateLicenseSeats = serverNativeModule.updateLicenseSeats;
|
|
export const parseDoc = serverNativeModule.parseDoc;
|
|
export const htmlSanitize = serverNativeModule.htmlSanitize;
|
|
export const processImage = serverNativeModule.processImage;
|
|
export const projectDocCanvasFromBinary =
|
|
serverNativeModule.projectDocCanvasFromBinary;
|
|
export const projectDocSearchFromBinary =
|
|
serverNativeModule.projectDocSearchFromBinary;
|
|
export const parseYDocToMarkdown = serverNativeModule.parseDocToMarkdown;
|
|
export const parsePageDocFromBinary = serverNativeModule.parsePageDoc;
|
|
export const parseWorkspaceDocFromBinary = serverNativeModule.parseWorkspaceDoc;
|
|
export const readAllDocIdsFromRootDoc =
|
|
serverNativeModule.readAllDocIdsFromRootDoc;
|
|
export const AFFINE_PRO_PUBLIC_KEY = serverNativeModule.AFFINE_PRO_PUBLIC_KEY;
|
|
export const AFFINE_PRO_LICENSE_AES_KEY =
|
|
serverNativeModule.AFFINE_PRO_LICENSE_AES_KEY;
|
|
export const BackendRuntime = serverNativeModule.BackendRuntime;
|
|
export const StorageRuntime = serverNativeModule.StorageRuntime;
|
|
|
|
export type PermissionWorkspaceRole = 'external' | 'member' | 'admin' | 'owner';
|
|
export type PermissionDocRole =
|
|
| 'none'
|
|
| 'external'
|
|
| 'reader'
|
|
| 'commenter'
|
|
| 'editor'
|
|
| 'manager'
|
|
| 'owner';
|
|
|
|
export type PermissionEvaluationInputV1 = {
|
|
version: 1;
|
|
legacyCompatMode?: boolean;
|
|
subject?: {
|
|
userId?: string;
|
|
groupIds?: string[];
|
|
allowLocal?: boolean;
|
|
};
|
|
runtime?: {
|
|
known?: boolean;
|
|
stale?: boolean;
|
|
readonly?: boolean;
|
|
readonlyReason?: string;
|
|
sharingEnabled?: boolean;
|
|
urlPreviewEnabled?: boolean;
|
|
};
|
|
workspace?: {
|
|
role?: PermissionWorkspaceRole;
|
|
memberState?: 'active' | 'pending' | 'waiting_review' | 'waiting_seat';
|
|
public?: boolean;
|
|
sharingEnabled?: boolean;
|
|
urlPreviewEnabled?: boolean;
|
|
local?: boolean;
|
|
};
|
|
workspaceActions?: string[];
|
|
docs?: Array<{
|
|
docId: string;
|
|
actions?: string[];
|
|
explicitUserRole?: PermissionDocRole;
|
|
groupGrants?: Array<{ groupId: string; role: PermissionDocRole }>;
|
|
groupGrantsEnabled?: boolean;
|
|
memberDefaultRole?: PermissionDocRole;
|
|
publicRole?: 'external';
|
|
visibility?: 'private' | 'public';
|
|
sharingEnabled?: boolean;
|
|
previewEnabled?: boolean;
|
|
}>;
|
|
};
|
|
|
|
export type PermissionDecisionV1 = {
|
|
action: string;
|
|
allowed: boolean;
|
|
sources: Array<{
|
|
type:
|
|
| 'workspace-member'
|
|
| 'workspace-policy'
|
|
| 'workspace-preview-policy'
|
|
| 'local-workspace'
|
|
| 'inherited-workspace-role'
|
|
| 'doc-grant'
|
|
| 'group-grant'
|
|
| 'member-default-policy'
|
|
| 'public-policy'
|
|
| 'doc-preview-policy';
|
|
role?: string;
|
|
}>;
|
|
restrictions: Array<{
|
|
type: 'runtime_unknown' | 'runtime_stale' | 'readonly' | 'sharing-disabled';
|
|
reason?: string;
|
|
}>;
|
|
};
|
|
|
|
export type PermissionEvaluationOutputV1 = {
|
|
version: 1;
|
|
workspace: {
|
|
resourceOwnerRole?: PermissionWorkspaceRole;
|
|
effectiveRole?: PermissionWorkspaceRole;
|
|
decisions: PermissionDecisionV1[];
|
|
};
|
|
docs: Array<{
|
|
docId: string;
|
|
resourceOwnerRole?: 'owner';
|
|
effectiveRole?: PermissionDocRole;
|
|
decisions: PermissionDecisionV1[];
|
|
}>;
|
|
};
|
|
|
|
export const evaluatePermissionV1 = (
|
|
input: PermissionEvaluationInputV1
|
|
): PermissionEvaluationOutputV1 =>
|
|
serverNativeModule.evaluatePermissionV1(input);
|
|
|
|
export const permissionActionRoleMatrixV1 = (): unknown =>
|
|
serverNativeModule.permissionActionRoleMatrixV1();
|
|
|
|
export const permissionActionRoleMatrixV1Json =
|
|
serverNativeModule.permissionActionRoleMatrixV1Json;
|
|
|
|
export const resolveEntitlementV1 = (
|
|
input: ResolveEntitlementInput
|
|
): ResolvedEntitlement => serverNativeModule.resolveEntitlementV1(input);
|
|
|
|
// MCP write tools exports
|
|
export const createDocWithMarkdown = serverNativeModule.createDocWithMarkdown;
|
|
export const updateDocWithMarkdown = serverNativeModule.updateDocWithMarkdown;
|
|
export const addDocToRootDoc = serverNativeModule.addDocToRootDoc;
|
|
export const buildPublicRootDoc = serverNativeModule.buildPublicRootDoc;
|
|
export const updateDocTitle = serverNativeModule.updateDocTitle;
|
|
export const updateDocProperties = serverNativeModule.updateDocProperties;
|
|
export const updateRootDocMetaTitle = serverNativeModule.updateRootDocMetaTitle;
|
|
|
|
const nativeLlmModule = serverNativeModule;
|
|
|
|
export type NativePromptMessageInput = Omit<
|
|
PromptMessageContract,
|
|
'role' | 'attachments' | 'params' | 'responseFormat'
|
|
> & {
|
|
role: 'system' | 'user' | 'assistant';
|
|
attachments?: Array<
|
|
| string
|
|
| {
|
|
attachment: string;
|
|
mimeType?: string;
|
|
}
|
|
| {
|
|
kind: 'url';
|
|
url: string;
|
|
data?: string;
|
|
encoding?: 'base64';
|
|
mimeType?: string;
|
|
fileName?: string;
|
|
providerHint?: {
|
|
provider?: string;
|
|
kind?: 'image' | 'audio' | 'file';
|
|
};
|
|
}
|
|
| {
|
|
kind: 'data';
|
|
data: string;
|
|
mimeType: string;
|
|
encoding?: 'base64' | 'utf8';
|
|
fileName?: string;
|
|
providerHint?: {
|
|
provider?: string;
|
|
kind?: 'image' | 'audio' | 'file';
|
|
};
|
|
}
|
|
| {
|
|
kind: 'bytes';
|
|
data: string;
|
|
mimeType: string;
|
|
encoding?: 'base64';
|
|
fileName?: string;
|
|
providerHint?: {
|
|
provider?: string;
|
|
kind?: 'image' | 'audio' | 'file';
|
|
};
|
|
}
|
|
| {
|
|
kind: 'file_handle';
|
|
fileHandle: string;
|
|
mimeType?: string;
|
|
fileName?: string;
|
|
providerHint?: {
|
|
provider?: string;
|
|
kind?: 'image' | 'audio' | 'file';
|
|
};
|
|
}
|
|
>;
|
|
params?: Record<string, unknown>;
|
|
responseFormat?: Omit<
|
|
PromptStructuredResponseContract,
|
|
'responseSchemaJson'
|
|
> & {
|
|
responseSchemaJson: Record<string, unknown>;
|
|
};
|
|
};
|
|
|
|
export type LlmImageRequest = LlmImageRequestContract;
|
|
|
|
export type LlmImageRequestBuildInput = {
|
|
model: string;
|
|
messages: PromptMessageContract[];
|
|
options?: {
|
|
quality?: string;
|
|
seed?: number;
|
|
modelName?: string | null;
|
|
loras?: unknown;
|
|
};
|
|
};
|
|
|
|
export type LlmRequest = Omit<
|
|
LlmRequestContract,
|
|
| 'messages'
|
|
| 'tools'
|
|
| 'toolChoice'
|
|
| 'reasoning'
|
|
| 'responseSchema'
|
|
| 'middleware'
|
|
> & {
|
|
messages: LlmCoreMessage[];
|
|
tools?: Array<{
|
|
name: string;
|
|
description?: string;
|
|
parameters: Record<string, unknown>;
|
|
}>;
|
|
toolChoice?: 'auto' | 'none' | 'required' | { name: string };
|
|
reasoning?: Record<string, unknown>;
|
|
responseSchema?: Record<string, unknown>;
|
|
middleware?: {
|
|
request?: Array<
|
|
| 'normalize_messages'
|
|
| 'clamp_max_tokens'
|
|
| 'tool_schema_rewrite'
|
|
| 'openai_request_compat'
|
|
>;
|
|
stream?: Array<'stream_event_normalize' | 'citation_indexing'>;
|
|
config?: {
|
|
additional_properties_policy?: 'preserve' | 'forbid';
|
|
property_format_policy?: 'preserve' | 'drop';
|
|
property_min_length_policy?: 'preserve' | 'drop';
|
|
array_min_items_policy?: 'preserve' | 'drop';
|
|
array_max_items_policy?: 'preserve' | 'drop';
|
|
max_tokens_cap?: number;
|
|
};
|
|
};
|
|
};
|
|
|
|
export type LlmStructuredRequest = Omit<
|
|
LlmStructuredRequestContract,
|
|
'messages' | 'schema' | 'reasoning' | 'middleware'
|
|
> & {
|
|
messages: LlmCoreMessage[];
|
|
schema: Record<string, unknown>;
|
|
reasoning?: Record<string, unknown>;
|
|
middleware?: LlmRequest['middleware'];
|
|
};
|
|
|
|
class StructuredResponseParseError extends Error {
|
|
readonly code = 'invalid_structured_output' as const;
|
|
|
|
constructor(message: string) {
|
|
super(message);
|
|
this.name = 'StructuredResponseParseError';
|
|
}
|
|
}
|
|
|
|
export type LlmDispatchResponse = {
|
|
id: string;
|
|
model: string;
|
|
message: LlmCoreMessage;
|
|
usage: {
|
|
prompt_tokens: number;
|
|
completion_tokens: number;
|
|
total_tokens: number;
|
|
cached_tokens?: number;
|
|
};
|
|
finish_reason:
|
|
| 'stop'
|
|
| 'length'
|
|
| 'tool_calls'
|
|
| 'content_filter'
|
|
| 'error'
|
|
| string;
|
|
reasoning_details?: unknown;
|
|
};
|
|
|
|
export type LlmStructuredResponse = {
|
|
id: string;
|
|
model: string;
|
|
output_text: string;
|
|
output_json?: unknown;
|
|
usage: LlmDispatchResponse['usage'];
|
|
finish_reason: LlmDispatchResponse['finish_reason'];
|
|
reasoning_details?: unknown;
|
|
};
|
|
|
|
export type LlmToolLoopStreamEvent =
|
|
| { type: 'message_start'; id?: string; model?: string }
|
|
| { type: 'provider_selected'; provider_id: string }
|
|
| { type: 'text_delta'; text: string }
|
|
| { type: 'reasoning_delta'; text: string }
|
|
| {
|
|
type: 'tool_call';
|
|
call_id: string;
|
|
name: string;
|
|
arguments: Record<string, unknown>;
|
|
arguments_text?: string;
|
|
arguments_error?: string;
|
|
thought?: string;
|
|
}
|
|
| {
|
|
type: 'tool_result';
|
|
call_id: string;
|
|
output: unknown;
|
|
is_error?: boolean;
|
|
name: string;
|
|
arguments: Record<string, unknown>;
|
|
arguments_text?: string;
|
|
arguments_error?: string;
|
|
}
|
|
| { type: 'citation'; index: number; url: string }
|
|
| {
|
|
type: 'usage';
|
|
usage: {
|
|
prompt_tokens: number;
|
|
completion_tokens: number;
|
|
total_tokens: number;
|
|
cached_tokens?: number;
|
|
};
|
|
}
|
|
| {
|
|
type: 'done';
|
|
finish_reason?: LlmDispatchResponse['finish_reason'];
|
|
usage?: {
|
|
prompt_tokens: number;
|
|
completion_tokens: number;
|
|
total_tokens: number;
|
|
cached_tokens?: number;
|
|
};
|
|
}
|
|
| { type: 'error'; message: string; code?: string; raw?: string };
|
|
|
|
export type LlmToolCallbackRequest = ToolCallRequest;
|
|
export type LlmToolCallbackResponse = ToolCallResult;
|
|
|
|
export function llmInferPromptModelConditions(
|
|
messages: NativePromptMessageInput[]
|
|
): ModelConditionsContract {
|
|
if (!nativeLlmModule.llmInferPromptModelConditions) {
|
|
throw new Error('native prompt model condition inference is not available');
|
|
}
|
|
|
|
return nativeLlmModule.llmInferPromptModelConditions(messages);
|
|
}
|
|
|
|
export type LlmImageResponse = {
|
|
images: Array<{
|
|
url?: string;
|
|
data_base64?: string;
|
|
media_type: string;
|
|
width?: number;
|
|
height?: number;
|
|
provider_metadata?: unknown;
|
|
}>;
|
|
text?: string;
|
|
usage?: {
|
|
input_tokens?: number;
|
|
output_tokens?: number;
|
|
total_tokens?: number;
|
|
};
|
|
provider_metadata?: unknown;
|
|
};
|
|
|
|
export type LlmImageResponseContract = LlmImageResponse;
|
|
|
|
export function buildLlmImageRequestFromMessages(
|
|
request: LlmImageRequestBuildInput
|
|
): LlmImageRequest {
|
|
return nativeLlmModule.llmBuildImageRequestFromMessages(request);
|
|
}
|
|
|
|
export function llmRenderBuiltInPrompt(
|
|
request: BuiltInPromptRenderContract
|
|
): PromptRenderResult {
|
|
if (!nativeLlmModule.llmRenderBuiltInPrompt) {
|
|
throw new Error('native built-in prompt renderer is not available');
|
|
}
|
|
|
|
return nativeLlmModule.llmRenderBuiltInPrompt(request);
|
|
}
|
|
|
|
export function llmRenderBuiltInSessionPrompt(
|
|
request: BuiltInPromptSessionContract
|
|
): PromptSessionResult {
|
|
if (!nativeLlmModule.llmRenderBuiltInSessionPrompt) {
|
|
throw new Error('native built-in session prompt renderer is not available');
|
|
}
|
|
|
|
return nativeLlmModule.llmRenderBuiltInSessionPrompt(request);
|
|
}
|
|
|
|
export function llmListBuiltInPromptSpecs(): BuiltInPromptSpec[] {
|
|
if (!nativeLlmModule.llmListBuiltInPromptSpecs) {
|
|
throw new Error('native built-in prompt specs are not available');
|
|
}
|
|
return nativeLlmModule.llmListBuiltInPromptSpecs();
|
|
}
|
|
|
|
export function llmGetBuiltInPromptSpec(
|
|
name: string
|
|
): BuiltInPromptSpec | null {
|
|
if (!nativeLlmModule.llmGetBuiltInPromptSpec) {
|
|
throw new Error('native built-in prompt spec lookup is not available');
|
|
}
|
|
return nativeLlmModule.llmGetBuiltInPromptSpec(name);
|
|
}
|
|
|
|
export function llmGetBuiltInRouteOptions(
|
|
name: string
|
|
): BuiltInRouteOptions | null {
|
|
return nativeLlmModule.llmGetBuiltInRouteOptions(name);
|
|
}
|
|
|
|
export const llmGetByokCatalog = nativeLlmModule.llmGetByokCatalog;
|
|
|
|
function stripLlmRequestMiddleware<
|
|
T extends { middleware?: { request?: string[]; stream?: string[] } },
|
|
>(request: T): T {
|
|
const middleware = request.middleware;
|
|
if (!middleware) {
|
|
return request;
|
|
}
|
|
|
|
const nextMiddleware = {
|
|
...(middleware.request?.length ? { request: middleware.request } : {}),
|
|
...(middleware.stream?.length ? { stream: middleware.stream } : {}),
|
|
};
|
|
if (Object.keys(nextMiddleware).length === 0) {
|
|
const { middleware: _middleware, ...rest } = request;
|
|
return rest as T;
|
|
}
|
|
|
|
return {
|
|
...request,
|
|
middleware: nextMiddleware,
|
|
};
|
|
}
|
|
|
|
export function llmBuildCanonicalRequest(
|
|
request: CanonicalChatRequestContract
|
|
): LlmRequest {
|
|
if (!nativeLlmModule.llmBuildCanonicalRequest) {
|
|
throw new Error('native canonical request builder is not available');
|
|
}
|
|
return stripLlmRequestMiddleware(
|
|
nativeLlmModule.llmBuildCanonicalRequest(request)
|
|
);
|
|
}
|
|
|
|
export function llmBuildCanonicalStructuredRequest(
|
|
request: CanonicalStructuredRequestContract
|
|
): LlmStructuredRequest {
|
|
if (!nativeLlmModule.llmBuildCanonicalStructuredRequest) {
|
|
throw new Error(
|
|
'native canonical structured request builder is not available'
|
|
);
|
|
}
|
|
return stripLlmRequestMiddleware(
|
|
nativeLlmModule.llmBuildCanonicalStructuredRequest(request)
|
|
);
|
|
}
|
|
|
|
function llmBuildEmbeddingRequest(
|
|
request: LlmEmbeddingRequestContract
|
|
): LlmEmbeddingRequestContract {
|
|
if (!nativeLlmModule.llmBuildEmbeddingRequest) {
|
|
throw new Error('native embedding request builder is not available');
|
|
}
|
|
return nativeLlmModule.llmBuildEmbeddingRequest(request);
|
|
}
|
|
|
|
export function buildLlmEmbeddingRequest(input: {
|
|
model: string;
|
|
inputs: string[];
|
|
dimensions?: number;
|
|
taskType?: string;
|
|
}): LlmEmbeddingRequestContract {
|
|
return llmBuildEmbeddingRequest({
|
|
model: input.model,
|
|
inputs: input.inputs,
|
|
dimensions: input.dimensions,
|
|
taskType: input.taskType,
|
|
});
|
|
}
|
|
|
|
function llmBuildRerankRequest(
|
|
request: LlmRerankRequestContract
|
|
): LlmRerankRequestContract {
|
|
if (!nativeLlmModule.llmBuildRerankRequest) {
|
|
throw new Error('native rerank request builder is not available');
|
|
}
|
|
return nativeLlmModule.llmBuildRerankRequest(request);
|
|
}
|
|
|
|
export function buildLlmRerankRequest(
|
|
model: string,
|
|
request: {
|
|
query: string;
|
|
candidates: Array<{ id?: string; text: string }>;
|
|
topK?: number;
|
|
}
|
|
): LlmRerankRequestContract {
|
|
return llmBuildRerankRequest({
|
|
model,
|
|
query: request.query,
|
|
candidates: request.candidates.map(candidate => ({
|
|
...(candidate.id ? { id: candidate.id } : {}),
|
|
text: candidate.text,
|
|
})),
|
|
...(request.topK ? { topN: request.topK } : {}),
|
|
});
|
|
}
|
|
|
|
export function parseNativeStructuredOutput(
|
|
response: Pick<LlmStructuredResponse, 'output_text'> & {
|
|
output_json?: unknown;
|
|
}
|
|
) {
|
|
if (response.output_json === undefined) {
|
|
throw new StructuredResponseParseError(
|
|
`Structured response missing required output_json: ${response.output_text
|
|
.trim()
|
|
.slice(0, 200)}`
|
|
);
|
|
}
|
|
|
|
return response.output_json;
|
|
}
|
|
|
|
export function llmValidateJsonSchema<T = unknown>(
|
|
schema: Record<string, unknown>,
|
|
value: T
|
|
): T {
|
|
if (!nativeLlmModule.llmValidateJsonSchema) {
|
|
throw new Error('native JSON schema validator is not available');
|
|
}
|
|
|
|
return nativeLlmModule.llmValidateJsonSchema(schema, value) as T;
|
|
}
|
|
|
|
export function llmCanonicalJsonSchemaHash(
|
|
schema: Record<string, unknown>
|
|
): string {
|
|
if (!nativeLlmModule.llmCanonicalJsonSchemaHash) {
|
|
throw new Error(
|
|
'native canonical JSON schema hash helper is not available'
|
|
);
|
|
}
|
|
|
|
return nativeLlmModule.llmCanonicalJsonSchemaHash(schema);
|
|
}
|
|
|
|
export type LlmContractName =
|
|
| 'toolCallbackRequest'
|
|
| 'toolCallbackResponse'
|
|
| 'toolLoopEvent'
|
|
| 'transcriptInput'
|
|
| 'transcriptGeneratedResult'
|
|
| 'transcriptResult';
|
|
|
|
export function llmGetContractSchema(
|
|
name: LlmContractName
|
|
): Record<string, unknown> {
|
|
if (!nativeLlmModule.llmGetContractSchema) {
|
|
throw new Error('native LLM contract schema registry is not available');
|
|
}
|
|
|
|
return nativeLlmModule.llmGetContractSchema(name) as Record<string, unknown>;
|
|
}
|
|
|
|
export function llmValidateContract<T = unknown>(
|
|
name: LlmContractName,
|
|
value: unknown
|
|
): T {
|
|
if (!nativeLlmModule.llmValidateContract) {
|
|
throw new Error('native LLM contract validator is not available');
|
|
}
|
|
|
|
return nativeLlmModule.llmValidateContract(name, value) as T;
|
|
}
|
|
|
|
export {
|
|
type LlmEmbeddingRequestContract as LlmEmbeddingRequest,
|
|
type LlmRerankRequestContract as LlmRerankRequest,
|
|
type BuiltInPromptRenderContract as NativeBuiltInPromptRenderRequest,
|
|
type BuiltInPromptSessionContract as NativeBuiltInPromptSessionRenderRequest,
|
|
type PromptRenderResult as NativePromptRenderResponse,
|
|
type PromptSessionResult as NativePromptSessionRenderResponse,
|
|
} from '@affine/server-native';
|