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:
DarkSky
2026-03-11 13:55:35 +08:00
committed by GitHub
parent 02744cec00
commit 29a27b561b
62 changed files with 4359 additions and 2296 deletions
@@ -10,6 +10,7 @@ import {
CopilotSessionNotFound,
} from '../base';
import { getTokenEncoder } from '../native';
import type { PromptAttachment } from '../plugins/copilot/providers/types';
import { BaseModel } from './base';
export enum SessionType {
@@ -24,7 +25,7 @@ type ChatPrompt = {
model: string;
};
type ChatAttachment = { attachment: string; mimeType: string } | string;
type ChatAttachment = PromptAttachment;
type ChatStreamObject = {
type: 'text-delta' | 'reasoning' | 'tool-call' | 'tool-result';
@@ -173,22 +174,105 @@ export class CopilotSessionModel extends BaseModel {
}
return attachments
.map(attachment =>
typeof attachment === 'string'
? (this.sanitizeString(attachment) ?? '')
: {
attachment:
this.sanitizeString(attachment.attachment) ??
attachment.attachment,
.map(attachment => {
if (typeof attachment === 'string') {
return this.sanitizeString(attachment) ?? '';
}
if ('attachment' in attachment) {
return {
attachment:
this.sanitizeString(attachment.attachment) ??
attachment.attachment,
mimeType:
this.sanitizeString(attachment.mimeType) ?? attachment.mimeType,
};
}
switch (attachment.kind) {
case 'url':
return {
...attachment,
url: this.sanitizeString(attachment.url) ?? attachment.url,
mimeType:
this.sanitizeString(attachment.mimeType) ?? attachment.mimeType,
}
)
fileName:
this.sanitizeString(attachment.fileName) ?? attachment.fileName,
providerHint: attachment.providerHint
? {
provider:
this.sanitizeString(attachment.providerHint.provider) ??
attachment.providerHint.provider,
kind:
this.sanitizeString(attachment.providerHint.kind) ??
attachment.providerHint.kind,
}
: undefined,
};
case 'data':
case 'bytes':
return {
...attachment,
data: this.sanitizeString(attachment.data) ?? attachment.data,
mimeType:
this.sanitizeString(attachment.mimeType) ?? attachment.mimeType,
fileName:
this.sanitizeString(attachment.fileName) ?? attachment.fileName,
providerHint: attachment.providerHint
? {
provider:
this.sanitizeString(attachment.providerHint.provider) ??
attachment.providerHint.provider,
kind:
this.sanitizeString(attachment.providerHint.kind) ??
attachment.providerHint.kind,
}
: undefined,
};
case 'file_handle':
return {
...attachment,
fileHandle:
this.sanitizeString(attachment.fileHandle) ??
attachment.fileHandle,
mimeType:
this.sanitizeString(attachment.mimeType) ?? attachment.mimeType,
fileName:
this.sanitizeString(attachment.fileName) ?? attachment.fileName,
providerHint: attachment.providerHint
? {
provider:
this.sanitizeString(attachment.providerHint.provider) ??
attachment.providerHint.provider,
kind:
this.sanitizeString(attachment.providerHint.kind) ??
attachment.providerHint.kind,
}
: undefined,
};
}
return attachment;
})
.filter(attachment => {
if (typeof attachment === 'string') {
return !!attachment;
}
return !!attachment.attachment && !!attachment.mimeType;
if ('attachment' in attachment) {
return !!attachment.attachment && !!attachment.mimeType;
}
switch (attachment.kind) {
case 'url':
return !!attachment.url;
case 'data':
case 'bytes':
return !!attachment.data && !!attachment.mimeType;
case 'file_handle':
return !!attachment.fileHandle;
}
return false;
});
}