mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-08-08 20:57:08 +08:00
feat(server): migrate copilot to native (#14620)
#### PR Dependency Tree * **PR #14620** 👈 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** * Native LLM workflows: structured outputs, embeddings, and reranking plus richer multimodal attachments (images, audio, files) and improved remote-attachment inlining. * **Refactor** * Tooling API unified behind a local tool-definition helper; provider/adapters reorganized to route through native dispatch paths. * **Chores** * Dependency updates, removed legacy Google SDK integrations, and increased front memory allocation. * **Tests** * Expanded end-to-end and streaming tests exercising native provider flows, attachments, and rerank/structured scenarios. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
@@ -65,6 +65,21 @@ type NativeLlmModule = {
|
||||
backendConfigJson: string,
|
||||
requestJson: string
|
||||
) => string | Promise<string>;
|
||||
llmStructuredDispatch?: (
|
||||
protocol: string,
|
||||
backendConfigJson: string,
|
||||
requestJson: string
|
||||
) => string | Promise<string>;
|
||||
llmEmbeddingDispatch?: (
|
||||
protocol: string,
|
||||
backendConfigJson: string,
|
||||
requestJson: string
|
||||
) => string | Promise<string>;
|
||||
llmRerankDispatch?: (
|
||||
protocol: string,
|
||||
backendConfigJson: string,
|
||||
requestJson: string
|
||||
) => string | Promise<string>;
|
||||
llmDispatchStream?: (
|
||||
protocol: string,
|
||||
backendConfigJson: string,
|
||||
@@ -79,12 +94,20 @@ const nativeLlmModule = serverNativeModule as typeof serverNativeModule &
|
||||
export type NativeLlmProtocol =
|
||||
| 'openai_chat'
|
||||
| 'openai_responses'
|
||||
| 'anthropic';
|
||||
| 'anthropic'
|
||||
| 'gemini';
|
||||
|
||||
export type NativeLlmBackendConfig = {
|
||||
base_url: string;
|
||||
auth_token: string;
|
||||
request_layer?: 'anthropic' | 'chat_completions' | 'responses' | 'vertex';
|
||||
request_layer?:
|
||||
| 'anthropic'
|
||||
| 'chat_completions'
|
||||
| 'responses'
|
||||
| 'vertex'
|
||||
| 'vertex_anthropic'
|
||||
| 'gemini_api'
|
||||
| 'gemini_vertex';
|
||||
headers?: Record<string, string>;
|
||||
no_streaming?: boolean;
|
||||
timeout_ms?: number;
|
||||
@@ -100,6 +123,8 @@ export type NativeLlmCoreContent =
|
||||
call_id: string;
|
||||
name: string;
|
||||
arguments: Record<string, unknown>;
|
||||
arguments_text?: string;
|
||||
arguments_error?: string;
|
||||
thought?: string;
|
||||
}
|
||||
| {
|
||||
@@ -109,8 +134,12 @@ export type NativeLlmCoreContent =
|
||||
is_error?: boolean;
|
||||
name?: string;
|
||||
arguments?: Record<string, unknown>;
|
||||
arguments_text?: string;
|
||||
arguments_error?: string;
|
||||
}
|
||||
| { type: 'image'; source: Record<string, unknown> | string };
|
||||
| { type: 'image'; source: Record<string, unknown> | string }
|
||||
| { type: 'audio'; source: Record<string, unknown> | string }
|
||||
| { type: 'file'; source: Record<string, unknown> | string };
|
||||
|
||||
export type NativeLlmCoreMessage = {
|
||||
role: NativeLlmCoreRole;
|
||||
@@ -133,22 +162,54 @@ export type NativeLlmRequest = {
|
||||
tool_choice?: 'auto' | 'none' | 'required' | { name: string };
|
||||
include?: string[];
|
||||
reasoning?: Record<string, unknown>;
|
||||
response_schema?: Record<string, unknown>;
|
||||
middleware?: {
|
||||
request?: Array<
|
||||
'normalize_messages' | 'clamp_max_tokens' | 'tool_schema_rewrite'
|
||||
>;
|
||||
stream?: Array<'stream_event_normalize' | 'citation_indexing'>;
|
||||
config?: {
|
||||
no_additional_properties?: boolean;
|
||||
drop_property_format?: boolean;
|
||||
drop_property_min_length?: boolean;
|
||||
drop_array_min_items?: boolean;
|
||||
drop_array_max_items?: boolean;
|
||||
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 NativeLlmStructuredRequest = {
|
||||
model: string;
|
||||
messages: NativeLlmCoreMessage[];
|
||||
schema: Record<string, unknown>;
|
||||
max_tokens?: number;
|
||||
temperature?: number;
|
||||
reasoning?: Record<string, unknown>;
|
||||
strict?: boolean;
|
||||
response_mime_type?: string;
|
||||
middleware?: NativeLlmRequest['middleware'];
|
||||
};
|
||||
|
||||
export type NativeLlmEmbeddingRequest = {
|
||||
model: string;
|
||||
inputs: string[];
|
||||
dimensions?: number;
|
||||
task_type?: string;
|
||||
};
|
||||
|
||||
export type NativeLlmRerankCandidate = {
|
||||
id?: string;
|
||||
text: string;
|
||||
};
|
||||
|
||||
export type NativeLlmRerankRequest = {
|
||||
model: string;
|
||||
query: string;
|
||||
candidates: NativeLlmRerankCandidate[];
|
||||
top_n?: number;
|
||||
};
|
||||
|
||||
export type NativeLlmDispatchResponse = {
|
||||
id: string;
|
||||
model: string;
|
||||
@@ -159,10 +220,39 @@ export type NativeLlmDispatchResponse = {
|
||||
total_tokens: number;
|
||||
cached_tokens?: number;
|
||||
};
|
||||
finish_reason: string;
|
||||
finish_reason:
|
||||
| 'stop'
|
||||
| 'length'
|
||||
| 'tool_calls'
|
||||
| 'content_filter'
|
||||
| 'error'
|
||||
| string;
|
||||
reasoning_details?: unknown;
|
||||
};
|
||||
|
||||
export type NativeLlmStructuredResponse = {
|
||||
id: string;
|
||||
model: string;
|
||||
output_text: string;
|
||||
usage: NativeLlmDispatchResponse['usage'];
|
||||
finish_reason: NativeLlmDispatchResponse['finish_reason'];
|
||||
reasoning_details?: unknown;
|
||||
};
|
||||
|
||||
export type NativeLlmEmbeddingResponse = {
|
||||
model: string;
|
||||
embeddings: number[][];
|
||||
usage?: {
|
||||
prompt_tokens: number;
|
||||
total_tokens: number;
|
||||
};
|
||||
};
|
||||
|
||||
export type NativeLlmRerankResponse = {
|
||||
model: string;
|
||||
scores: number[];
|
||||
};
|
||||
|
||||
export type NativeLlmStreamEvent =
|
||||
| { type: 'message_start'; id?: string; model?: string }
|
||||
| { type: 'text_delta'; text: string }
|
||||
@@ -178,6 +268,8 @@ export type NativeLlmStreamEvent =
|
||||
call_id: string;
|
||||
name: string;
|
||||
arguments: Record<string, unknown>;
|
||||
arguments_text?: string;
|
||||
arguments_error?: string;
|
||||
thought?: string;
|
||||
}
|
||||
| {
|
||||
@@ -187,6 +279,8 @@ export type NativeLlmStreamEvent =
|
||||
is_error?: boolean;
|
||||
name?: string;
|
||||
arguments?: Record<string, unknown>;
|
||||
arguments_text?: string;
|
||||
arguments_error?: string;
|
||||
}
|
||||
| { type: 'citation'; index: number; url: string }
|
||||
| {
|
||||
@@ -200,7 +294,7 @@ export type NativeLlmStreamEvent =
|
||||
}
|
||||
| {
|
||||
type: 'done';
|
||||
finish_reason?: string;
|
||||
finish_reason?: NativeLlmDispatchResponse['finish_reason'];
|
||||
usage?: {
|
||||
prompt_tokens: number;
|
||||
completion_tokens: number;
|
||||
@@ -228,6 +322,57 @@ export async function llmDispatch(
|
||||
return JSON.parse(responseText) as NativeLlmDispatchResponse;
|
||||
}
|
||||
|
||||
export async function llmStructuredDispatch(
|
||||
protocol: NativeLlmProtocol,
|
||||
backendConfig: NativeLlmBackendConfig,
|
||||
request: NativeLlmStructuredRequest
|
||||
): Promise<NativeLlmStructuredResponse> {
|
||||
if (!nativeLlmModule.llmStructuredDispatch) {
|
||||
throw new Error('native llm structured dispatch is not available');
|
||||
}
|
||||
const response = nativeLlmModule.llmStructuredDispatch(
|
||||
protocol,
|
||||
JSON.stringify(backendConfig),
|
||||
JSON.stringify(request)
|
||||
);
|
||||
const responseText = await Promise.resolve(response);
|
||||
return JSON.parse(responseText) as NativeLlmStructuredResponse;
|
||||
}
|
||||
|
||||
export async function llmEmbeddingDispatch(
|
||||
protocol: NativeLlmProtocol,
|
||||
backendConfig: NativeLlmBackendConfig,
|
||||
request: NativeLlmEmbeddingRequest
|
||||
): Promise<NativeLlmEmbeddingResponse> {
|
||||
if (!nativeLlmModule.llmEmbeddingDispatch) {
|
||||
throw new Error('native llm embedding dispatch is not available');
|
||||
}
|
||||
const response = nativeLlmModule.llmEmbeddingDispatch(
|
||||
protocol,
|
||||
JSON.stringify(backendConfig),
|
||||
JSON.stringify(request)
|
||||
);
|
||||
const responseText = await Promise.resolve(response);
|
||||
return JSON.parse(responseText) as NativeLlmEmbeddingResponse;
|
||||
}
|
||||
|
||||
export async function llmRerankDispatch(
|
||||
protocol: NativeLlmProtocol,
|
||||
backendConfig: NativeLlmBackendConfig,
|
||||
request: NativeLlmRerankRequest
|
||||
): Promise<NativeLlmRerankResponse> {
|
||||
if (!nativeLlmModule.llmRerankDispatch) {
|
||||
throw new Error('native llm rerank dispatch is not available');
|
||||
}
|
||||
const response = nativeLlmModule.llmRerankDispatch(
|
||||
protocol,
|
||||
JSON.stringify(backendConfig),
|
||||
JSON.stringify(request)
|
||||
);
|
||||
const responseText = await Promise.resolve(response);
|
||||
return JSON.parse(responseText) as NativeLlmRerankResponse;
|
||||
}
|
||||
|
||||
export class NativeStreamAdapter<T> implements AsyncIterableIterator<T> {
|
||||
readonly #queue: T[] = [];
|
||||
readonly #waiters: ((result: IteratorResult<T>) => void)[] = [];
|
||||
|
||||
Reference in New Issue
Block a user